Merge "Remove races in Geocoder/LocationProvider Proxy" into gingerbread
diff --git a/api/current.xml b/api/current.xml
index 89a28e2..b657c34 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -1145,6 +1145,17 @@
visibility="public"
>
</field>
+<field name="USE_SIP"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""android.permission.USE_SIP""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="VIBRATE"
type="java.lang.String"
transient="false"
@@ -6895,7 +6906,7 @@
visibility="public"
>
</field>
-<field name="overscrollFooter"
+<field name="overScrollFooter"
type="int"
transient="false"
volatile="false"
@@ -6906,7 +6917,7 @@
visibility="public"
>
</field>
-<field name="overscrollHeader"
+<field name="overScrollHeader"
type="int"
transient="false"
volatile="false"
@@ -6917,7 +6928,7 @@
visibility="public"
>
</field>
-<field name="overscrollMode"
+<field name="overScrollMode"
type="int"
transient="false"
volatile="false"
@@ -48191,6 +48202,16 @@
visibility="public"
>
</field>
+<field name="firstInstallTime"
+ type="long"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="gids"
type="int[]"
transient="false"
@@ -48213,6 +48234,16 @@
visibility="public"
>
</field>
+<field name="lastUpdateTime"
+ type="long"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="packageName"
type="java.lang.String"
transient="false"
@@ -79272,7 +79303,7 @@
type="float"
transient="false"
volatile="false"
- value="0.001f"
+ value="0.0010f"
static="true"
final="true"
deprecated="not deprecated"
@@ -99439,6 +99470,1945 @@
</field>
</class>
</package>
+<package name="android.net.sip"
+>
+<class name="SipAudioCall"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="SipAudioCall"
+ type="android.net.sip.SipAudioCall"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+<parameter name="localProfile" type="android.net.sip.SipProfile">
+</parameter>
+</constructor>
+<method name="answerCall"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="timeout" type="int">
+</parameter>
+<exception name="SipException" type="android.net.sip.SipException">
+</exception>
+</method>
+<method name="attachCall"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="session" type="android.net.sip.SipSession">
+</parameter>
+<parameter name="sessionDescription" type="java.lang.String">
+</parameter>
+<exception name="SipException" type="android.net.sip.SipException">
+</exception>
+</method>
+<method name="close"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="continueCall"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="timeout" type="int">
+</parameter>
+<exception name="SipException" type="android.net.sip.SipException">
+</exception>
+</method>
+<method name="endCall"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<exception name="SipException" type="android.net.sip.SipException">
+</exception>
+</method>
+<method name="getLocalProfile"
+ return="android.net.sip.SipProfile"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getPeerProfile"
+ return="android.net.sip.SipProfile"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getState"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="holdCall"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="timeout" type="int">
+</parameter>
+<exception name="SipException" type="android.net.sip.SipException">
+</exception>
+</method>
+<method name="isInCall"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="isMuted"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="isOnHold"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="makeCall"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="peerProfile" type="android.net.sip.SipProfile">
+</parameter>
+<parameter name="sipSession" type="android.net.sip.SipSession">
+</parameter>
+<parameter name="timeout" type="int">
+</parameter>
+<exception name="SipException" type="android.net.sip.SipException">
+</exception>
+</method>
+<method name="sendDtmf"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="code" type="int">
+</parameter>
+</method>
+<method name="sendDtmf"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="code" type="int">
+</parameter>
+<parameter name="result" type="android.os.Message">
+</parameter>
+</method>
+<method name="setListener"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="listener" type="android.net.sip.SipAudioCall.Listener">
+</parameter>
+</method>
+<method name="setListener"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="listener" type="android.net.sip.SipAudioCall.Listener">
+</parameter>
+<parameter name="callbackImmediately" type="boolean">
+</parameter>
+</method>
+<method name="setRingbackToneEnabled"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="enabled" type="boolean">
+</parameter>
+</method>
+<method name="setRingtoneEnabled"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="enabled" type="boolean">
+</parameter>
+</method>
+<method name="setSpeakerMode"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="speakerMode" type="boolean">
+</parameter>
+</method>
+<method name="startAudio"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="toggleMute"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="SipAudioCall.Listener"
+ extends="java.lang.Object"
+ abstract="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="SipAudioCall.Listener"
+ type="android.net.sip.SipAudioCall.Listener"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="onCallBusy"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="call" type="android.net.sip.SipAudioCall">
+</parameter>
+</method>
+<method name="onCallEnded"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="call" type="android.net.sip.SipAudioCall">
+</parameter>
+</method>
+<method name="onCallEstablished"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="call" type="android.net.sip.SipAudioCall">
+</parameter>
+</method>
+<method name="onCallHeld"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="call" type="android.net.sip.SipAudioCall">
+</parameter>
+</method>
+<method name="onCalling"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="call" type="android.net.sip.SipAudioCall">
+</parameter>
+</method>
+<method name="onChanged"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="call" type="android.net.sip.SipAudioCall">
+</parameter>
+</method>
+<method name="onError"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="call" type="android.net.sip.SipAudioCall">
+</parameter>
+<parameter name="errorCode" type="int">
+</parameter>
+<parameter name="errorMessage" type="java.lang.String">
+</parameter>
+</method>
+<method name="onReadyToCall"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="call" type="android.net.sip.SipAudioCall">
+</parameter>
+</method>
+<method name="onRinging"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="call" type="android.net.sip.SipAudioCall">
+</parameter>
+<parameter name="caller" type="android.net.sip.SipProfile">
+</parameter>
+</method>
+<method name="onRingingBack"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="call" type="android.net.sip.SipAudioCall">
+</parameter>
+</method>
+</class>
+<class name="SipErrorCode"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="toString"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="errorCode" type="int">
+</parameter>
+</method>
+<field name="CLIENT_ERROR"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="-4"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="CROSS_DOMAIN_AUTHENTICATION"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="-11"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="DATA_CONNECTION_LOST"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="-10"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="INVALID_CREDENTIALS"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="-8"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="INVALID_REMOTE_URI"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="-6"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="IN_PROGRESS"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="-9"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="NO_ERROR"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="0"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="PEER_NOT_REACHABLE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="-7"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="SERVER_ERROR"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="-2"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="SERVER_UNREACHABLE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="-12"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="SOCKET_ERROR"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="-1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TIME_OUT"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="-5"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TRANSACTION_TERMINTED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="-3"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+<class name="SipException"
+ extends="java.lang.Exception"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="SipException"
+ type="android.net.sip.SipException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<constructor name="SipException"
+ type="android.net.sip.SipException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="message" type="java.lang.String">
+</parameter>
+</constructor>
+<constructor name="SipException"
+ type="android.net.sip.SipException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="message" type="java.lang.String">
+</parameter>
+<parameter name="cause" type="java.lang.Throwable">
+</parameter>
+</constructor>
+</class>
+<class name="SipManager"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="close"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="localProfileUri" type="java.lang.String">
+</parameter>
+<exception name="SipException" type="android.net.sip.SipException">
+</exception>
+</method>
+<method name="createSipSession"
+ return="android.net.sip.SipSession"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="localProfile" type="android.net.sip.SipProfile">
+</parameter>
+<parameter name="listener" type="android.net.sip.SipSession.Listener">
+</parameter>
+<exception name="SipException" type="android.net.sip.SipException">
+</exception>
+</method>
+<method name="getCallId"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="incomingCallIntent" type="android.content.Intent">
+</parameter>
+</method>
+<method name="getOfferSessionDescription"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="incomingCallIntent" type="android.content.Intent">
+</parameter>
+</method>
+<method name="getSessionFor"
+ return="android.net.sip.SipSession"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="incomingCallIntent" type="android.content.Intent">
+</parameter>
+<exception name="SipException" type="android.net.sip.SipException">
+</exception>
+</method>
+<method name="isApiSupported"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+</method>
+<method name="isIncomingCallIntent"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="intent" type="android.content.Intent">
+</parameter>
+</method>
+<method name="isOpened"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="localProfileUri" type="java.lang.String">
+</parameter>
+<exception name="SipException" type="android.net.sip.SipException">
+</exception>
+</method>
+<method name="isRegistered"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="localProfileUri" type="java.lang.String">
+</parameter>
+<exception name="SipException" type="android.net.sip.SipException">
+</exception>
+</method>
+<method name="isSipWifiOnly"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+</method>
+<method name="isVoipSupported"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+</method>
+<method name="makeAudioCall"
+ return="android.net.sip.SipAudioCall"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="localProfile" type="android.net.sip.SipProfile">
+</parameter>
+<parameter name="peerProfile" type="android.net.sip.SipProfile">
+</parameter>
+<parameter name="listener" type="android.net.sip.SipAudioCall.Listener">
+</parameter>
+<parameter name="timeout" type="int">
+</parameter>
+<exception name="SipException" type="android.net.sip.SipException">
+</exception>
+</method>
+<method name="makeAudioCall"
+ return="android.net.sip.SipAudioCall"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="localProfileUri" type="java.lang.String">
+</parameter>
+<parameter name="peerProfileUri" type="java.lang.String">
+</parameter>
+<parameter name="listener" type="android.net.sip.SipAudioCall.Listener">
+</parameter>
+<parameter name="timeout" type="int">
+</parameter>
+<exception name="SipException" type="android.net.sip.SipException">
+</exception>
+</method>
+<method name="newInstance"
+ return="android.net.sip.SipManager"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+</method>
+<method name="open"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="localProfile" type="android.net.sip.SipProfile">
+</parameter>
+<exception name="SipException" type="android.net.sip.SipException">
+</exception>
+</method>
+<method name="open"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="localProfile" type="android.net.sip.SipProfile">
+</parameter>
+<parameter name="incomingCallPendingIntent" type="android.app.PendingIntent">
+</parameter>
+<parameter name="listener" type="android.net.sip.SipRegistrationListener">
+</parameter>
+<exception name="SipException" type="android.net.sip.SipException">
+</exception>
+</method>
+<method name="register"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="localProfile" type="android.net.sip.SipProfile">
+</parameter>
+<parameter name="expiryTime" type="int">
+</parameter>
+<parameter name="listener" type="android.net.sip.SipRegistrationListener">
+</parameter>
+<exception name="SipException" type="android.net.sip.SipException">
+</exception>
+</method>
+<method name="setRegistrationListener"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="localProfileUri" type="java.lang.String">
+</parameter>
+<parameter name="listener" type="android.net.sip.SipRegistrationListener">
+</parameter>
+<exception name="SipException" type="android.net.sip.SipException">
+</exception>
+</method>
+<method name="takeAudioCall"
+ return="android.net.sip.SipAudioCall"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="incomingCallIntent" type="android.content.Intent">
+</parameter>
+<parameter name="listener" type="android.net.sip.SipAudioCall.Listener">
+</parameter>
+<exception name="SipException" type="android.net.sip.SipException">
+</exception>
+</method>
+<method name="takeAudioCall"
+ return="android.net.sip.SipAudioCall"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="incomingCallIntent" type="android.content.Intent">
+</parameter>
+<parameter name="listener" type="android.net.sip.SipAudioCall.Listener">
+</parameter>
+<parameter name="ringtoneEnabled" type="boolean">
+</parameter>
+<exception name="SipException" type="android.net.sip.SipException">
+</exception>
+</method>
+<method name="unregister"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="localProfile" type="android.net.sip.SipProfile">
+</parameter>
+<parameter name="listener" type="android.net.sip.SipRegistrationListener">
+</parameter>
+<exception name="SipException" type="android.net.sip.SipException">
+</exception>
+</method>
+<field name="EXTRA_CALL_ID"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""android:sipCallID""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="EXTRA_OFFER_SD"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""android:sipOfferSD""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="INCOMING_CALL_RESULT_CODE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="101"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+<class name="SipProfile"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="java.lang.Cloneable">
+</implements>
+<implements name="android.os.Parcelable">
+</implements>
+<implements name="java.io.Serializable">
+</implements>
+<method name="describeContents"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getAutoRegistration"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getDisplayName"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getPassword"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getPort"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getProfileName"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getProtocol"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getProxyAddress"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getSendKeepAlive"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getSipDomain"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getUriString"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getUserName"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="writeToParcel"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="out" type="android.os.Parcel">
+</parameter>
+<parameter name="flags" type="int">
+</parameter>
+</method>
+<field name="CREATOR"
+ type="android.os.Parcelable.Creator"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+<class name="SipProfile.Builder"
+ extends="java.lang.Object"
+ abstract="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="SipProfile.Builder"
+ type="android.net.sip.SipProfile.Builder"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="profile" type="android.net.sip.SipProfile">
+</parameter>
+</constructor>
+<constructor name="SipProfile.Builder"
+ type="android.net.sip.SipProfile.Builder"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="uriString" type="java.lang.String">
+</parameter>
+<exception name="ParseException" type="java.text.ParseException">
+</exception>
+</constructor>
+<constructor name="SipProfile.Builder"
+ type="android.net.sip.SipProfile.Builder"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="username" type="java.lang.String">
+</parameter>
+<parameter name="serverDomain" type="java.lang.String">
+</parameter>
+<exception name="ParseException" type="java.text.ParseException">
+</exception>
+</constructor>
+<method name="build"
+ return="android.net.sip.SipProfile"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="setAutoRegistration"
+ return="android.net.sip.SipProfile.Builder"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="flag" type="boolean">
+</parameter>
+</method>
+<method name="setDisplayName"
+ return="android.net.sip.SipProfile.Builder"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="displayName" type="java.lang.String">
+</parameter>
+</method>
+<method name="setOutboundProxy"
+ return="android.net.sip.SipProfile.Builder"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="outboundProxy" type="java.lang.String">
+</parameter>
+</method>
+<method name="setPassword"
+ return="android.net.sip.SipProfile.Builder"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="password" type="java.lang.String">
+</parameter>
+</method>
+<method name="setPort"
+ return="android.net.sip.SipProfile.Builder"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="port" type="int">
+</parameter>
+<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException">
+</exception>
+</method>
+<method name="setProfileName"
+ return="android.net.sip.SipProfile.Builder"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="name" type="java.lang.String">
+</parameter>
+</method>
+<method name="setProtocol"
+ return="android.net.sip.SipProfile.Builder"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="protocol" type="java.lang.String">
+</parameter>
+<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException">
+</exception>
+</method>
+<method name="setSendKeepAlive"
+ return="android.net.sip.SipProfile.Builder"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="flag" type="boolean">
+</parameter>
+</method>
+</class>
+<interface name="SipRegistrationListener"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="onRegistering"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="localProfileUri" type="java.lang.String">
+</parameter>
+</method>
+<method name="onRegistrationDone"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="localProfileUri" type="java.lang.String">
+</parameter>
+<parameter name="expiryTime" type="long">
+</parameter>
+</method>
+<method name="onRegistrationFailed"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="localProfileUri" type="java.lang.String">
+</parameter>
+<parameter name="errorCode" type="int">
+</parameter>
+<parameter name="errorMessage" type="java.lang.String">
+</parameter>
+</method>
+</interface>
+<class name="SipSession"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="answerCall"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="sessionDescription" type="java.lang.String">
+</parameter>
+<parameter name="timeout" type="int">
+</parameter>
+</method>
+<method name="changeCall"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="sessionDescription" type="java.lang.String">
+</parameter>
+<parameter name="timeout" type="int">
+</parameter>
+</method>
+<method name="endCall"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getCallId"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getLocalIp"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getLocalProfile"
+ return="android.net.sip.SipProfile"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getPeerProfile"
+ return="android.net.sip.SipProfile"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getState"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="isInCall"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="makeCall"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="callee" type="android.net.sip.SipProfile">
+</parameter>
+<parameter name="sessionDescription" type="java.lang.String">
+</parameter>
+<parameter name="timeout" type="int">
+</parameter>
+</method>
+<method name="register"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="duration" type="int">
+</parameter>
+</method>
+<method name="setListener"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="listener" type="android.net.sip.SipSession.Listener">
+</parameter>
+</method>
+<method name="unregister"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="SipSession.Listener"
+ extends="java.lang.Object"
+ abstract="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="SipSession.Listener"
+ type="android.net.sip.SipSession.Listener"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="onCallBusy"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="session" type="android.net.sip.SipSession">
+</parameter>
+</method>
+<method name="onCallChangeFailed"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="session" type="android.net.sip.SipSession">
+</parameter>
+<parameter name="errorCode" type="int">
+</parameter>
+<parameter name="errorMessage" type="java.lang.String">
+</parameter>
+</method>
+<method name="onCallEnded"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="session" type="android.net.sip.SipSession">
+</parameter>
+</method>
+<method name="onCallEstablished"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="session" type="android.net.sip.SipSession">
+</parameter>
+<parameter name="sessionDescription" type="java.lang.String">
+</parameter>
+</method>
+<method name="onCalling"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="session" type="android.net.sip.SipSession">
+</parameter>
+</method>
+<method name="onError"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="session" type="android.net.sip.SipSession">
+</parameter>
+<parameter name="errorCode" type="int">
+</parameter>
+<parameter name="errorMessage" type="java.lang.String">
+</parameter>
+</method>
+<method name="onRegistering"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="session" type="android.net.sip.SipSession">
+</parameter>
+</method>
+<method name="onRegistrationDone"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="session" type="android.net.sip.SipSession">
+</parameter>
+<parameter name="duration" type="int">
+</parameter>
+</method>
+<method name="onRegistrationFailed"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="session" type="android.net.sip.SipSession">
+</parameter>
+<parameter name="errorCode" type="int">
+</parameter>
+<parameter name="errorMessage" type="java.lang.String">
+</parameter>
+</method>
+<method name="onRegistrationTimeout"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="session" type="android.net.sip.SipSession">
+</parameter>
+</method>
+<method name="onRinging"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="session" type="android.net.sip.SipSession">
+</parameter>
+<parameter name="caller" type="android.net.sip.SipProfile">
+</parameter>
+<parameter name="sessionDescription" type="java.lang.String">
+</parameter>
+</method>
+<method name="onRingingBack"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="session" type="android.net.sip.SipSession">
+</parameter>
+</method>
+</class>
+<class name="SipSession.State"
+ extends="java.lang.Object"
+ abstract="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="toString"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="state" type="int">
+</parameter>
+</method>
+<field name="DEREGISTERING"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="INCOMING_CALL"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="3"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="INCOMING_CALL_ANSWERING"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="4"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="IN_CALL"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="8"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="NOT_DEFINED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="101"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="OUTGOING_CALL"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="5"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="OUTGOING_CALL_CANCELING"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="7"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="OUTGOING_CALL_RING_BACK"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="6"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="PINGING"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="9"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="READY_TO_CALL"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="0"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="REGISTERING"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+</package>
<package name="android.net.wifi"
>
<class name="ScanResult"
@@ -186040,7 +188010,7 @@
visibility="public"
>
</method>
-<method name="getOverscrollMode"
+<method name="getOverScrollMode"
return="int"
abstract="false"
native="false"
@@ -187204,7 +189174,7 @@
<parameter name="heightMeasureSpec" type="int">
</parameter>
</method>
-<method name="onOverscrolled"
+<method name="onOverScrolled"
return="void"
abstract="false"
native="false"
@@ -187376,7 +189346,7 @@
<parameter name="visibility" type="int">
</parameter>
</method>
-<method name="overscrollBy"
+<method name="overScrollBy"
return="boolean"
abstract="false"
native="false"
@@ -187398,9 +189368,9 @@
</parameter>
<parameter name="scrollRangeY" type="int">
</parameter>
-<parameter name="maxOverscrollX" type="int">
+<parameter name="maxOverScrollX" type="int">
</parameter>
-<parameter name="maxOverscrollY" type="int">
+<parameter name="maxOverScrollY" type="int">
</parameter>
<parameter name="isTouchEvent" type="boolean">
</parameter>
@@ -188244,7 +190214,7 @@
<parameter name="l" type="android.view.View.OnTouchListener">
</parameter>
</method>
-<method name="setOverscrollMode"
+<method name="setOverScrollMode"
return="void"
abstract="false"
native="false"
@@ -188254,7 +190224,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="overscrollMode" type="int">
+<parameter name="overScrollMode" type="int">
</parameter>
</method>
<method name="setPadding"
@@ -188879,7 +190849,7 @@
visibility="public"
>
</field>
-<field name="OVERSCROLL_ALWAYS"
+<field name="OVER_SCROLL_ALWAYS"
type="int"
transient="false"
volatile="false"
@@ -188890,7 +190860,7 @@
visibility="public"
>
</field>
-<field name="OVERSCROLL_IF_CONTENT_SCROLLS"
+<field name="OVER_SCROLL_IF_CONTENT_SCROLLS"
type="int"
transient="false"
volatile="false"
@@ -188901,7 +190871,7 @@
visibility="public"
>
</field>
-<field name="OVERSCROLL_NEVER"
+<field name="OVER_SCROLL_NEVER"
type="int"
transient="false"
volatile="false"
@@ -216094,7 +218064,7 @@
visibility="public"
>
</method>
-<method name="isOverscrolled"
+<method name="isOverScrolled"
return="boolean"
abstract="false"
native="false"
@@ -216139,7 +218109,7 @@
<parameter name="overY" type="int">
</parameter>
</method>
-<method name="springback"
+<method name="springBack"
return="boolean"
abstract="false"
native="false"
diff --git a/cmds/installd/commands.c b/cmds/installd/commands.c
index f6f80d1..a5b3e0e 100644
--- a/cmds/installd/commands.c
+++ b/cmds/installd/commands.c
@@ -936,3 +936,157 @@
done:
return 0;
}
+
+int linklib(const char* dataDir, const char* asecLibDir)
+{
+ char libdir[PKG_PATH_MAX];
+ struct stat s, libStat;
+ int rc = 0;
+
+ const size_t libdirLen = strlen(dataDir) + strlen(PKG_LIB_POSTFIX);
+ if (libdirLen >= PKG_PATH_MAX) {
+ LOGE("library dir len too large");
+ rc = -1;
+ goto out;
+ }
+
+ if (snprintf(libdir, sizeof(libdir), "%s%s", dataDir, PKG_LIB_POSTFIX) != (ssize_t)libdirLen) {
+ LOGE("library dir not written successfully: %s\n", strerror(errno));
+ rc = -1;
+ goto out;
+ }
+
+ if (stat(dataDir, &s) < 0) return -1;
+
+ if (chown(dataDir, 0, 0) < 0) {
+ LOGE("failed to chown '%s': %s\n", dataDir, strerror(errno));
+ return -1;
+ }
+
+ if (chmod(dataDir, 0700) < 0) {
+ LOGE("failed to chmod '%s': %s\n", dataDir, strerror(errno));
+ rc = -1;
+ goto out;
+ }
+
+ if (lstat(libdir, &libStat) < 0) {
+ LOGE("couldn't stat lib dir: %s\n", strerror(errno));
+ rc = -1;
+ goto out;
+ }
+
+ if (S_ISDIR(libStat.st_mode)) {
+ if (delete_dir_contents(libdir, 1, 0) < 0) {
+ rc = -1;
+ goto out;
+ }
+ } else if (S_ISLNK(libStat.st_mode)) {
+ if (unlink(libdir) < 0) {
+ rc = -1;
+ goto out;
+ }
+ }
+
+ if (symlink(asecLibDir, libdir) < 0) {
+ LOGE("couldn't symlink directory '%s' -> '%s': %s\n", libdir, asecLibDir, strerror(errno));
+ rc = -errno;
+ goto out;
+ }
+
+ if (lchown(libdir, AID_SYSTEM, AID_SYSTEM) < 0) {
+ LOGE("cannot chown dir '%s': %s\n", libdir, strerror(errno));
+ unlink(libdir);
+ rc = -errno;
+ goto out;
+ }
+
+out:
+ if (chmod(dataDir, s.st_mode) < 0) {
+ LOGE("failed to chmod '%s': %s\n", dataDir, strerror(errno));
+ return -errno;
+ }
+
+ if (chown(dataDir, s.st_uid, s.st_gid) < 0) {
+ LOGE("failed to chown '%s' : %s\n", dataDir, strerror(errno));
+ return -errno;
+ }
+
+ return rc;
+}
+
+int unlinklib(const char* dataDir)
+{
+ char libdir[PKG_PATH_MAX];
+ struct stat s, libStat;
+ int rc = 0;
+
+ const size_t libdirLen = strlen(dataDir) + strlen(PKG_LIB_POSTFIX);
+ if (libdirLen >= PKG_PATH_MAX) {
+ return -1;
+ }
+
+ if (snprintf(libdir, sizeof(libdir), "%s%s", dataDir, PKG_LIB_POSTFIX) != (ssize_t)libdirLen) {
+ LOGE("library dir not written successfully: %s\n", strerror(errno));
+ return -1;
+ }
+
+ if (stat(dataDir, &s) < 0) {
+ LOGE("couldn't state data dir");
+ return -1;
+ }
+
+ if (chown(dataDir, 0, 0) < 0) {
+ LOGE("failed to chown '%s': %s\n", dataDir, strerror(errno));
+ return -1;
+ }
+
+ if (chmod(dataDir, 0700) < 0) {
+ LOGE("failed to chmod '%s': %s\n", dataDir, strerror(errno));
+ rc = -1;
+ goto out;
+ }
+
+ if (lstat(libdir, &libStat) < 0) {
+ LOGE("couldn't stat lib dir: %s\n", strerror(errno));
+ rc = -1;
+ goto out;
+ }
+
+ if (S_ISDIR(libStat.st_mode)) {
+ if (delete_dir_contents(libdir, 1, 0) < 0) {
+ rc = -1;
+ goto out;
+ }
+ } else if (S_ISLNK(libStat.st_mode)) {
+ if (unlink(libdir) < 0) {
+ rc = -1;
+ goto out;
+ }
+ }
+
+ if (mkdir(libdir, 0755) < 0) {
+ LOGE("cannot create dir '%s': %s\n", libdir, strerror(errno));
+ rc = -errno;
+ goto out;
+ }
+
+ if (chown(libdir, AID_SYSTEM, AID_SYSTEM) < 0) {
+ LOGE("cannot chown dir '%s': %s\n", libdir, strerror(errno));
+ unlink(libdir);
+ rc = -errno;
+ goto out;
+ }
+
+out:
+ if (chmod(dataDir, s.st_mode) < 0) {
+ LOGE("failed to chmod '%s': %s\n", dataDir, strerror(errno));
+ return -1;
+ }
+
+ if (chown(dataDir, s.st_uid, s.st_gid) < 0) {
+ LOGE("failed to chown '%s' : %s\n", dataDir, strerror(errno));
+ return -1;
+ }
+
+ return rc;
+}
diff --git a/cmds/installd/installd.c b/cmds/installd/installd.c
index c991845..9ba6402 100644
--- a/cmds/installd/installd.c
+++ b/cmds/installd/installd.c
@@ -101,6 +101,16 @@
return movefiles();
}
+static int do_linklib(char **arg, char reply[REPLY_MAX])
+{
+ return linklib(arg[0], arg[1]);
+}
+
+static int do_unlinklib(char **arg, char reply[REPLY_MAX])
+{
+ return unlinklib(arg[0]);
+}
+
struct cmdinfo {
const char *name;
unsigned numargs;
@@ -121,6 +131,8 @@
{ "getsize", 4, do_get_size },
{ "rmuserdata", 2, do_rm_user_data },
{ "movefiles", 0, do_movefiles },
+ { "linklib", 2, do_linklib },
+ { "unlinklib", 1, do_unlinklib },
};
static int readx(int s, void *_buf, int count)
diff --git a/cmds/installd/installd.h b/cmds/installd/installd.h
index 479e4b2..59475e9 100644
--- a/cmds/installd/installd.h
+++ b/cmds/installd/installd.h
@@ -111,3 +111,5 @@
int free_cache(int64_t free_size);
int dexopt(const char *apk_path, uid_t uid, int is_public);
int movefiles();
+int linklib(const char* target, const char* source);
+int unlinklib(const char* libPath);
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 72bf825..78a77eb 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -1631,35 +1631,11 @@
}
/**
- * @deprecated This functionality will be removed in the future; please do
- * not use.
- *
- * Control whether this activity is required to be persistent. By default
- * activities are not persistent; setting this to true will prevent the
- * system from stopping this activity or its process when running low on
- * resources.
- *
- * <p><em>You should avoid using this method</em>, it has severe negative
- * consequences on how well the system can manage its resources. A better
- * approach is to implement an application service that you control with
- * {@link Context#startService} and {@link Context#stopService}.
- *
- * @param isPersistent Control whether the current activity must be
- * persistent, true if so, false for the normal
- * behavior.
+ * @deprecated As of {@link android.os.Build.VERSION_CODES#GINGERBREAD}
+ * this is a no-op.
*/
@Deprecated
public void setPersistent(boolean isPersistent) {
- if (mParent == null) {
- try {
- ActivityManagerNative.getDefault()
- .setPersistent(mToken, isPersistent);
- } catch (RemoteException e) {
- // Empty
- }
- } else {
- throw new RuntimeException("setPersistent() not yet supported for embedded activities");
- }
}
/**
@@ -2633,6 +2609,10 @@
* <p>This can be useful if you know that you will never show a dialog again and
* want to avoid the overhead of saving and restoring it in the future.
*
+ * <p>As of {@link android.os.Build.VERSION_CODES#GINGERBREAD}, this function
+ * will not throw an exception if you try to remove an ID that does not
+ * currently have an associated dialog.</p>
+ *
* @param id The id of the managed dialog.
*
* @see #onCreateDialog(int, Bundle)
@@ -2641,17 +2621,13 @@
* @see #dismissDialog(int)
*/
public final void removeDialog(int id) {
- if (mManagedDialogs == null) {
- return;
+ if (mManagedDialogs != null) {
+ final ManagedDialog md = mManagedDialogs.get(id);
+ if (md != null) {
+ md.mDialog.dismiss();
+ mManagedDialogs.remove(id);
+ }
}
-
- final ManagedDialog md = mManagedDialogs.get(id);
- if (md == null) {
- return;
- }
-
- md.mDialog.dismiss();
- mManagedDialogs.remove(id);
}
/**
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 89812ab..d6231ea 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -345,17 +345,6 @@
return true;
}
- case SET_PERSISTENT_TRANSACTION: {
- data.enforceInterface(IActivityManager.descriptor);
- IBinder token = data.readStrongBinder();
- boolean isPersistent = data.readInt() != 0;
- if (token != null) {
- setPersistent(token, isPersistent);
- }
- reply.writeNoException();
- return true;
- }
-
case ATTACH_APPLICATION_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
IApplicationThread app = ApplicationThreadNative.asInterface(
@@ -1589,18 +1578,6 @@
data.recycle();
reply.recycle();
}
- public void setPersistent(IBinder token, boolean isPersistent) throws RemoteException
- {
- Parcel data = Parcel.obtain();
- Parcel reply = Parcel.obtain();
- data.writeInterfaceToken(IActivityManager.descriptor);
- data.writeStrongBinder(token);
- data.writeInt(isPersistent ? 1 : 0);
- mRemote.transact(SET_PERSISTENT_TRANSACTION, data, reply, 0);
- reply.readException();
- data.recycle();
- reply.recycle();
- }
public void attachApplication(IApplicationThread app) throws RemoteException
{
Parcel data = Parcel.obtain();
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index e93e684..e66f52a 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -2775,7 +2775,7 @@
synchronized (this) {
if (mDiskWritesInFlight > 0) {
// If we know we caused it, it's not unexpected.
- Log.d(TAG, "disk write in flight, not unexpected.");
+ if (DEBUG) Log.d(TAG, "disk write in flight, not unexpected.");
return false;
}
}
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 28af0d3..83d422e 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -116,7 +116,6 @@
public void unbroadcastIntent(IApplicationThread caller, Intent intent) throws RemoteException;
/* oneway */
public void finishReceiver(IBinder who, int resultCode, String resultData, Bundle map, boolean abortBroadcast) throws RemoteException;
- public void setPersistent(IBinder token, boolean isPersistent) throws RemoteException;
public void attachApplication(IApplicationThread app) throws RemoteException;
/* oneway */
public void activityIdle(IBinder token, Configuration config) throws RemoteException;
@@ -444,7 +443,7 @@
int REPORT_THUMBNAIL_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+27;
int GET_CONTENT_PROVIDER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+28;
int PUBLISH_CONTENT_PROVIDERS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+29;
- int SET_PERSISTENT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+30;
+
int FINISH_SUB_ACTIVITY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+31;
int GET_RUNNING_SERVICE_CONTROL_PANEL_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+32;
int START_SERVICE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+33;
diff --git a/core/java/android/bluetooth/BluetoothDeviceProfileState.java b/core/java/android/bluetooth/BluetoothDeviceProfileState.java
index 8e655e2..df1d960 100644
--- a/core/java/android/bluetooth/BluetoothDeviceProfileState.java
+++ b/core/java/android/bluetooth/BluetoothDeviceProfileState.java
@@ -67,10 +67,11 @@
private static final int DISCONNECT_HFP_INCOMING = 6;
public static final int DISCONNECT_A2DP_OUTGOING = 7;
public static final int DISCONNECT_A2DP_INCOMING = 8;
+ public static final int DISCONNECT_PBAP_OUTGOING = 9;
- public static final int UNPAIR = 9;
- public static final int AUTO_CONNECT_PROFILES = 10;
- public static final int TRANSITION_TO_STABLE = 11;
+ public static final int UNPAIR = 100;
+ public static final int AUTO_CONNECT_PROFILES = 101;
+ public static final int TRANSITION_TO_STABLE = 102;
private static final int AUTO_CONNECT_DELAY = 6000; // 6 secs
@@ -84,7 +85,9 @@
private BluetoothService mService;
private BluetoothA2dpService mA2dpService;
private BluetoothHeadset mHeadsetService;
+ private BluetoothPbap mPbapService;
private boolean mHeadsetServiceConnected;
+ private boolean mPbapServiceConnected;
private BluetoothDevice mDevice;
private int mHeadsetState;
@@ -176,6 +179,7 @@
mContext.registerReceiver(mBroadcastReceiver, filter);
HeadsetServiceListener l = new HeadsetServiceListener();
+ PbapServiceListener p = new PbapServiceListener();
}
private class HeadsetServiceListener implements BluetoothHeadset.ServiceListener {
@@ -194,6 +198,22 @@
}
}
+ private class PbapServiceListener implements BluetoothPbap.ServiceListener {
+ public PbapServiceListener() {
+ mPbapService = new BluetoothPbap(mContext, this);
+ }
+ public void onServiceConnected() {
+ synchronized(BluetoothDeviceProfileState.this) {
+ mPbapServiceConnected = true;
+ }
+ }
+ public void onServiceDisconnected() {
+ synchronized(BluetoothDeviceProfileState.this) {
+ mPbapServiceConnected = false;
+ }
+ }
+ }
+
private class BondedDevice extends HierarchicalState {
@Override
protected void enter() {
@@ -224,6 +244,9 @@
case DISCONNECT_A2DP_INCOMING:
transitionTo(mIncomingA2dp);
break;
+ case DISCONNECT_PBAP_OUTGOING:
+ processCommand(DISCONNECT_PBAP_OUTGOING);
+ break;
case UNPAIR:
if (mHeadsetState != BluetoothHeadset.STATE_DISCONNECTED) {
sendMessage(DISCONNECT_HFP_OUTGOING);
@@ -342,6 +365,7 @@
deferMessage(deferMsg);
}
break;
+ case DISCONNECT_PBAP_OUTGOING:
case UNPAIR:
case AUTO_CONNECT_PROFILES:
deferMessage(message);
@@ -409,6 +433,7 @@
// If this causes incoming HFP to fail, it is more of a headset problem
// since both connections are incoming ones.
break;
+ case DISCONNECT_PBAP_OUTGOING:
case UNPAIR:
case AUTO_CONNECT_PROFILES:
deferMessage(message);
@@ -496,6 +521,7 @@
case DISCONNECT_A2DP_INCOMING:
// Ignore, will be handled by Bluez
break;
+ case DISCONNECT_PBAP_OUTGOING:
case UNPAIR:
case AUTO_CONNECT_PROFILES:
deferMessage(message);
@@ -561,6 +587,7 @@
case DISCONNECT_A2DP_INCOMING:
// Ignore, will be handled by Bluez
break;
+ case DISCONNECT_PBAP_OUTGOING:
case UNPAIR:
case AUTO_CONNECT_PROFILES:
deferMessage(message);
@@ -588,7 +615,7 @@
}
}
- synchronized void deferHeadsetMessage(int command) {
+ synchronized void deferProfileServiceMessage(int command) {
Message msg = new Message();
msg.what = command;
deferMessage(msg);
@@ -604,7 +631,7 @@
break;
case CONNECT_HFP_INCOMING:
if (!mHeadsetServiceConnected) {
- deferHeadsetMessage(command);
+ deferProfileServiceMessage(command);
} else if (mHeadsetState == BluetoothHeadset.STATE_CONNECTING) {
return mHeadsetService.acceptIncomingConnect(mDevice);
} else if (mHeadsetState == BluetoothHeadset.STATE_DISCONNECTED) {
@@ -621,8 +648,13 @@
return true;
case DISCONNECT_HFP_OUTGOING:
if (!mHeadsetServiceConnected) {
- deferHeadsetMessage(command);
+ deferProfileServiceMessage(command);
} else {
+ // Disconnect PBAP
+ // TODO(): Add PBAP to the state machine.
+ Message m = new Message();
+ m.what = DISCONNECT_PBAP_OUTGOING;
+ deferMessage(m);
if (mHeadsetService.getPriority(mDevice) ==
BluetoothHeadset.PRIORITY_AUTO_CONNECT) {
mHeadsetService.setPriority(mDevice, BluetoothHeadset.PRIORITY_ON);
@@ -645,6 +677,13 @@
return mA2dpService.disconnectSinkInternal(mDevice);
}
break;
+ case DISCONNECT_PBAP_OUTGOING:
+ if (!mPbapServiceConnected) {
+ deferProfileServiceMessage(command);
+ } else {
+ return mPbapService.disconnect();
+ }
+ break;
case UNPAIR:
return mService.removeBondInternal(mDevice.getAddress());
default:
diff --git a/core/java/android/content/SyncStorageEngine.java b/core/java/android/content/SyncStorageEngine.java
index 6413cec..f9a1637 100644
--- a/core/java/android/content/SyncStorageEngine.java
+++ b/core/java/android/content/SyncStorageEngine.java
@@ -95,7 +95,7 @@
public static final long NOT_IN_BACKOFF_MODE = -1;
- private static final Intent SYNC_CONNECTION_SETTING_CHANGED_INTENT =
+ public static final Intent SYNC_CONNECTION_SETTING_CHANGED_INTENT =
new Intent("com.android.sync.SYNC_CONN_STATUS_CHANGED");
// TODO: i18n -- grab these out of resources.
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index b1ef0db..175d6db5 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -400,7 +400,11 @@
pw.println(prefix + "uid=" + uid + " flags=0x" + Integer.toHexString(flags)
+ " theme=0x" + Integer.toHexString(theme));
pw.println(prefix + "sourceDir=" + sourceDir);
- if (!sourceDir.equals(publicSourceDir)) {
+ if (sourceDir == null) {
+ if (publicSourceDir != null) {
+ pw.println(prefix + "publicSourceDir=" + publicSourceDir);
+ }
+ } else if (!sourceDir.equals(publicSourceDir)) {
pw.println(prefix + "publicSourceDir=" + publicSourceDir);
}
if (resourceDirs != null) {
diff --git a/core/java/android/content/pm/PackageInfo.java b/core/java/android/content/pm/PackageInfo.java
index af327c3..eb05d76 100644
--- a/core/java/android/content/pm/PackageInfo.java
+++ b/core/java/android/content/pm/PackageInfo.java
@@ -65,6 +65,18 @@
public ApplicationInfo applicationInfo;
/**
+ * The time at which the app was first installed. Units are as
+ * per {@link System#currentTimeMillis()}.
+ */
+ public long firstInstallTime;
+
+ /**
+ * The time at which the app was last updated. Units are as
+ * per {@link System#currentTimeMillis()}.
+ */
+ public long lastUpdateTime;
+
+ /**
* All kernel group-IDs that have been assigned to this package.
* This is only filled in if the flag {@link PackageManager#GET_GIDS} was set.
*/
@@ -207,6 +219,8 @@
} else {
dest.writeInt(0);
}
+ dest.writeLong(firstInstallTime);
+ dest.writeLong(lastUpdateTime);
dest.writeIntArray(gids);
dest.writeTypedArray(activities, parcelableFlags);
dest.writeTypedArray(receivers, parcelableFlags);
@@ -242,6 +256,8 @@
if (hasApp != 0) {
applicationInfo = ApplicationInfo.CREATOR.createFromParcel(source);
}
+ firstInstallTime = source.readLong();
+ lastUpdateTime = source.readLong();
gids = source.createIntArray();
activities = source.createTypedArray(ActivityInfo.CREATOR);
receivers = source.createTypedArray(ActivityInfo.CREATOR);
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 7346561..b5d1653 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -1891,7 +1891,7 @@
if (pkg == null) {
return null;
}
- return PackageParser.generatePackageInfo(pkg, null, flags);
+ return PackageParser.generatePackageInfo(pkg, null, flags, 0, 0);
}
/**
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 89839ce..51f4202 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -187,7 +187,7 @@
* @param flags indicating which optional information is included.
*/
public static PackageInfo generatePackageInfo(PackageParser.Package p,
- int gids[], int flags) {
+ int gids[], int flags, long firstInstallTime, long lastUpdateTime) {
PackageInfo pi = new PackageInfo();
pi.packageName = p.packageName;
@@ -197,6 +197,8 @@
pi.sharedUserLabel = p.mSharedUserLabel;
pi.applicationInfo = p.applicationInfo;
pi.installLocation = p.installLocation;
+ pi.firstInstallTime = firstInstallTime;
+ pi.lastUpdateTime = lastUpdateTime;
if ((flags&PackageManager.GET_GIDS) != 0) {
pi.gids = gids;
}
diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java
index 7b930d5..a27ba84 100644
--- a/core/java/android/hardware/Camera.java
+++ b/core/java/android/hardware/Camera.java
@@ -1354,8 +1354,23 @@
/**
* Sets the dimensions for preview pictures.
*
+ * The sides of width and height are based on camera orientation. That
+ * is, the preview size is the size before it is rotated by display
+ * orientation. So applications need to consider the display orientation
+ * while setting preview size. For example, suppose the camera supports
+ * both 480x320 and 320x480 preview sizes. The application wants a 3:2
+ * preview ratio. If the display orientation is set to 0 or 180, preview
+ * size should be set to 480x320. If the display orientation is set to
+ * 90 or 270, preview size should be set to 320x480. The display
+ * orientation should also be considered while setting picture size and
+ * thumbnail size.
+ *
* @param width the width of the pictures, in pixels
* @param height the height of the pictures, in pixels
+ * @see #setDisplayOrientation(int)
+ * @see #getCameraInfo(int, CameraInfo)
+ * @see #setPictureSize(int, int)
+ * @see #setJpegThumbnailSize(int, int)
*/
public void setPreviewSize(int width, int height) {
String v = Integer.toString(width) + "x" + Integer.toString(height);
@@ -1389,8 +1404,12 @@
* applications set both width and height to 0, EXIF will not contain
* thumbnail.
*
+ * Applications need to consider the display orientation. See {@link
+ * #setPreviewSize(int,int)} for reference.
+ *
* @param width the width of the thumbnail, in pixels
* @param height the height of the thumbnail, in pixels
+ * @see #setPreviewSize(int,int)
*/
public void setJpegThumbnailSize(int width, int height) {
set(KEY_JPEG_THUMBNAIL_WIDTH, width);
@@ -1606,8 +1625,13 @@
/**
* Sets the dimensions for pictures.
*
+ * Applications need to consider the display orientation. See {@link
+ * #setPreviewSize(int,int)} for reference.
+ *
* @param width the width for pictures, in pixels
* @param height the height for pictures, in pixels
+ * @see #setPreviewSize(int,int)
+ *
*/
public void setPictureSize(int width, int height) {
String v = Integer.toString(width) + "x" + Integer.toString(height);
diff --git a/core/java/android/os/DropBoxManager.java b/core/java/android/os/DropBoxManager.java
index 23fdb0b..fa23458 100644
--- a/core/java/android/os/DropBoxManager.java
+++ b/core/java/android/os/DropBoxManager.java
@@ -152,7 +152,7 @@
/** @return time when the entry was originally created. */
public long getTimeMillis() { return mTimeMillis; }
- /** @return flags describing the content returned by @{link #getInputStream()}. */
+ /** @return flags describing the content returned by {@link #getInputStream()}. */
public int getFlags() { return mFlags & ~IS_GZIPPED; } // getInputStream() decompresses.
/**
@@ -288,8 +288,8 @@
}
/**
- * Gets the next entry from the drop box *after* the specified time.
- * Requires android.permission.READ_LOGS. You must always call
+ * Gets the next entry from the drop box <em>after</em> the specified time.
+ * Requires <code>android.permission.READ_LOGS</code>. You must always call
* {@link Entry#close()} on the return value!
*
* @param tag of entry to look for, null for all tags
diff --git a/core/java/android/os/MessageQueue.java b/core/java/android/os/MessageQueue.java
index 6237c0e..0090177 100644
--- a/core/java/android/os/MessageQueue.java
+++ b/core/java/android/os/MessageQueue.java
@@ -34,16 +34,19 @@
Message mMessages;
private final ArrayList<IdleHandler> mIdleHandlers = new ArrayList<IdleHandler>();
private IdleHandler[] mPendingIdleHandlers;
- private boolean mQuiting = false;
+ private boolean mQuiting;
boolean mQuitAllowed = true;
+ // Indicates whether next() is blocked waiting in pollOnce() with a non-zero timeout.
+ private boolean mBlocked;
+
@SuppressWarnings("unused")
private int mPtr; // used by native code
private native void nativeInit();
private native void nativeDestroy();
- private native boolean nativePollOnce(int timeoutMillis);
- private native void nativeWake();
+ private native void nativePollOnce(int ptr, int timeoutMillis);
+ private native void nativeWake(int ptr);
/**
* Callback interface for discovering when a thread is going to block
@@ -113,7 +116,7 @@
if (nextPollTimeoutMillis != 0) {
Binder.flushPendingCommands();
}
- nativePollOnce(nextPollTimeoutMillis);
+ nativePollOnce(mPtr, nextPollTimeoutMillis);
synchronized (this) {
// Try to retrieve the next message. Return if found.
@@ -122,7 +125,9 @@
if (msg != null) {
final long when = msg.when;
if (now >= when) {
+ mBlocked = false;
mMessages = msg.next;
+ msg.next = null;
if (Config.LOGV) Log.v("MessageQueue", "Returning message: " + msg);
return msg;
} else {
@@ -138,6 +143,7 @@
}
if (pendingIdleHandlerCount == 0) {
// No idle handlers to run. Loop and wait some more.
+ mBlocked = true;
continue;
}
@@ -184,6 +190,7 @@
if (msg.target == null && !mQuitAllowed) {
throw new RuntimeException("Main thread not allowed to quit");
}
+ final boolean needWake;
synchronized (this) {
if (mQuiting) {
RuntimeException e = new RuntimeException(
@@ -200,6 +207,7 @@
if (p == null || when == 0 || when < p.when) {
msg.next = p;
mMessages = msg;
+ needWake = mBlocked; // new head, might need to wake up
} else {
Message prev = null;
while (p != null && p.when <= when) {
@@ -208,9 +216,12 @@
}
msg.next = prev.next;
prev.next = msg;
+ needWake = false; // still waiting on head, no need to wake up
}
}
- nativeWake();
+ if (needWake) {
+ nativeWake(mPtr);
+ }
return true;
}
diff --git a/core/java/android/view/InputQueue.java b/core/java/android/view/InputQueue.java
index 43c957a..9e800df 100644
--- a/core/java/android/view/InputQueue.java
+++ b/core/java/android/view/InputQueue.java
@@ -28,8 +28,21 @@
private static final boolean DEBUG = false;
+ /**
+ * Interface to receive notification of when an InputQueue is associated
+ * and dissociated with a thread.
+ */
public static interface Callback {
+ /**
+ * Called when the given InputQueue is now associated with the
+ * thread making this call, so it can start receiving events from it.
+ */
void onInputQueueCreated(InputQueue queue);
+
+ /**
+ * Called when the given InputQueue is no longer associated with
+ * the thread and thus not dispatching events.
+ */
void onInputQueueDestroyed(InputQueue queue);
}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index b794a6a..acda3e1 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -1551,38 +1551,38 @@
private static final int AWAKEN_SCROLL_BARS_ON_ATTACH = 0x08000000;
/**
- * Always allow a user to overscroll this view, provided it is a
+ * Always allow a user to over-scroll this view, provided it is a
* view that can scroll.
*
- * @see #getOverscrollMode()
- * @see #setOverscrollMode(int)
+ * @see #getOverScrollMode()
+ * @see #setOverScrollMode(int)
*/
- public static final int OVERSCROLL_ALWAYS = 0;
+ public static final int OVER_SCROLL_ALWAYS = 0;
/**
- * Allow a user to overscroll this view only if the content is large
+ * Allow a user to over-scroll this view only if the content is large
* enough to meaningfully scroll, provided it is a view that can scroll.
*
- * @see #getOverscrollMode()
- * @see #setOverscrollMode(int)
+ * @see #getOverScrollMode()
+ * @see #setOverScrollMode(int)
*/
- public static final int OVERSCROLL_IF_CONTENT_SCROLLS = 1;
+ public static final int OVER_SCROLL_IF_CONTENT_SCROLLS = 1;
/**
- * Never allow a user to overscroll this view.
+ * Never allow a user to over-scroll this view.
*
- * @see #getOverscrollMode()
- * @see #setOverscrollMode(int)
+ * @see #getOverScrollMode()
+ * @see #setOverScrollMode(int)
*/
- public static final int OVERSCROLL_NEVER = 2;
+ public static final int OVER_SCROLL_NEVER = 2;
/**
- * Controls the overscroll mode for this view.
- * See {@link #overscrollBy(int, int, int, int, int, int, int, int, boolean)},
- * {@link #OVERSCROLL_ALWAYS}, {@link #OVERSCROLL_IF_CONTENT_SCROLLS},
- * and {@link #OVERSCROLL_NEVER}.
+ * Controls the over-scroll mode for this view.
+ * See {@link #overScrollBy(int, int, int, int, int, int, int, int, boolean)},
+ * {@link #OVER_SCROLL_ALWAYS}, {@link #OVER_SCROLL_IF_CONTENT_SCROLLS},
+ * and {@link #OVER_SCROLL_NEVER}.
*/
- private int mOverscrollMode;
+ private int mOverScrollMode;
/**
* The parent this view is attached to.
@@ -1876,7 +1876,7 @@
// Used for debug only
//++sInstanceCount;
mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
- setOverscrollMode(OVERSCROLL_ALWAYS);
+ setOverScrollMode(OVER_SCROLL_IF_CONTENT_SCROLLS);
}
/**
@@ -1942,7 +1942,7 @@
int scrollbarStyle = SCROLLBARS_INSIDE_OVERLAY;
- int overscrollMode = mOverscrollMode;
+ int overScrollMode = mOverScrollMode;
final int N = a.getIndexCount();
for (int i = 0; i < N; i++) {
int attr = a.getIndex(i);
@@ -2148,13 +2148,13 @@
});
}
break;
- case R.styleable.View_overscrollMode:
- overscrollMode = a.getInt(attr, OVERSCROLL_ALWAYS);
+ case R.styleable.View_overScrollMode:
+ overScrollMode = a.getInt(attr, OVER_SCROLL_IF_CONTENT_SCROLLS);
break;
}
}
- setOverscrollMode(overscrollMode);
+ setOverScrollMode(overScrollMode);
if (background != null) {
setBackgroundDrawable(background);
@@ -8810,8 +8810,8 @@
/**
* Scroll the view with standard behavior for scrolling beyond the normal
* content boundaries. Views that call this method should override
- * {@link #onOverscrolled(int, int, boolean, boolean)} to respond to the
- * results of an overscroll operation.
+ * {@link #onOverScrolled(int, int, boolean, boolean)} to respond to the
+ * results of an over-scroll operation.
*
* Views can use this method to handle any touch or fling-based scrolling.
*
@@ -8821,44 +8821,44 @@
* @param scrollY Current Y scroll value in pixels before applying deltaY
* @param scrollRangeX Maximum content scroll range along the X axis
* @param scrollRangeY Maximum content scroll range along the Y axis
- * @param maxOverscrollX Number of pixels to overscroll by in either direction
+ * @param maxOverScrollX Number of pixels to overscroll by in either direction
* along the X axis.
- * @param maxOverscrollY Number of pixels to overscroll by in either direction
+ * @param maxOverScrollY Number of pixels to overscroll by in either direction
* along the Y axis.
* @param isTouchEvent true if this scroll operation is the result of a touch event.
- * @return true if scrolling was clamped to an overscroll boundary along either
+ * @return true if scrolling was clamped to an over-scroll boundary along either
* axis, false otherwise.
*/
- protected boolean overscrollBy(int deltaX, int deltaY,
+ protected boolean overScrollBy(int deltaX, int deltaY,
int scrollX, int scrollY,
int scrollRangeX, int scrollRangeY,
- int maxOverscrollX, int maxOverscrollY,
+ int maxOverScrollX, int maxOverScrollY,
boolean isTouchEvent) {
- final int overscrollMode = mOverscrollMode;
+ final int overScrollMode = mOverScrollMode;
final boolean canScrollHorizontal =
computeHorizontalScrollRange() > computeHorizontalScrollExtent();
final boolean canScrollVertical =
computeVerticalScrollRange() > computeVerticalScrollExtent();
- final boolean overscrollHorizontal = overscrollMode == OVERSCROLL_ALWAYS ||
- (overscrollMode == OVERSCROLL_IF_CONTENT_SCROLLS && canScrollHorizontal);
- final boolean overscrollVertical = overscrollMode == OVERSCROLL_ALWAYS ||
- (overscrollMode == OVERSCROLL_IF_CONTENT_SCROLLS && canScrollVertical);
+ final boolean overScrollHorizontal = overScrollMode == OVER_SCROLL_ALWAYS ||
+ (overScrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && canScrollHorizontal);
+ final boolean overScrollVertical = overScrollMode == OVER_SCROLL_ALWAYS ||
+ (overScrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && canScrollVertical);
int newScrollX = scrollX + deltaX;
- if (!overscrollHorizontal) {
- maxOverscrollX = 0;
+ if (!overScrollHorizontal) {
+ maxOverScrollX = 0;
}
int newScrollY = scrollY + deltaY;
- if (!overscrollVertical) {
- maxOverscrollY = 0;
+ if (!overScrollVertical) {
+ maxOverScrollY = 0;
}
// Clamp values if at the limits and record
- final int left = -maxOverscrollX;
- final int right = maxOverscrollX + scrollRangeX;
- final int top = -maxOverscrollY;
- final int bottom = maxOverscrollY + scrollRangeY;
+ final int left = -maxOverScrollX;
+ final int right = maxOverScrollX + scrollRangeX;
+ final int top = -maxOverScrollY;
+ final int bottom = maxOverScrollY + scrollRangeY;
boolean clampedX = false;
if (newScrollX > right) {
@@ -8878,55 +8878,55 @@
clampedY = true;
}
- onOverscrolled(newScrollX, newScrollY, clampedX, clampedY);
+ onOverScrolled(newScrollX, newScrollY, clampedX, clampedY);
return clampedX || clampedY;
}
/**
- * Called by {@link #overscrollBy(int, int, int, int, int, int, int, int, boolean)} to
- * respond to the results of an overscroll operation.
+ * Called by {@link #overScrollBy(int, int, int, int, int, int, int, int, boolean)} to
+ * respond to the results of an over-scroll operation.
*
* @param scrollX New X scroll value in pixels
* @param scrollY New Y scroll value in pixels
- * @param clampedX True if scrollX was clamped to an overscroll boundary
- * @param clampedY True if scrollY was clamped to an overscroll boundary
+ * @param clampedX True if scrollX was clamped to an over-scroll boundary
+ * @param clampedY True if scrollY was clamped to an over-scroll boundary
*/
- protected void onOverscrolled(int scrollX, int scrollY,
+ protected void onOverScrolled(int scrollX, int scrollY,
boolean clampedX, boolean clampedY) {
// Intentionally empty.
}
/**
- * Returns the overscroll mode for this view. The result will be
- * one of {@link #OVERSCROLL_ALWAYS} (default), {@link #OVERSCROLL_IF_CONTENT_SCROLLS}
- * (allow overscrolling only if the view content is larger than the container),
- * or {@link #OVERSCROLL_NEVER}.
+ * Returns the over-scroll mode for this view. The result will be
+ * one of {@link #OVER_SCROLL_ALWAYS} (default), {@link #OVER_SCROLL_IF_CONTENT_SCROLLS}
+ * (allow over-scrolling only if the view content is larger than the container),
+ * or {@link #OVER_SCROLL_NEVER}.
*
- * @return This view's overscroll mode.
+ * @return This view's over-scroll mode.
*/
- public int getOverscrollMode() {
- return mOverscrollMode;
+ public int getOverScrollMode() {
+ return mOverScrollMode;
}
/**
- * Set the overscroll mode for this view. Valid overscroll modes are
- * {@link #OVERSCROLL_ALWAYS} (default), {@link #OVERSCROLL_IF_CONTENT_SCROLLS}
- * (allow overscrolling only if the view content is larger than the container),
- * or {@link #OVERSCROLL_NEVER}.
+ * Set the over-scroll mode for this view. Valid over-scroll modes are
+ * {@link #OVER_SCROLL_ALWAYS} (default), {@link #OVER_SCROLL_IF_CONTENT_SCROLLS}
+ * (allow over-scrolling only if the view content is larger than the container),
+ * or {@link #OVER_SCROLL_NEVER}.
*
- * Setting the overscroll mode of a view will have an effect only if the
+ * Setting the over-scroll mode of a view will have an effect only if the
* view is capable of scrolling.
*
- * @param overscrollMode The new overscroll mode for this view.
+ * @param overScrollMode The new over-scroll mode for this view.
*/
- public void setOverscrollMode(int overscrollMode) {
- if (overscrollMode != OVERSCROLL_ALWAYS &&
- overscrollMode != OVERSCROLL_IF_CONTENT_SCROLLS &&
- overscrollMode != OVERSCROLL_NEVER) {
- throw new IllegalArgumentException("Invalid overscroll mode " + overscrollMode);
+ public void setOverScrollMode(int overScrollMode) {
+ if (overScrollMode != OVER_SCROLL_ALWAYS &&
+ overScrollMode != OVER_SCROLL_IF_CONTENT_SCROLLS &&
+ overScrollMode != OVER_SCROLL_NEVER) {
+ throw new IllegalArgumentException("Invalid overscroll mode " + overScrollMode);
}
- mOverscrollMode = overscrollMode;
+ mOverScrollMode = overScrollMode;
}
/**
diff --git a/core/java/android/view/WindowOrientationListener.java b/core/java/android/view/WindowOrientationListener.java
index 3e2e92b..2a76e33 100755
--- a/core/java/android/view/WindowOrientationListener.java
+++ b/core/java/android/view/WindowOrientationListener.java
@@ -109,7 +109,9 @@
}
public void setAllow180Rotation(boolean allowed) {
- mSensorEventListener.setAllow180Rotation(allowed);
+ if (mSensorEventListener != null) {
+ mSensorEventListener.setAllow180Rotation(allowed);
+ }
}
public int getCurrentRotation(int lastRotation) {
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 24b1158c..6df5445 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -1043,9 +1043,9 @@
}
@Override
- public void setOverscrollMode(int mode) {
- super.setOverscrollMode(mode);
- if (mode != OVERSCROLL_NEVER) {
+ public void setOverScrollMode(int mode) {
+ super.setOverScrollMode(mode);
+ if (mode != OVER_SCROLL_NEVER) {
if (mEdgeGlowTop == null) {
final Resources res = getContext().getResources();
final Drawable edge = res.getDrawable(R.drawable.overscroll_edge);
@@ -2565,7 +2565,7 @@
}
@Override
- protected void onOverscrolled(int scrollX, int scrollY, boolean clampedX,
+ protected void onOverScrolled(int scrollX, int scrollY, boolean clampedX,
boolean clampedY) {
mInOverScrollMode = false;
int maxX = computeMaxScrollX();
@@ -2942,12 +2942,12 @@
if (oldX != x || oldY != y) {
final int rangeX = computeMaxScrollX();
final int rangeY = computeMaxScrollY();
- overscrollBy(x - oldX, y - oldY, oldX, oldY,
+ overScrollBy(x - oldX, y - oldY, oldX, oldY,
rangeX, rangeY,
mOverflingDistance, mOverflingDistance, false);
if (mEdgeGlowTop != null) {
- if (rangeY > 0 || getOverscrollMode() == OVERSCROLL_ALWAYS) {
+ if (rangeY > 0 || getOverScrollMode() == OVER_SCROLL_ALWAYS) {
if (y < 0 && oldY >= 0) {
mEdgeGlowTop.onAbsorb((int) mScroller.getCurrVelocity());
if (!mEdgeGlowBottom.isFinished()) {
@@ -5457,7 +5457,7 @@
doFling();
break;
} else {
- if (mScroller.springback(mScrollX, mScrollY, 0,
+ if (mScroller.springBack(mScrollX, mScrollY, 0,
computeMaxScrollX(), 0,
computeMaxScrollY())) {
invalidate();
@@ -5481,7 +5481,7 @@
}
case MotionEvent.ACTION_CANCEL: {
if (mTouchMode == TOUCH_DRAG_MODE) {
- mScroller.springback(mScrollX, mScrollY, 0,
+ mScroller.springBack(mScrollX, mScrollY, 0,
computeMaxScrollX(), 0, computeMaxScrollY());
invalidate();
}
@@ -5550,7 +5550,7 @@
final int oldY = mScrollY;
final int rangeX = computeMaxScrollX();
final int rangeY = computeMaxScrollY();
- overscrollBy(deltaX, deltaY, oldX, oldY,
+ overScrollBy(deltaX, deltaY, oldX, oldY,
rangeX, rangeY,
mOverscrollDistance, mOverscrollDistance, true);
@@ -5571,7 +5571,7 @@
}
}
- if (rangeY > 0 || getOverscrollMode() == OVERSCROLL_ALWAYS) {
+ if (rangeY > 0 || getOverScrollMode() == OVER_SCROLL_ALWAYS) {
final int pulledToY = oldY + deltaY;
if (pulledToY < 0) {
mEdgeGlowTop.onPull((float) deltaY / getHeight());
@@ -5990,7 +5990,7 @@
if ((maxX == 0 && vy == 0) || (maxY == 0 && vx == 0)) {
WebViewCore.resumePriority();
WebViewCore.resumeUpdatePicture(mWebViewCore);
- if (mScroller.springback(mScrollX, mScrollY, 0, computeMaxScrollX(),
+ if (mScroller.springBack(mScrollX, mScrollY, 0, computeMaxScrollX(),
0, computeMaxScrollY())) {
invalidate();
}
@@ -7096,7 +7096,7 @@
case MotionEvent.ACTION_CANCEL:
if (mDeferTouchMode == TOUCH_DRAG_MODE) {
// no fling in defer process
- mScroller.springback(mScrollX, mScrollY, 0,
+ mScroller.springBack(mScrollX, mScrollY, 0,
computeMaxScrollX(), 0,
computeMaxScrollY());
invalidate();
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 4558854..6260cdb 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -647,8 +647,8 @@
}
@Override
- public void setOverscrollMode(int mode) {
- if (mode != OVERSCROLL_NEVER) {
+ public void setOverScrollMode(int mode) {
+ if (mode != OVER_SCROLL_NEVER) {
if (mEdgeGlowTop == null) {
final Resources res = getContext().getResources();
final Drawable edge = res.getDrawable(R.drawable.overscroll_edge);
@@ -660,7 +660,7 @@
mEdgeGlowTop = null;
mEdgeGlowBottom = null;
}
- super.setOverscrollMode(mode);
+ super.setOverScrollMode(mode);
}
/**
@@ -2232,23 +2232,29 @@
int overscroll = -incrementalDeltaY -
(motionViewRealTop - motionViewPrevTop);
- overscrollBy(0, overscroll, 0, mScrollY, 0, 0,
+ overScrollBy(0, overscroll, 0, mScrollY, 0, 0,
0, mOverscrollDistance, true);
if (Math.abs(mOverscrollDistance) == Math.abs(mScrollY)) {
// Don't allow overfling if we're at the edge.
mVelocityTracker.clear();
}
- final int overscrollMode = getOverscrollMode();
- if (overscrollMode == OVERSCROLL_ALWAYS ||
- (overscrollMode == OVERSCROLL_IF_CONTENT_SCROLLS &&
+ final int overscrollMode = getOverScrollMode();
+ if (overscrollMode == OVER_SCROLL_ALWAYS ||
+ (overscrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS &&
!contentFits())) {
mDirection = 0; // Reset when entering overscroll.
mTouchMode = TOUCH_MODE_OVERSCROLL;
if (rawDeltaY > 0) {
mEdgeGlowTop.onPull((float) overscroll / getHeight());
+ if (!mEdgeGlowBottom.isFinished()) {
+ mEdgeGlowBottom.onRelease();
+ }
} else if (rawDeltaY < 0) {
mEdgeGlowBottom.onPull((float) overscroll / getHeight());
+ if (!mEdgeGlowTop.isFinished()) {
+ mEdgeGlowTop.onRelease();
+ }
}
}
}
@@ -2299,16 +2305,22 @@
mMotionPosition = motionPosition;
}
} else {
- overscrollBy(0, -incrementalDeltaY, 0, mScrollY, 0, 0,
+ overScrollBy(0, -incrementalDeltaY, 0, mScrollY, 0, 0,
0, mOverscrollDistance, true);
- final int overscrollMode = getOverscrollMode();
- if (overscrollMode == OVERSCROLL_ALWAYS ||
- (overscrollMode == OVERSCROLL_IF_CONTENT_SCROLLS &&
+ final int overscrollMode = getOverScrollMode();
+ if (overscrollMode == OVER_SCROLL_ALWAYS ||
+ (overscrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS &&
!contentFits())) {
if (rawDeltaY > 0) {
mEdgeGlowTop.onPull((float) -incrementalDeltaY / getHeight());
+ if (!mEdgeGlowBottom.isFinished()) {
+ mEdgeGlowBottom.onRelease();
+ }
} else if (rawDeltaY < 0) {
mEdgeGlowBottom.onPull((float) -incrementalDeltaY / getHeight());
+ if (!mEdgeGlowTop.isFinished()) {
+ mEdgeGlowTop.onRelease();
+ }
}
invalidate();
}
@@ -2542,7 +2554,7 @@
}
@Override
- protected void onOverscrolled(int scrollX, int scrollY,
+ protected void onOverScrolled(int scrollX, int scrollY,
boolean clampedX, boolean clampedY) {
mScrollY = scrollY;
@@ -2767,7 +2779,7 @@
}
void startSpringback() {
- if (mScroller.springback(0, mScrollY, 0, 0, 0, 0)) {
+ if (mScroller.springBack(0, mScrollY, 0, 0, 0, 0)) {
mTouchMode = TOUCH_MODE_OVERFLING;
invalidate();
post(this);
@@ -2787,9 +2799,9 @@
void edgeReached(int delta) {
mScroller.notifyVerticalEdgeReached(mScrollY, 0, mOverflingDistance);
- final int overscrollMode = getOverscrollMode();
- if (overscrollMode == OVERSCROLL_ALWAYS ||
- (overscrollMode == OVERSCROLL_IF_CONTENT_SCROLLS && !contentFits())) {
+ final int overscrollMode = getOverScrollMode();
+ if (overscrollMode == OVER_SCROLL_ALWAYS ||
+ (overscrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && !contentFits())) {
mTouchMode = TOUCH_MODE_OVERFLING;
final int vel = (int) mScroller.getCurrVelocity();
if (delta > 0) {
@@ -2875,7 +2887,7 @@
if (motionView != null) {
// Tweak the scroll for how far we overshot
int overshoot = -(delta - (motionView.getTop() - oldTop));
- overscrollBy(0, overshoot, 0, mScrollY, 0, 0,
+ overScrollBy(0, overshoot, 0, mScrollY, 0, 0,
0, mOverflingDistance, false);
}
edgeReached(delta);
@@ -2904,7 +2916,7 @@
if (scroller.computeScrollOffset()) {
final int scrollY = mScrollY;
final int deltaY = scroller.getCurrY() - scrollY;
- if (overscrollBy(0, deltaY, 0, scrollY, 0, 0,
+ if (overScrollBy(0, deltaY, 0, scrollY, 0, 0,
0, mOverflingDistance, false)) {
startSpringback();
} else {
diff --git a/core/java/android/widget/HorizontalScrollView.java b/core/java/android/widget/HorizontalScrollView.java
index cd10a59..d38eef3 100644
--- a/core/java/android/widget/HorizontalScrollView.java
+++ b/core/java/android/widget/HorizontalScrollView.java
@@ -468,7 +468,7 @@
/* Release the drag */
mIsBeingDragged = false;
mActivePointerId = INVALID_POINTER;
- if (mScroller.springback(mScrollX, mScrollY, 0, getScrollRange(), 0, 0)) {
+ if (mScroller.springBack(mScrollX, mScrollY, 0, getScrollRange(), 0, 0)) {
invalidate();
}
break;
@@ -529,21 +529,27 @@
final int oldX = mScrollX;
final int oldY = mScrollY;
final int range = getScrollRange();
- if (overscrollBy(deltaX, 0, mScrollX, 0, range, 0,
+ if (overScrollBy(deltaX, 0, mScrollX, 0, range, 0,
mOverscrollDistance, 0, true)) {
// Break our velocity if we hit a scroll barrier.
mVelocityTracker.clear();
}
onScrollChanged(mScrollX, mScrollY, oldX, oldY);
- final int overscrollMode = getOverscrollMode();
- if (overscrollMode == OVERSCROLL_ALWAYS ||
- (overscrollMode == OVERSCROLL_IF_CONTENT_SCROLLS && range > 0)) {
+ final int overscrollMode = getOverScrollMode();
+ if (overscrollMode == OVER_SCROLL_ALWAYS ||
+ (overscrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && range > 0)) {
final int pulledToX = oldX + deltaX;
if (pulledToX < 0) {
mEdgeGlowLeft.onPull((float) deltaX / getWidth());
+ if (!mEdgeGlowRight.isFinished()) {
+ mEdgeGlowRight.onRelease();
+ }
} else if (pulledToX > range) {
mEdgeGlowRight.onPull((float) deltaX / getWidth());
+ if (!mEdgeGlowLeft.isFinished()) {
+ mEdgeGlowLeft.onRelease();
+ }
}
}
}
@@ -559,7 +565,7 @@
fling(-initialVelocity);
} else {
final int right = getScrollRange();
- if (mScroller.springback(mScrollX, mScrollY, 0, right, 0, 0)) {
+ if (mScroller.springBack(mScrollX, mScrollY, 0, right, 0, 0)) {
invalidate();
}
}
@@ -580,7 +586,7 @@
break;
case MotionEvent.ACTION_CANCEL:
if (mIsBeingDragged && getChildCount() > 0) {
- if (mScroller.springback(mScrollX, mScrollY, 0, getScrollRange(), 0, 0)) {
+ if (mScroller.springBack(mScrollX, mScrollY, 0, getScrollRange(), 0, 0)) {
invalidate();
}
mActivePointerId = INVALID_POINTER;
@@ -620,14 +626,14 @@
}
@Override
- protected void onOverscrolled(int scrollX, int scrollY,
+ protected void onOverScrolled(int scrollX, int scrollY,
boolean clampedX, boolean clampedY) {
// Treat animating scrolls differently; see #computeScroll() for why.
if (!mScroller.isFinished()) {
mScrollX = scrollX;
mScrollY = scrollY;
if (clampedX) {
- mScroller.springback(mScrollX, mScrollY, 0, getScrollRange(), 0, 0);
+ mScroller.springBack(mScrollX, mScrollY, 0, getScrollRange(), 0, 0);
}
} else {
super.scrollTo(scrollX, scrollY);
@@ -1088,14 +1094,14 @@
int y = mScroller.getCurrY();
if (oldX != x || oldY != y) {
- overscrollBy(x - oldX, y - oldY, oldX, oldY, getScrollRange(), 0,
+ overScrollBy(x - oldX, y - oldY, oldX, oldY, getScrollRange(), 0,
mOverflingDistance, 0, false);
onScrollChanged(mScrollX, mScrollY, oldX, oldY);
final int range = getScrollRange();
- final int overscrollMode = getOverscrollMode();
- if (overscrollMode == OVERSCROLL_ALWAYS ||
- (overscrollMode == OVERSCROLL_IF_CONTENT_SCROLLS && range > 0)) {
+ final int overscrollMode = getOverScrollMode();
+ if (overscrollMode == OVER_SCROLL_ALWAYS ||
+ (overscrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && range > 0)) {
if (x < 0 && oldX >= 0) {
mEdgeGlowLeft.onAbsorb((int) mScroller.getCurrVelocity());
} else if (x > range && oldX <= range) {
@@ -1376,8 +1382,8 @@
}
@Override
- public void setOverscrollMode(int mode) {
- if (mode != OVERSCROLL_NEVER) {
+ public void setOverScrollMode(int mode) {
+ if (mode != OVER_SCROLL_NEVER) {
if (mEdgeGlowLeft == null) {
final Resources res = getContext().getResources();
final Drawable edge = res.getDrawable(R.drawable.overscroll_edge);
@@ -1389,7 +1395,7 @@
mEdgeGlowLeft = null;
mEdgeGlowRight = null;
}
- super.setOverscrollMode(mode);
+ super.setOverScrollMode(mode);
}
@Override
diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java
index 46cd45a..82b7c4f 100644
--- a/core/java/android/widget/ListView.java
+++ b/core/java/android/widget/ListView.java
@@ -121,8 +121,8 @@
Drawable mDivider;
int mDividerHeight;
- Drawable mOverscrollHeader;
- Drawable mOverscrollFooter;
+ Drawable mOverScrollHeader;
+ Drawable mOverScrollFooter;
private boolean mIsCacheColorOpaque;
private boolean mDividerIsOpaque;
@@ -178,12 +178,14 @@
setDivider(d);
}
- final Drawable osHeader = a.getDrawable(com.android.internal.R.styleable.ListView_overscrollHeader);
+ final Drawable osHeader = a.getDrawable(
+ com.android.internal.R.styleable.ListView_overScrollHeader);
if (osHeader != null) {
setOverscrollHeader(osHeader);
}
- final Drawable osFooter = a.getDrawable(com.android.internal.R.styleable.ListView_overscrollFooter);
+ final Drawable osFooter = a.getDrawable(
+ com.android.internal.R.styleable.ListView_overScrollFooter);
if (osFooter != null) {
setOverscrollFooter(osFooter);
}
@@ -2997,8 +2999,8 @@
protected void dispatchDraw(Canvas canvas) {
// Draw the dividers
final int dividerHeight = mDividerHeight;
- final Drawable overscrollHeader = mOverscrollHeader;
- final Drawable overscrollFooter = mOverscrollFooter;
+ final Drawable overscrollHeader = mOverScrollHeader;
+ final Drawable overscrollFooter = mOverScrollFooter;
final boolean drawOverscrollHeader = overscrollHeader != null;
final boolean drawOverscrollFooter = overscrollFooter != null;
final boolean drawDividers = dividerHeight > 0 && mDivider != null;
@@ -3243,7 +3245,7 @@
* @param header The drawable to use
*/
public void setOverscrollHeader(Drawable header) {
- mOverscrollHeader = header;
+ mOverScrollHeader = header;
if (mScrollY < 0) {
invalidate();
}
@@ -3253,7 +3255,7 @@
* @return The drawable that will be drawn above all other list content
*/
public Drawable getOverscrollHeader() {
- return mOverscrollHeader;
+ return mOverScrollHeader;
}
/**
@@ -3264,7 +3266,7 @@
* @param footer The drawable to use
*/
public void setOverscrollFooter(Drawable footer) {
- mOverscrollFooter = footer;
+ mOverScrollFooter = footer;
invalidate();
}
@@ -3272,7 +3274,7 @@
* @return The drawable that will be drawn below all other list content
*/
public Drawable getOverscrollFooter() {
- return mOverscrollFooter;
+ return mOverScrollFooter;
}
@Override
diff --git a/core/java/android/widget/OverScroller.java b/core/java/android/widget/OverScroller.java
index 78973ad..f48eb89 100644
--- a/core/java/android/widget/OverScroller.java
+++ b/core/java/android/widget/OverScroller.java
@@ -338,7 +338,7 @@
* @return true if a springback was initiated, false if startX and startY were
* already within the valid range.
*/
- public boolean springback(int startX, int startY, int minX, int maxX, int minY, int maxY) {
+ public boolean springBack(int startX, int startY, int minX, int maxX, int minY, int maxY) {
mMode = FLING_MODE;
// Make sure both methods are called.
@@ -433,7 +433,7 @@
* @return true when the current position is overscrolled and in the process of
* interpolating back to a valid value.
*/
- public boolean isOverscrolled() {
+ public boolean isOverScrolled() {
return ((!mScrollerX.mFinished &&
mScrollerX.mState != MagneticOverScroller.TO_EDGE) ||
(!mScrollerY.mFinished &&
diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java
index 055ba87..76755de 100644
--- a/core/java/android/widget/PopupWindow.java
+++ b/core/java/android/widget/PopupWindow.java
@@ -109,6 +109,7 @@
private Drawable mBelowAnchorBackgroundDrawable;
private boolean mAboveAnchor;
+ private int mWindowLayoutType = WindowManager.LayoutParams.TYPE_APPLICATION_PANEL;
private OnDismissListener mOnDismissListener;
private boolean mIgnoreCheekPress = false;
@@ -623,6 +624,25 @@
}
/**
+ * Set the layout type for this window. Should be one of the TYPE constants defined in
+ * {@link WindowManager.LayoutParams}.
+ *
+ * @param layoutType Layout type for this window.
+ * @hide
+ */
+ public void setWindowLayoutType(int layoutType) {
+ mWindowLayoutType = layoutType;
+ }
+
+ /**
+ * @return The layout type for this window.
+ * @hide
+ */
+ public int getWindowLayoutType() {
+ return mWindowLayoutType;
+ }
+
+ /**
* <p>Change the width and height measure specs that are given to the
* window manager by the popup. By default these are 0, meaning that
* the current width or height is requested as an explicit size from
@@ -911,7 +931,7 @@
p.format = PixelFormat.TRANSLUCENT;
}
p.flags = computeFlags(p.flags);
- p.type = WindowManager.LayoutParams.TYPE_APPLICATION_PANEL;
+ p.type = mWindowLayoutType;
p.token = token;
p.softInputMode = mSoftInputMode;
p.setTitle("PopupWindow:" + Integer.toHexString(hashCode()));
diff --git a/core/java/android/widget/ScrollView.java b/core/java/android/widget/ScrollView.java
index 8472d9c..1daf2ab 100644
--- a/core/java/android/widget/ScrollView.java
+++ b/core/java/android/widget/ScrollView.java
@@ -463,7 +463,7 @@
/* Release the drag */
mIsBeingDragged = false;
mActivePointerId = INVALID_POINTER;
- if (mScroller.springback(mScrollX, mScrollY, 0, 0, 0, getScrollRange())) {
+ if (mScroller.springBack(mScrollX, mScrollY, 0, 0, 0, getScrollRange())) {
invalidate();
}
break;
@@ -524,21 +524,27 @@
final int oldX = mScrollX;
final int oldY = mScrollY;
final int range = getScrollRange();
- if (overscrollBy(0, deltaY, 0, mScrollY, 0, range,
+ if (overScrollBy(0, deltaY, 0, mScrollY, 0, range,
0, mOverscrollDistance, true)) {
// Break our velocity if we hit a scroll barrier.
mVelocityTracker.clear();
}
onScrollChanged(mScrollX, mScrollY, oldX, oldY);
- final int overscrollMode = getOverscrollMode();
- if (overscrollMode == OVERSCROLL_ALWAYS ||
- (overscrollMode == OVERSCROLL_IF_CONTENT_SCROLLS && range > 0)) {
+ final int overscrollMode = getOverScrollMode();
+ if (overscrollMode == OVER_SCROLL_ALWAYS ||
+ (overscrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && range > 0)) {
final int pulledToY = oldY + deltaY;
if (pulledToY < 0) {
mEdgeGlowTop.onPull((float) deltaY / getHeight());
+ if (!mEdgeGlowBottom.isFinished()) {
+ mEdgeGlowBottom.onRelease();
+ }
} else if (pulledToY > range) {
mEdgeGlowBottom.onPull((float) deltaY / getHeight());
+ if (!mEdgeGlowTop.isFinished()) {
+ mEdgeGlowTop.onRelease();
+ }
}
}
}
@@ -554,7 +560,7 @@
fling(-initialVelocity);
} else {
final int bottom = getScrollRange();
- if (mScroller.springback(mScrollX, mScrollY, 0, 0, 0, bottom)) {
+ if (mScroller.springBack(mScrollX, mScrollY, 0, 0, 0, bottom)) {
invalidate();
}
}
@@ -575,7 +581,7 @@
break;
case MotionEvent.ACTION_CANCEL:
if (mIsBeingDragged && getChildCount() > 0) {
- if (mScroller.springback(mScrollX, mScrollY, 0, 0, 0, getScrollRange())) {
+ if (mScroller.springBack(mScrollX, mScrollY, 0, 0, 0, getScrollRange())) {
invalidate();
}
mActivePointerId = INVALID_POINTER;
@@ -615,14 +621,14 @@
}
@Override
- protected void onOverscrolled(int scrollX, int scrollY,
+ protected void onOverScrolled(int scrollX, int scrollY,
boolean clampedX, boolean clampedY) {
// Treat animating scrolls differently; see #computeScroll() for why.
if (!mScroller.isFinished()) {
mScrollX = scrollX;
mScrollY = scrollY;
if (clampedY) {
- mScroller.springback(mScrollX, mScrollY, 0, 0, 0, getScrollRange());
+ mScroller.springBack(mScrollX, mScrollY, 0, 0, 0, getScrollRange());
}
} else {
super.scrollTo(scrollX, scrollY);
@@ -1087,14 +1093,14 @@
int y = mScroller.getCurrY();
if (oldX != x || oldY != y) {
- overscrollBy(x - oldX, y - oldY, oldX, oldY, 0, getScrollRange(),
+ overScrollBy(x - oldX, y - oldY, oldX, oldY, 0, getScrollRange(),
0, mOverflingDistance, false);
onScrollChanged(mScrollX, mScrollY, oldX, oldY);
final int range = getScrollRange();
- final int overscrollMode = getOverscrollMode();
- if (overscrollMode == OVERSCROLL_ALWAYS ||
- (overscrollMode == OVERSCROLL_IF_CONTENT_SCROLLS && range > 0)) {
+ final int overscrollMode = getOverScrollMode();
+ if (overscrollMode == OVER_SCROLL_ALWAYS ||
+ (overscrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && range > 0)) {
if (y < 0 && oldY >= 0) {
mEdgeGlowTop.onAbsorb((int) mScroller.getCurrVelocity());
} else if (y > range && oldY <= range) {
@@ -1376,8 +1382,8 @@
}
@Override
- public void setOverscrollMode(int mode) {
- if (mode != OVERSCROLL_NEVER) {
+ public void setOverScrollMode(int mode) {
+ if (mode != OVER_SCROLL_NEVER) {
if (mEdgeGlowTop == null) {
final Resources res = getContext().getResources();
final Drawable edge = res.getDrawable(R.drawable.overscroll_edge);
@@ -1389,7 +1395,7 @@
mEdgeGlowTop = null;
mEdgeGlowBottom = null;
}
- super.setOverscrollMode(mode);
+ super.setOverScrollMode(mode);
}
@Override
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 6797ea8..d1974dc 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -96,6 +96,7 @@
import android.view.ViewParent;
import android.view.ViewRoot;
import android.view.ViewTreeObserver;
+import android.view.WindowManager;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
import android.view.animation.AnimationUtils;
@@ -287,9 +288,13 @@
}
InputMethodState mInputMethodState;
- private int mTextSelectHandleLeftRes;
- private int mTextSelectHandleRightRes;
- private int mTextSelectHandleRes;
+ int mTextSelectHandleLeftRes;
+ int mTextSelectHandleRightRes;
+ int mTextSelectHandleRes;
+
+ Drawable mSelectHandleLeft;
+ Drawable mSelectHandleRight;
+ Drawable mSelectHandleCenter;
/*
* Kick-start the font cache for the zygote process (to pay the cost of
@@ -4316,6 +4321,7 @@
switch (keyCode) {
case KeyEvent.KEYCODE_ENTER:
+ mEnterKeyIsDown = true;
// If ALT modifier is held, then we always insert a
// newline character.
if ((event.getMetaState()&KeyEvent.META_ALT_ON) == 0) {
@@ -4348,6 +4354,7 @@
break;
case KeyEvent.KEYCODE_DPAD_CENTER:
+ mDPadCenterIsDown = true;
if (shouldAdvanceFocusOnEnter()) {
return 0;
}
@@ -4442,6 +4449,7 @@
switch (keyCode) {
case KeyEvent.KEYCODE_DPAD_CENTER:
+ mDPadCenterIsDown = false;
/*
* If there is a click listener, just call through to
* super, which will invoke it.
@@ -4462,6 +4470,7 @@
return super.onKeyUp(keyCode, event);
case KeyEvent.KEYCODE_ENTER:
+ mEnterKeyIsDown = false;
if (mInputContentType != null
&& mInputContentType.onEditorActionListener != null
&& mInputContentType.enterDown) {
@@ -7222,9 +7231,21 @@
}
// Two ints packed in a long
- return (((long) start) << 32) | end;
+ return packRangeInLong(start, end);
}
+ private static long packRangeInLong(int start, int end) {
+ return (((long) start) << 32) | end;
+ }
+
+ private static int extractRangeStartFromLong(long range) {
+ return (int) (range >>> 32);
+ }
+
+ private static int extractRangeEndFromLong(long range) {
+ return (int) (range & 0x00000000FFFFFFFFL);
+ }
+
private void selectCurrentWord() {
// In case selection mode is started after an orientation change or after a select all,
// use the current selection instead of creating one
@@ -7232,24 +7253,31 @@
return;
}
- int selectionStart, selectionEnd;
+ int minOffset, maxOffset;
- // selectionModifierCursorController is not null at that point
- SelectionModifierCursorController selectionModifierCursorController =
- ((SelectionModifierCursorController) mSelectionModifierCursorController);
- int minOffset = selectionModifierCursorController.getMinTouchOffset();
- int maxOffset = selectionModifierCursorController.getMaxTouchOffset();
+ if (mDPadCenterIsDown || mEnterKeyIsDown) {
+ minOffset = getSelectionStart();
+ maxOffset = getSelectionEnd();
+ } else {
+ // selectionModifierCursorController is not null at that point
+ SelectionModifierCursorController selectionModifierCursorController =
+ ((SelectionModifierCursorController) mSelectionModifierCursorController);
+ minOffset = selectionModifierCursorController.getMinTouchOffset();
+ maxOffset = selectionModifierCursorController.getMaxTouchOffset();
+ }
+
+ int selectionStart, selectionEnd;
long wordLimits = getWordLimitsAt(minOffset);
if (wordLimits >= 0) {
- selectionStart = (int) (wordLimits >>> 32);
+ selectionStart = extractRangeStartFromLong(wordLimits);
} else {
selectionStart = Math.max(minOffset - 5, 0);
}
wordLimits = getWordLimitsAt(maxOffset);
if (wordLimits >= 0) {
- selectionEnd = (int) (wordLimits & 0x00000000FFFFFFFFL);
+ selectionEnd = extractRangeEndFromLong(wordLimits);
} else {
selectionEnd = Math.min(maxOffset + 5, mText.length());
}
@@ -7258,14 +7286,10 @@
}
private String getWordForDictionary() {
- if (mLastTouchOffset < 0) {
- return null;
- }
-
- long wordLimits = getWordLimitsAt(mLastTouchOffset);
+ long wordLimits = getWordLimitsAt(getSelectionStart());
if (wordLimits >= 0) {
- int start = (int) (wordLimits >>> 32);
- int end = (int) (wordLimits & 0x00000000FFFFFFFFL);
+ int start = extractRangeStartFromLong(wordLimits);
+ int end = extractRangeEndFromLong(wordLimits);
return mTransformed.subSequence(start, end).toString();
} else {
return null;
@@ -7480,36 +7504,9 @@
CharSequence paste = clip.getText();
if (paste != null && paste.length() > 0) {
- // Paste adds/removes spaces before or after insertion as needed.
-
- if (Character.isSpaceChar(paste.charAt(0))) {
- if (min > 0 && Character.isSpaceChar(mTransformed.charAt(min - 1))) {
- // Two spaces at beginning of paste: remove one
- ((Editable) mText).replace(min - 1, min, "");
- min = min - 1;
- max = max - 1;
- }
- } else {
- if (min > 0 && !Character.isSpaceChar(mTransformed.charAt(min - 1))) {
- // No space at beginning of paste: add one
- ((Editable) mText).replace(min, min, " ");
- min = min + 1;
- max = max + 1;
- }
- }
-
- if (Character.isSpaceChar(paste.charAt(paste.length() - 1))) {
- if (max < mText.length() && Character.isSpaceChar(mTransformed.charAt(max))) {
- // Two spaces at end of paste: remove one
- ((Editable) mText).replace(max, max + 1, "");
- }
- } else {
- if (max < mText.length() && !Character.isSpaceChar(mTransformed.charAt(max))) {
- // No space at end of paste: add one
- ((Editable) mText).replace(max, max, " ");
- }
- }
-
+ long minMax = prepareSpacesAroundPaste(min, max, paste);
+ min = extractRangeStartFromLong(minMax);
+ max = extractRangeEndFromLong(minMax);
Selection.setSelection((Spannable) mText, max);
((Editable) mText).replace(min, max, paste);
stopTextSelectionMode();
@@ -7545,6 +7542,49 @@
return false;
}
+ /**
+ * Prepare text so that there are not zero or two spaces at beginning and end of region defined
+ * by [min, max] when replacing this region by paste.
+ */
+ private long prepareSpacesAroundPaste(int min, int max, CharSequence paste) {
+ // Paste adds/removes spaces before or after insertion as needed.
+ if (Character.isSpaceChar(paste.charAt(0))) {
+ if (min > 0 && Character.isSpaceChar(mTransformed.charAt(min - 1))) {
+ // Two spaces at beginning of paste: remove one
+ final int originalLength = mText.length();
+ ((Editable) mText).replace(min - 1, min, "");
+ // Due to filters, there is no garantee that exactly one character was
+ // removed. Count instead.
+ final int delta = mText.length() - originalLength;
+ min += delta;
+ max += delta;
+ }
+ } else {
+ if (min > 0 && !Character.isSpaceChar(mTransformed.charAt(min - 1))) {
+ // No space at beginning of paste: add one
+ final int originalLength = mText.length();
+ ((Editable) mText).replace(min, min, " ");
+ // Taking possible filters into account as above.
+ final int delta = mText.length() - originalLength;
+ min += delta;
+ max += delta;
+ }
+ }
+
+ if (Character.isSpaceChar(paste.charAt(paste.length() - 1))) {
+ if (max < mText.length() && Character.isSpaceChar(mTransformed.charAt(max))) {
+ // Two spaces at end of paste: remove one
+ ((Editable) mText).replace(max, max + 1, "");
+ }
+ } else {
+ if (max < mText.length() && !Character.isSpaceChar(mTransformed.charAt(max))) {
+ // No space at end of paste: add one
+ ((Editable) mText).replace(max, max, " ");
+ }
+ }
+ return packRangeInLong(min, max);
+ }
+
@Override
public boolean performLongClick() {
if (super.performLongClick()) {
@@ -7644,26 +7684,75 @@
private int mPositionY;
private CursorController mController;
private boolean mIsDragging;
- private float mOffsetX;
- private float mOffsetY;
+ private float mTouchToWindowOffsetX;
+ private float mTouchToWindowOffsetY;
private float mHotspotX;
private float mHotspotY;
+ private int mHeight;
+ private float mTouchOffsetY;
private int mLastParentX;
private int mLastParentY;
- public HandleView(CursorController controller, Drawable handle) {
+ public static final int LEFT = 0;
+ public static final int CENTER = 1;
+ public static final int RIGHT = 2;
+
+ public HandleView(CursorController controller, int pos) {
super(TextView.this.mContext);
mController = controller;
- mDrawable = handle;
mContainer = new PopupWindow(TextView.this.mContext, null,
com.android.internal.R.attr.textSelectHandleWindowStyle);
mContainer.setSplitTouchEnabled(true);
mContainer.setClippingEnabled(false);
+ mContainer.setWindowLayoutType(WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL);
- final int handleWidth = mDrawable.getIntrinsicWidth();
+ setOrientation(pos);
+ }
+
+ public void setOrientation(int pos) {
+ int handleWidth;
+ switch (pos) {
+ case LEFT: {
+ if (mSelectHandleLeft == null) {
+ mSelectHandleLeft = mContext.getResources().getDrawable(
+ mTextSelectHandleLeftRes);
+ }
+ mDrawable = mSelectHandleLeft;
+ handleWidth = mDrawable.getIntrinsicWidth();
+ mHotspotX = handleWidth / 4 * 3;
+ break;
+ }
+
+ case RIGHT: {
+ if (mSelectHandleRight == null) {
+ mSelectHandleRight = mContext.getResources().getDrawable(
+ mTextSelectHandleRightRes);
+ }
+ mDrawable = mSelectHandleRight;
+ handleWidth = mDrawable.getIntrinsicWidth();
+ mHotspotX = handleWidth / 4;
+ break;
+ }
+
+ case CENTER:
+ default: {
+ if (mSelectHandleCenter == null) {
+ mSelectHandleCenter = mContext.getResources().getDrawable(
+ mTextSelectHandleRes);
+ }
+ mDrawable = mSelectHandleCenter;
+ handleWidth = mDrawable.getIntrinsicWidth();
+ mHotspotX = handleWidth / 2;
+ break;
+ }
+ }
+
final int handleHeight = mDrawable.getIntrinsicHeight();
- mHotspotX = handleWidth * 0.5f;
- mHotspotY = -handleHeight * 0.2f;
+
+ mTouchOffsetY = -handleHeight * 0.3f;
+ mHotspotY = 0;
+ mHeight = handleHeight;
+ invalidate();
}
@Override
@@ -7728,10 +7817,10 @@
final int[] coords = mTempCoords;
hostView.getLocationInWindow(coords);
final int posX = coords[0] + mPositionX + (int) mHotspotX;
- final int posY = coords[1] + mPositionY;
+ final int posY = coords[1] + mPositionY + (int) mHotspotY;
return posX >= clip.left && posX <= clip.right &&
- posY >= clip.top && posY + mHotspotY <= clip.bottom;
+ posY >= clip.top && posY <= clip.bottom;
}
private void moveTo(int x, int y) {
@@ -7754,8 +7843,8 @@
TextView.this.getLocationInWindow(coords);
}
if (coords[0] != mLastParentX || coords[1] != mLastParentY) {
- mOffsetX += coords[0] - mLastParentX;
- mOffsetY += coords[1] - mLastParentY;
+ mTouchToWindowOffsetX += coords[0] - mLastParentX;
+ mTouchToWindowOffsetY += coords[1] - mLastParentY;
mLastParentX = coords[0];
mLastParentY = coords[1];
}
@@ -7784,8 +7873,8 @@
case MotionEvent.ACTION_DOWN: {
final float rawX = ev.getRawX();
final float rawY = ev.getRawY();
- mOffsetX = rawX - mPositionX;
- mOffsetY = rawY - mPositionY;
+ mTouchToWindowOffsetX = rawX - mPositionX;
+ mTouchToWindowOffsetY = rawY - mPositionY;
final int[] coords = mTempCoords;
TextView.this.getLocationInWindow(coords);
mLastParentX = coords[0];
@@ -7796,11 +7885,10 @@
case MotionEvent.ACTION_MOVE: {
final float rawX = ev.getRawX();
final float rawY = ev.getRawY();
- final float newPosX = rawX - mOffsetX + mHotspotX;
- final float newPosY = rawY - mOffsetY + mHotspotY;
+ final float newPosX = rawX - mTouchToWindowOffsetX + mHotspotX;
+ final float newPosY = rawY - mTouchToWindowOffsetY + mHotspotY + mTouchOffsetY;
- mController.updatePosition(this, (int) Math.round(newPosX),
- (int) Math.round(newPosY));
+ mController.updatePosition(this, Math.round(newPosX), Math.round(newPosY));
break;
}
@@ -7823,9 +7911,9 @@
final int lineBottom = mLayout.getLineBottom(line);
final Rect bounds = sCursorControllerTempRect;
- bounds.left = (int) (mLayout.getPrimaryHorizontal(offset) - width / 2.0)
+ bounds.left = (int) (mLayout.getPrimaryHorizontal(offset) - mHotspotX)
+ TextView.this.mScrollX;
- bounds.top = (bottom ? lineBottom : lineTop) + TextView.this.mScrollY;
+ bounds.top = (bottom ? lineBottom : lineTop - mHeight) + TextView.this.mScrollY;
bounds.right = bounds.left + width;
bounds.bottom = bounds.top + height;
@@ -7848,8 +7936,7 @@
};
InsertionPointCursorController() {
- Resources res = mContext.getResources();
- mHandle = new HandleView(this, res.getDrawable(mTextSelectHandleRes));
+ mHandle = new HandleView(this, HandleView.CENTER);
}
public void show() {
@@ -7924,9 +8011,8 @@
};
SelectionModifierCursorController() {
- Resources res = mContext.getResources();
- mStartHandle = new HandleView(this, res.getDrawable(mTextSelectHandleLeftRes));
- mEndHandle = new HandleView(this, res.getDrawable(mTextSelectHandleRightRes));
+ mStartHandle = new HandleView(this, HandleView.LEFT);
+ mEndHandle = new HandleView(this, HandleView.RIGHT);
}
public void show() {
@@ -7967,31 +8053,25 @@
// Handle the case where start and end are swapped, making sure start <= end
if (handle == mStartHandle) {
- if (offset <= selectionEnd) {
- if (selectionStart == offset) {
- return; // no change, no need to redraw;
- }
- selectionStart = offset;
- } else {
- selectionStart = selectionEnd;
- selectionEnd = offset;
- HandleView temp = mStartHandle;
- mStartHandle = mEndHandle;
- mEndHandle = temp;
+ if (selectionStart == offset || offset > selectionEnd) {
+ return; // no change, no need to redraw;
}
+ // If the user "closes" the selection entirely they were probably trying to
+ // select a single character. Help them out.
+ if (offset == selectionEnd) {
+ offset = selectionEnd - 1;
+ }
+ selectionStart = offset;
} else {
- if (offset >= selectionStart) {
- if (selectionEnd == offset) {
- return; // no change, no need to redraw;
- }
- selectionEnd = offset;
- } else {
- selectionEnd = selectionStart;
- selectionStart = offset;
- HandleView temp = mStartHandle;
- mStartHandle = mEndHandle;
- mEndHandle = temp;
+ if (selectionEnd == offset || offset < selectionStart) {
+ return; // no change, no need to redraw;
}
+ // If the user "closes" the selection entirely they were probably trying to
+ // select a single character. Help them out.
+ if (offset == selectionStart) {
+ offset = selectionStart + 1;
+ }
+ selectionEnd = offset;
}
Selection.setSelection((Spannable) mText, selectionStart, selectionEnd);
@@ -8009,9 +8089,7 @@
return;
}
- boolean oneLineSelection = mLayout.getLineForOffset(selectionStart) ==
- mLayout.getLineForOffset(selectionEnd);
- mStartHandle.positionAtCursor(selectionStart, oneLineSelection);
+ mStartHandle.positionAtCursor(selectionStart, true);
mEndHandle.positionAtCursor(selectionEnd, true);
hideDelayed(DELAY_BEFORE_FADE_OUT);
}
@@ -8137,7 +8215,7 @@
final int previousLine = layout.getLineForOffset(previousOffset);
final int previousLineTop = layout.getLineTop(previousLine);
final int previousLineBottom = layout.getLineBottom(previousLine);
- final int hysteresisThreshold = (previousLineBottom - previousLineTop) / 6;
+ final int hysteresisThreshold = (previousLineBottom - previousLineTop) / 8;
// If new line is just before or after previous line and y position is less than
// hysteresisThreshold away from previous line, keep cursor on previous line.
@@ -8182,6 +8260,10 @@
private CursorController mSelectionModifierCursorController;
private boolean mIsInTextSelectionMode = false;
private int mLastTouchOffset = -1;
+ // These are needed to desambiguate a long click. If the long click comes from ones of these, we
+ // select from the current cursor position. Otherwise, select from long pressed position.
+ private boolean mDPadCenterIsDown = false;
+ private boolean mEnterKeyIsDown = false;
// Created once and shared by different CursorController helper methods.
// Only one cursor controller is active at any time which prevent race conditions.
private static Rect sCursorControllerTempRect = new Rect();
diff --git a/core/java/com/android/internal/content/NativeLibraryHelper.java b/core/java/com/android/internal/content/NativeLibraryHelper.java
index 2a8cd94..00c4dbe 100644
--- a/core/java/com/android/internal/content/NativeLibraryHelper.java
+++ b/core/java/com/android/internal/content/NativeLibraryHelper.java
@@ -294,33 +294,44 @@
}
}
+ // Convenience method to call removeNativeBinariesFromDirLI(File)
+ public static boolean removeNativeBinariesLI(String nativeLibraryPath) {
+ return removeNativeBinariesFromDirLI(new File(nativeLibraryPath));
+ }
+
// Remove the native binaries of a given package. This simply
// gets rid of the files in the 'lib' sub-directory.
- public static void removeNativeBinariesLI(String nativeLibraryPath) {
+ public static boolean removeNativeBinariesFromDirLI(File nativeLibraryDir) {
if (DEBUG_NATIVE) {
- Slog.w(TAG, "Deleting native binaries from: " + nativeLibraryPath);
+ Slog.w(TAG, "Deleting native binaries from: " + nativeLibraryDir.getPath());
}
+ boolean deletedFiles = false;
+
/*
* Just remove any file in the directory. Since the directory is owned
* by the 'system' UID, the application is not supposed to have written
* anything there.
*/
- File binaryDir = new File(nativeLibraryPath);
- if (binaryDir.exists()) {
- File[] binaries = binaryDir.listFiles();
+ if (nativeLibraryDir.exists()) {
+ final File[] binaries = nativeLibraryDir.listFiles();
if (binaries != null) {
for (int nn = 0; nn < binaries.length; nn++) {
if (DEBUG_NATIVE) {
Slog.d(TAG, " Deleting " + binaries[nn].getName());
}
+
if (!binaries[nn].delete()) {
Slog.w(TAG, "Could not delete native binary: " + binaries[nn].getPath());
+ } else {
+ deletedFiles = true;
}
}
}
// Do not delete 'lib' directory itself, or this will prevent
// installation of future updates.
}
+
+ return deletedFiles;
}
}
diff --git a/core/jni/android_os_MessageQueue.cpp b/core/jni/android_os_MessageQueue.cpp
index 1b203ca..d2e5462 100644
--- a/core/jni/android_os_MessageQueue.cpp
+++ b/core/jni/android_os_MessageQueue.cpp
@@ -41,7 +41,7 @@
inline sp<Looper> getLooper() { return mLooper; }
- bool pollOnce(int timeoutMillis);
+ void pollOnce(int timeoutMillis);
void wake();
private:
@@ -61,8 +61,8 @@
NativeMessageQueue::~NativeMessageQueue() {
}
-bool NativeMessageQueue::pollOnce(int timeoutMillis) {
- return mLooper->pollOnce(timeoutMillis) != ALOOPER_POLL_TIMEOUT;
+void NativeMessageQueue::pollOnce(int timeoutMillis) {
+ mLooper->pollOnce(timeoutMillis);
}
void NativeMessageQueue::wake() {
@@ -112,24 +112,14 @@
jniThrowException(env, "java/lang/IllegalStateException", "Message queue not initialized");
}
-static jboolean android_os_MessageQueue_nativePollOnce(JNIEnv* env, jobject obj,
- jint timeoutMillis) {
- NativeMessageQueue* nativeMessageQueue =
- android_os_MessageQueue_getNativeMessageQueue(env, obj);
- if (! nativeMessageQueue) {
- throwQueueNotInitialized(env);
- return false;
- }
- return nativeMessageQueue->pollOnce(timeoutMillis);
+static void android_os_MessageQueue_nativePollOnce(JNIEnv* env, jobject obj,
+ jint ptr, jint timeoutMillis) {
+ NativeMessageQueue* nativeMessageQueue = reinterpret_cast<NativeMessageQueue*>(ptr);
+ nativeMessageQueue->pollOnce(timeoutMillis);
}
-static void android_os_MessageQueue_nativeWake(JNIEnv* env, jobject obj) {
- NativeMessageQueue* nativeMessageQueue =
- android_os_MessageQueue_getNativeMessageQueue(env, obj);
- if (! nativeMessageQueue) {
- throwQueueNotInitialized(env);
- return;
- }
+static void android_os_MessageQueue_nativeWake(JNIEnv* env, jobject obj, jint ptr) {
+ NativeMessageQueue* nativeMessageQueue = reinterpret_cast<NativeMessageQueue*>(ptr);
return nativeMessageQueue->wake();
}
@@ -139,8 +129,8 @@
/* name, signature, funcPtr */
{ "nativeInit", "()V", (void*)android_os_MessageQueue_nativeInit },
{ "nativeDestroy", "()V", (void*)android_os_MessageQueue_nativeDestroy },
- { "nativePollOnce", "(I)Z", (void*)android_os_MessageQueue_nativePollOnce },
- { "nativeWake", "()V", (void*)android_os_MessageQueue_nativeWake }
+ { "nativePollOnce", "(II)V", (void*)android_os_MessageQueue_nativePollOnce },
+ { "nativeWake", "(I)V", (void*)android_os_MessageQueue_nativeWake }
};
#define FIND_CLASS(var, className) \
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index b9eb5d6..9d914ad 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -364,6 +364,13 @@
android:description="@string/permdesc_nfcLlcp"
android:label="@string/permlab_nfcLlcp" />
+ <!-- Allows an application to use SIP service -->
+ <permission android:name="android.permission.USE_SIP"
+ android:permissionGroup="android.permission-group.NETWORK"
+ android:protectionLevel="dangerous"
+ android:description="@string/permdesc_use_sip"
+ android:label="@string/permlab_use_sip" />
+
<!-- Allows applications to call into AccountAuthenticators. Only
the system can get this permission. -->
<permission android:name="android.permission.ACCOUNT_MANAGER"
diff --git a/core/res/res/drawable-hdpi/btn_default_small_normal.9.png b/core/res/res/drawable-hdpi/btn_default_small_normal.9.png
index 11a97d0..6d3ea9a 100755
--- a/core/res/res/drawable-hdpi/btn_default_small_normal.9.png
+++ b/core/res/res/drawable-hdpi/btn_default_small_normal.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_default_small_normal_disable.9.png b/core/res/res/drawable-hdpi/btn_default_small_normal_disable.9.png
index 8f86e3d..2646ba0 100755
--- a/core/res/res/drawable-hdpi/btn_default_small_normal_disable.9.png
+++ b/core/res/res/drawable-hdpi/btn_default_small_normal_disable.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_default_small_normal_disable_focused.9.png b/core/res/res/drawable-hdpi/btn_default_small_normal_disable_focused.9.png
index 7c8082f..013210c 100755
--- a/core/res/res/drawable-hdpi/btn_default_small_normal_disable_focused.9.png
+++ b/core/res/res/drawable-hdpi/btn_default_small_normal_disable_focused.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_default_small_pressed.9.png b/core/res/res/drawable-hdpi/btn_default_small_pressed.9.png
index cf03f7e..24cefd4 100755
--- a/core/res/res/drawable-hdpi/btn_default_small_pressed.9.png
+++ b/core/res/res/drawable-hdpi/btn_default_small_pressed.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_default_small_selected.9.png b/core/res/res/drawable-hdpi/btn_default_small_selected.9.png
index 477a666..bedbceb 100755
--- a/core/res/res/drawable-hdpi/btn_default_small_selected.9.png
+++ b/core/res/res/drawable-hdpi/btn_default_small_selected.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/popup_bottom_bright.9.png b/core/res/res/drawable-hdpi/popup_bottom_bright.9.png
index f4125a8..eaae624 100755
--- a/core/res/res/drawable-hdpi/popup_bottom_bright.9.png
+++ b/core/res/res/drawable-hdpi/popup_bottom_bright.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/popup_bottom_dark.9.png b/core/res/res/drawable-hdpi/popup_bottom_dark.9.png
index 734981a..8b5d3d5 100755
--- a/core/res/res/drawable-hdpi/popup_bottom_dark.9.png
+++ b/core/res/res/drawable-hdpi/popup_bottom_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/popup_center_bright.9.png b/core/res/res/drawable-hdpi/popup_center_bright.9.png
index 102c84b..e0ea9c0fa 100755
--- a/core/res/res/drawable-hdpi/popup_center_bright.9.png
+++ b/core/res/res/drawable-hdpi/popup_center_bright.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/popup_center_dark.9.png b/core/res/res/drawable-hdpi/popup_center_dark.9.png
old mode 100644
new mode 100755
Binary files differ
diff --git a/core/res/res/drawable-hdpi/popup_full_bright.9.png b/core/res/res/drawable-hdpi/popup_full_bright.9.png
index d98ab0c..e5b1b46 100755
--- a/core/res/res/drawable-hdpi/popup_full_bright.9.png
+++ b/core/res/res/drawable-hdpi/popup_full_bright.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/popup_full_dark.9.png b/core/res/res/drawable-hdpi/popup_full_dark.9.png
index 502adaf..8f2fdf0 100755
--- a/core/res/res/drawable-hdpi/popup_full_dark.9.png
+++ b/core/res/res/drawable-hdpi/popup_full_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/popup_top_bright.9.png b/core/res/res/drawable-hdpi/popup_top_bright.9.png
index e52a603..766a658 100755
--- a/core/res/res/drawable-hdpi/popup_top_bright.9.png
+++ b/core/res/res/drawable-hdpi/popup_top_bright.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/popup_top_dark.9.png b/core/res/res/drawable-hdpi/popup_top_dark.9.png
index 3f7d61e..1108909 100755
--- a/core/res/res/drawable-hdpi/popup_top_dark.9.png
+++ b/core/res/res/drawable-hdpi/popup_top_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/screen_progress_frame.9.png b/core/res/res/drawable-hdpi/screen_progress_frame.9.png
deleted file mode 100644
index 3f9d738..0000000
--- a/core/res/res/drawable-hdpi/screen_progress_frame.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/screen_progress_inner.9.png b/core/res/res/drawable-hdpi/screen_progress_inner.9.png
deleted file mode 100644
index 10c7da5..0000000
--- a/core/res/res/drawable-hdpi/screen_progress_inner.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_gps_on.png b/core/res/res/drawable-hdpi/stat_sys_gps_on.png
index f901ae8..1e1ab32 100644
--- a/core/res/res/drawable-hdpi/stat_sys_gps_on.png
+++ b/core/res/res/drawable-hdpi/stat_sys_gps_on.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_r_signal_0_cdma.png b/core/res/res/drawable-hdpi/stat_sys_r_signal_0_cdma.png
index 28b2fc2..14a7e94 100644
--- a/core/res/res/drawable-hdpi/stat_sys_r_signal_0_cdma.png
+++ b/core/res/res/drawable-hdpi/stat_sys_r_signal_0_cdma.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_r_signal_1_cdma.png b/core/res/res/drawable-hdpi/stat_sys_r_signal_1_cdma.png
index a7449cd..9cf04b5 100644
--- a/core/res/res/drawable-hdpi/stat_sys_r_signal_1_cdma.png
+++ b/core/res/res/drawable-hdpi/stat_sys_r_signal_1_cdma.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_r_signal_2_cdma.png b/core/res/res/drawable-hdpi/stat_sys_r_signal_2_cdma.png
index c4c1fb8..dbd3308 100644
--- a/core/res/res/drawable-hdpi/stat_sys_r_signal_2_cdma.png
+++ b/core/res/res/drawable-hdpi/stat_sys_r_signal_2_cdma.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_r_signal_3_cdma.png b/core/res/res/drawable-hdpi/stat_sys_r_signal_3_cdma.png
index 1d2f966..a3a6b6c 100755
--- a/core/res/res/drawable-hdpi/stat_sys_r_signal_3_cdma.png
+++ b/core/res/res/drawable-hdpi/stat_sys_r_signal_3_cdma.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_r_signal_4_cdma.png b/core/res/res/drawable-hdpi/stat_sys_r_signal_4_cdma.png
index beefdd2..0f95041 100644
--- a/core/res/res/drawable-hdpi/stat_sys_r_signal_4_cdma.png
+++ b/core/res/res/drawable-hdpi/stat_sys_r_signal_4_cdma.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_ra_signal_0_cdma.png b/core/res/res/drawable-hdpi/stat_sys_ra_signal_0_cdma.png
index 901058a..a2fa547 100755
--- a/core/res/res/drawable-hdpi/stat_sys_ra_signal_0_cdma.png
+++ b/core/res/res/drawable-hdpi/stat_sys_ra_signal_0_cdma.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_ra_signal_1_cdma.png b/core/res/res/drawable-hdpi/stat_sys_ra_signal_1_cdma.png
index f5c5f98..17c8681 100755
--- a/core/res/res/drawable-hdpi/stat_sys_ra_signal_1_cdma.png
+++ b/core/res/res/drawable-hdpi/stat_sys_ra_signal_1_cdma.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_ra_signal_2_cdma.png b/core/res/res/drawable-hdpi/stat_sys_ra_signal_2_cdma.png
index 82102b2..4a21fb6 100755
--- a/core/res/res/drawable-hdpi/stat_sys_ra_signal_2_cdma.png
+++ b/core/res/res/drawable-hdpi/stat_sys_ra_signal_2_cdma.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_ra_signal_3_cdma.png b/core/res/res/drawable-hdpi/stat_sys_ra_signal_3_cdma.png
index 91037da..188b1f9 100644
--- a/core/res/res/drawable-hdpi/stat_sys_ra_signal_3_cdma.png
+++ b/core/res/res/drawable-hdpi/stat_sys_ra_signal_3_cdma.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_ra_signal_4_cdma.png b/core/res/res/drawable-hdpi/stat_sys_ra_signal_4_cdma.png
index c08cc86..5729f7d 100755
--- a/core/res/res/drawable-hdpi/stat_sys_ra_signal_4_cdma.png
+++ b/core/res/res/drawable-hdpi/stat_sys_ra_signal_4_cdma.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/text_select_handle_left.png b/core/res/res/drawable-hdpi/text_select_handle_left.png
old mode 100644
new mode 100755
index 271a6d0..3743d91
--- a/core/res/res/drawable-hdpi/text_select_handle_left.png
+++ b/core/res/res/drawable-hdpi/text_select_handle_left.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/text_select_handle_middle.png b/core/res/res/drawable-hdpi/text_select_handle_middle.png
old mode 100644
new mode 100755
index 5a83c6c..daf8e68
--- a/core/res/res/drawable-hdpi/text_select_handle_middle.png
+++ b/core/res/res/drawable-hdpi/text_select_handle_middle.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/text_select_handle_right.png b/core/res/res/drawable-hdpi/text_select_handle_right.png
old mode 100644
new mode 100755
index dfdf899..12a3dff
--- a/core/res/res/drawable-hdpi/text_select_handle_right.png
+++ b/core/res/res/drawable-hdpi/text_select_handle_right.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_default_small_normal.9.png b/core/res/res/drawable-mdpi/btn_default_small_normal.9.png
index bcedd5f..5dddd46 100644
--- a/core/res/res/drawable-mdpi/btn_default_small_normal.9.png
+++ b/core/res/res/drawable-mdpi/btn_default_small_normal.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_default_small_normal_disable.9.png b/core/res/res/drawable-mdpi/btn_default_small_normal_disable.9.png
index ac6260f..6ab5c4a 100644
--- a/core/res/res/drawable-mdpi/btn_default_small_normal_disable.9.png
+++ b/core/res/res/drawable-mdpi/btn_default_small_normal_disable.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_default_small_normal_disable_focused.9.png b/core/res/res/drawable-mdpi/btn_default_small_normal_disable_focused.9.png
index 4ee1b3f..c65bace 100644
--- a/core/res/res/drawable-mdpi/btn_default_small_normal_disable_focused.9.png
+++ b/core/res/res/drawable-mdpi/btn_default_small_normal_disable_focused.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_default_small_pressed.9.png b/core/res/res/drawable-mdpi/btn_default_small_pressed.9.png
index 25e38f4..43e82f9 100644
--- a/core/res/res/drawable-mdpi/btn_default_small_pressed.9.png
+++ b/core/res/res/drawable-mdpi/btn_default_small_pressed.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_default_small_selected.9.png b/core/res/res/drawable-mdpi/btn_default_small_selected.9.png
index cc209c6..7a376a9 100644
--- a/core/res/res/drawable-mdpi/btn_default_small_selected.9.png
+++ b/core/res/res/drawable-mdpi/btn_default_small_selected.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_emergency.png b/core/res/res/drawable-mdpi/ic_emergency.png
index 45d0f21..c6faf1e 100755
--- a/core/res/res/drawable-mdpi/ic_emergency.png
+++ b/core/res/res/drawable-mdpi/ic_emergency.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/screen_progress_frame.9.png b/core/res/res/drawable-mdpi/screen_progress_frame.9.png
deleted file mode 100644
index 0e92429..0000000
--- a/core/res/res/drawable-mdpi/screen_progress_frame.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/screen_progress_inner.9.png b/core/res/res/drawable-mdpi/screen_progress_inner.9.png
deleted file mode 100644
index 1799a53..0000000
--- a/core/res/res/drawable-mdpi/screen_progress_inner.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/screen_progress.xml b/core/res/res/drawable/screen_progress.xml
deleted file mode 100644
index aed23a6..0000000
--- a/core/res/res/drawable/screen_progress.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/* //device/apps/common/res/drawable/progress.xml
-**
-** Copyright 2007, 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.
-*/
--->
-
-<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:drawable="@android:drawable/screen_progress_frame" />
- <item>
- <scale scaleWidth="100%" scaleGravity="0x3" drawable="@android:drawable/screen_progress_inner" />
- </item>
-</layer-list>
-
diff --git a/core/res/res/layout/alert_dialog.xml b/core/res/res/layout/alert_dialog.xml
index 25a41f8..d461f40 100644
--- a/core/res/res/layout/alert_dialog.xml
+++ b/core/res/res/layout/alert_dialog.xml
@@ -81,7 +81,7 @@
android:paddingBottom="12dip"
android:paddingLeft="14dip"
android:paddingRight="10dip"
- android:overscrollMode="ifContentScrolls">
+ android:overScrollMode="ifContentScrolls">
<TextView android:id="@+id/message"
style="?android:attr/textAppearanceMedium"
android:layout_width="match_parent"
diff --git a/core/res/res/layout/preference_dialog_edittext.xml b/core/res/res/layout/preference_dialog_edittext.xml
index b41e774..b2a4368 100644
--- a/core/res/res/layout/preference_dialog_edittext.xml
+++ b/core/res/res/layout/preference_dialog_edittext.xml
@@ -18,7 +18,7 @@
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:overscrollMode="ifContentScrolls">
+ android:overScrollMode="ifContentScrolls">
<LinearLayout
android:id="@+android:id/edittext_container"
diff --git a/core/res/res/layout/select_dialog.xml b/core/res/res/layout/select_dialog.xml
index 6e4e5e1..a1a3e76 100644
--- a/core/res/res/layout/select_dialog.xml
+++ b/core/res/res/layout/select_dialog.xml
@@ -32,4 +32,4 @@
android:cacheColorHint="@null"
android:divider="@android:drawable/divider_horizontal_bright"
android:scrollbars="vertical"
- android:overscrollMode="ifContentScrolls" />
+ android:overScrollMode="ifContentScrolls" />
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 925e26c..9029ab3 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -267,8 +267,8 @@
<string name="permdesc_clearAppCache" msgid="7740465694193671402">"Umožňuje aplikaci uvolnit paměť telefonu smazáním souborů v adresáři mezipaměti aplikace. Přístup je velmi omezený, většinou pouze pro systémové procesy."</string>
<string name="permlab_movePackage" msgid="728454979946503926">"Přesun zdrojů aplikace"</string>
<string name="permdesc_movePackage" msgid="6323049291923925277">"Umožňuje aplikaci přesunout své zdroje z interní paměti na externí médium a opačně."</string>
- <!-- outdated translation 4811921703882532070 --> <string name="permlab_readLogs" msgid="6615778543198967614">"čtení systémových souborů protokolu"</string>
- <!-- outdated translation 2257937955580475902 --> <string name="permdesc_readLogs" msgid="8896449437464867766">"Umožňuje aplikaci číst různé systémové soubory protokolů. Toto nastavení aplikaci umožní získat obecné informace o činnostech s telefonem, ale neměly by obsahovat žádné osobní či soukromé informace."</string>
+ <string name="permlab_readLogs" msgid="6615778543198967614">"číst citlivá data v protokolech"</string>
+ <string name="permdesc_readLogs" msgid="8896449437464867766">"Umožňuje aplikaci číst různé systémové soubory protokolů. Toto nastavení aplikaci umožní získat obecné informace o činnostech s telefonem, které by mohly obsahovat osobní či soukromé informace."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"čtení nebo zápis do prostředků funkce diag"</string>
<string name="permdesc_diagnostic" msgid="3121238373951637049">"Umožňuje aplikaci číst libovolné prostředky ve skupině diag, např. soubory ve složce /dev, a zapisovat do nich. Může dojít k ovlivnění stability a bezpečnosti systému. Toto nastavení by měl používat pouze výrobce či operátor pro diagnostiku hardwaru."</string>
<string name="permlab_changeComponentState" msgid="79425198834329406">"povolení či zakázání komponent aplikací"</string>
@@ -544,14 +544,10 @@
<string name="orgTypeWork" msgid="29268870505363872">"Práce"</string>
<string name="orgTypeOther" msgid="3951781131570124082">"Jiné"</string>
<string name="orgTypeCustom" msgid="225523415372088322">"Vlastní"</string>
- <!-- no translation found for sipAddressTypeCustom (2473580593111590945) -->
- <skip />
- <!-- no translation found for sipAddressTypeHome (6093598181069359295) -->
- <skip />
- <!-- no translation found for sipAddressTypeWork (6920725730797099047) -->
- <skip />
- <!-- no translation found for sipAddressTypeOther (4408436162950119849) -->
- <skip />
+ <string name="sipAddressTypeCustom" msgid="2473580593111590945">"Vlastní"</string>
+ <string name="sipAddressTypeHome" msgid="6093598181069359295">"Plocha"</string>
+ <string name="sipAddressTypeWork" msgid="6920725730797099047">"Práce"</string>
+ <string name="sipAddressTypeOther" msgid="4408436162950119849">"Jiné"</string>
<string name="contact_status_update_attribution" msgid="5112589886094402795">"pomocí <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
<string name="contact_status_update_attribution_with_date" msgid="5945386376369979909">"<xliff:g id="DATE">%1$s</xliff:g> pomocí <xliff:g id="SOURCE">%2$s</xliff:g>"</string>
<string name="keyguard_password_enter_pin_code" msgid="3731488827218876115">"Zadejte kód PIN"</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 5f0c0ee..a74b9b7 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -267,8 +267,8 @@
<string name="permdesc_clearAppCache" msgid="7740465694193671402">"Tillader, at et program frigør plads på telefonen ved at slette filer i programmets cachemappe. Adgang er normalt meget begrænset til systemprocesser."</string>
<string name="permlab_movePackage" msgid="728454979946503926">"Flyt programressourcer"</string>
<string name="permdesc_movePackage" msgid="6323049291923925277">"Tillader, at et program flytter programressourcer fra interne til eksterne medier og omvendt."</string>
- <!-- outdated translation 4811921703882532070 --> <string name="permlab_readLogs" msgid="6615778543198967614">"læs systemlogfiler"</string>
- <!-- outdated translation 2257937955580475902 --> <string name="permdesc_readLogs" msgid="8896449437464867766">"Tillader, at et program læser fra systemets forskellige logfiler. Dermed kan generelle oplysninger om, hvad du laver med telefonen, registreres, men logfilerne bør ikke indeholde personlige eller private oplysninger."</string>
+ <string name="permlab_readLogs" msgid="6615778543198967614">"læse følsomme logdata"</string>
+ <string name="permdesc_readLogs" msgid="8896449437464867766">"Tillader, at et program læser fra systemets forskellige logfiler. Dermed kan generelle oplysninger om, hvad du laver med telefonen, registreres, også personlige eller private oplysninger."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"læs/skriv til ressourcer ejet af diag"</string>
<string name="permdesc_diagnostic" msgid="3121238373951637049">"Tillader, at et program læser og skriver til alle ressourcer, der ejes af diag-gruppen, som f.eks. flier i /dev. Dette kan muligvis påvirke systemets stabilitet og sikkerhed. Dette bør KUN bruges til hardwarespecifikke diagnosticeringer foretaget af producent eller udbyder."</string>
<string name="permlab_changeComponentState" msgid="79425198834329406">"aktiver eller deaktiver programkomponenter"</string>
@@ -544,14 +544,10 @@
<string name="orgTypeWork" msgid="29268870505363872">"Arbejde"</string>
<string name="orgTypeOther" msgid="3951781131570124082">"Andre"</string>
<string name="orgTypeCustom" msgid="225523415372088322">"Tilpasset"</string>
- <!-- no translation found for sipAddressTypeCustom (2473580593111590945) -->
- <skip />
- <!-- no translation found for sipAddressTypeHome (6093598181069359295) -->
- <skip />
- <!-- no translation found for sipAddressTypeWork (6920725730797099047) -->
- <skip />
- <!-- no translation found for sipAddressTypeOther (4408436162950119849) -->
- <skip />
+ <string name="sipAddressTypeCustom" msgid="2473580593111590945">"Tilpasset"</string>
+ <string name="sipAddressTypeHome" msgid="6093598181069359295">"Hjem"</string>
+ <string name="sipAddressTypeWork" msgid="6920725730797099047">"Arbejde"</string>
+ <string name="sipAddressTypeOther" msgid="4408436162950119849">"Andre"</string>
<string name="contact_status_update_attribution" msgid="5112589886094402795">"via <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
<string name="contact_status_update_attribution_with_date" msgid="5945386376369979909">"<xliff:g id="DATE">%1$s</xliff:g> via <xliff:g id="SOURCE">%2$s</xliff:g>"</string>
<string name="keyguard_password_enter_pin_code" msgid="3731488827218876115">"Indtast PIN-kode"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 539bbe8..2f4013f 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -267,8 +267,8 @@
<string name="permdesc_clearAppCache" msgid="7740465694193671402">"Ermöglicht einer Anwendung, Telefonspeicher durch das Löschen von Dateien im Cache-Verzeichnis der Anwendung freizugeben. Der Zugriff beschränkt sich in der Regel auf Systemprozesse."</string>
<string name="permlab_movePackage" msgid="728454979946503926">"Anwendungsressourcen verschieben"</string>
<string name="permdesc_movePackage" msgid="6323049291923925277">"Ermöglicht einer Anwendung, Anwendungsressourcen von interne auf externe Medien zu verschieben und umgekehrt."</string>
- <!-- outdated translation 4811921703882532070 --> <string name="permlab_readLogs" msgid="6615778543198967614">"System-Protokolldateien lesen"</string>
- <!-- outdated translation 2257937955580475902 --> <string name="permdesc_readLogs" msgid="8896449437464867766">"Ermöglicht einer Anwendung, die verschiedenen Protokolldateien des Systems zu lesen. So können allgemeine Informationen zu den auf Ihrem Telefon durchgeführten Aktionen eingesehen werden, diese sollten jedoch keine persönlichen oder geheimen Daten enthalten."</string>
+ <string name="permlab_readLogs" msgid="6615778543198967614">"Lesen vertraulicher Protokolldaten"</string>
+ <string name="permdesc_readLogs" msgid="8896449437464867766">"Ermöglicht einer Anwendung, die verschiedenen Protokolldateien des Systems zu lesen. So können allgemeine Informationen zu den auf Ihrem Telefon durchgeführten Aktionen eingesehen werden. Diese können persönliche oder geheime Daten enthalten."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"Lese-/Schreibberechtigung für zu Diagnosegruppe gehörige Elemente"</string>
<string name="permdesc_diagnostic" msgid="3121238373951637049">"Ermöglicht einer Anwendung, alle Elemente in der Diagnosegruppe zu lesen und zu bearbeiten, etwa Dateien in \"/dev\". Dies könnte eine potenzielle Gefährdung für die Stabilität und Sicherheit des Systems darstellen und sollte NUR für Hardware-spezifische Diagnosen des Herstellers oder Netzbetreibers verwendet werden."</string>
<string name="permlab_changeComponentState" msgid="79425198834329406">"Anwendungskomponenten aktivieren oder deaktivieren"</string>
@@ -544,14 +544,10 @@
<string name="orgTypeWork" msgid="29268870505363872">"Beruflich"</string>
<string name="orgTypeOther" msgid="3951781131570124082">"Andere"</string>
<string name="orgTypeCustom" msgid="225523415372088322">"Benutzerdefiniert"</string>
- <!-- no translation found for sipAddressTypeCustom (2473580593111590945) -->
- <skip />
- <!-- no translation found for sipAddressTypeHome (6093598181069359295) -->
- <skip />
- <!-- no translation found for sipAddressTypeWork (6920725730797099047) -->
- <skip />
- <!-- no translation found for sipAddressTypeOther (4408436162950119849) -->
- <skip />
+ <string name="sipAddressTypeCustom" msgid="2473580593111590945">"Benutzerdefiniert"</string>
+ <string name="sipAddressTypeHome" msgid="6093598181069359295">"Privat"</string>
+ <string name="sipAddressTypeWork" msgid="6920725730797099047">"Geschäftlich"</string>
+ <string name="sipAddressTypeOther" msgid="4408436162950119849">"Andere"</string>
<string name="contact_status_update_attribution" msgid="5112589886094402795">"über <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
<string name="contact_status_update_attribution_with_date" msgid="5945386376369979909">"<xliff:g id="DATE">%1$s</xliff:g> über <xliff:g id="SOURCE">%2$s</xliff:g>"</string>
<string name="keyguard_password_enter_pin_code" msgid="3731488827218876115">"PIN-Code eingeben"</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index ae51c55..7128ad7 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -267,8 +267,8 @@
<string name="permdesc_clearAppCache" msgid="7740465694193671402">"Επιτρέπει σε μια εφαρμογή να αυξήσει τον ελεύθερο χώρο αποθήκευσης του τηλεφώνου διαγράφοντας αρχεία από τον κατάλογο προσωρινής μνήμης της εφαρμογής. Η πρόσβαση είναι συνήθως πολύ περιορισμένη στη διαδικασία συστήματος."</string>
<string name="permlab_movePackage" msgid="728454979946503926">"Μετακίνηση πόρων εφαρμογής"</string>
<string name="permdesc_movePackage" msgid="6323049291923925277">"Επιτρέπει σε μια εφαρμογή τη μετακίνηση πόρων εφαρμογής από ένα εσωτερικό σε ένα εξωτερικό μέσο και αντίστροφα."</string>
- <!-- outdated translation 4811921703882532070 --> <string name="permlab_readLogs" msgid="6615778543198967614">"ανάγνωση αρχείων καταγραφής συστήματος"</string>
- <!-- outdated translation 2257937955580475902 --> <string name="permdesc_readLogs" msgid="8896449437464867766">"Επιτρέπει σε μια εφαρμογή να αναγνώσει τα αρχεία καταγραφής του συστήματος. Έτσι μπορεί να ανακαλύψει γενικές πληροφορίες σχετικά με τις δραστηριότητές σας στο τηλέφωνο, όμως δεν θα πρέπει να περιέχουν προσωπικές ή ιδιωτικές πληροφορίες."</string>
+ <string name="permlab_readLogs" msgid="6615778543198967614">"ανάγνωση ευαίσθητων δεδομένων αρχείου καταγραφής"</string>
+ <string name="permdesc_readLogs" msgid="8896449437464867766">"Επιτρέπει σε μια εφαρμογή την ανάγνωση των αρχείων καταγραφής του συστήματος. Έτσι, μπορεί να ανακαλύψει γενικές πληροφορίες σχετικά με τις δραστηριότητές σας στο τηλέφωνο, συμπεριλαμβάνοντας πιθανώς και προσωπικές ή ιδιωτικές πληροφορίες."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"ανάγνωση/εγγραφή σε πόρους που ανήκουν στο διαγνωστικό"</string>
<string name="permdesc_diagnostic" msgid="3121238373951637049">"Επιτρέπει σε μια εφαρμογή την ανάγνωση και την εγγραφή σε πόρο που ανήκει στην ομάδα διαγνωστικού (π.χ. αρχεία στον κατάλογο /dev). Αυτό ενδέχεται να επηρεάσει την σταθερότητα και την ασφάλεια του συστήματος. Θα πρέπει να χρησιμοποιείται ΜΟΝΟ για διαγνωστικά υλικού του κατασκευαστή ή του χειριστή."</string>
<string name="permlab_changeComponentState" msgid="79425198834329406">"ενεργοποίηση ή απενεργοποίηση στοιχείων εφαρμογής"</string>
@@ -544,14 +544,10 @@
<string name="orgTypeWork" msgid="29268870505363872">"Εργασία"</string>
<string name="orgTypeOther" msgid="3951781131570124082">"Άλλο"</string>
<string name="orgTypeCustom" msgid="225523415372088322">"Προσαρμοσμένο"</string>
- <!-- no translation found for sipAddressTypeCustom (2473580593111590945) -->
- <skip />
- <!-- no translation found for sipAddressTypeHome (6093598181069359295) -->
- <skip />
- <!-- no translation found for sipAddressTypeWork (6920725730797099047) -->
- <skip />
- <!-- no translation found for sipAddressTypeOther (4408436162950119849) -->
- <skip />
+ <string name="sipAddressTypeCustom" msgid="2473580593111590945">"Προσαρμοσμένο"</string>
+ <string name="sipAddressTypeHome" msgid="6093598181069359295">"Αρχική σελίδα"</string>
+ <string name="sipAddressTypeWork" msgid="6920725730797099047">"Εργασία"</string>
+ <string name="sipAddressTypeOther" msgid="4408436162950119849">"Άλλο"</string>
<string name="contact_status_update_attribution" msgid="5112589886094402795">"μέσω <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
<string name="contact_status_update_attribution_with_date" msgid="5945386376369979909">"<xliff:g id="DATE">%1$s</xliff:g> μέσω <xliff:g id="SOURCE">%2$s</xliff:g>"</string>
<string name="keyguard_password_enter_pin_code" msgid="3731488827218876115">"Πληκτρολογήστε τον κωδικό αριθμό PIN"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index d9d1c9b..406d335 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -267,8 +267,8 @@
<string name="permdesc_clearAppCache" msgid="7740465694193671402">"Admite una aplicación que libera espacio de almacenamiento en el teléfono al eliminar archivos del directorio de memoria caché de la aplicación. En general, el acceso es muy restringido para el proceso del sistema."</string>
<string name="permlab_movePackage" msgid="728454979946503926">"Mover recursos de la aplicación"</string>
<string name="permdesc_movePackage" msgid="6323049291923925277">"Permite a una aplicación mover recursos de aplicación de medios internos a externos y viceversa."</string>
- <!-- outdated translation 4811921703882532070 --> <string name="permlab_readLogs" msgid="6615778543198967614">"leer archivos de registro del sistema"</string>
- <!-- outdated translation 2257937955580475902 --> <string name="permdesc_readLogs" msgid="8896449437464867766">"Admite una aplicación que lee diversos archivos de registro del sistema. Esto le permite descubrir información general sobre lo que haces con el teléfono, pero no debe contener información personal ni privada."</string>
+ <string name="permlab_readLogs" msgid="6615778543198967614">"lee los datos confidenciales del registro"</string>
+ <string name="permdesc_readLogs" msgid="8896449437464867766">"Admite una aplicación que lee diversos archivos de registro del sistema. Esto te permite descubrir información general acerca de lo que haces con el teléfono, y puede potencialmente incluir información personal o privada."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"leer y escribir a recursos dentro del grupo de diagnóstico"</string>
<string name="permdesc_diagnostic" msgid="3121238373951637049">"Admite una aplicación que lee y escribe a cualquier recurso dentro del grupo de diagnóstico; por ejemplo, archivos con /dev. Esto puede afectar potencialmente la estabilidad y la seguridad del sistema. Debe utilizarlo SÓLO el fabricante o el operador en los diagnósticos específicos del hardware."</string>
<string name="permlab_changeComponentState" msgid="79425198834329406">"activar o desactivar componentes de la aplicación"</string>
@@ -544,14 +544,10 @@
<string name="orgTypeWork" msgid="29268870505363872">"Trabajo"</string>
<string name="orgTypeOther" msgid="3951781131570124082">"Otro"</string>
<string name="orgTypeCustom" msgid="225523415372088322">"Personalizado"</string>
- <!-- no translation found for sipAddressTypeCustom (2473580593111590945) -->
- <skip />
- <!-- no translation found for sipAddressTypeHome (6093598181069359295) -->
- <skip />
- <!-- no translation found for sipAddressTypeWork (6920725730797099047) -->
- <skip />
- <!-- no translation found for sipAddressTypeOther (4408436162950119849) -->
- <skip />
+ <string name="sipAddressTypeCustom" msgid="2473580593111590945">"Personalizado"</string>
+ <string name="sipAddressTypeHome" msgid="6093598181069359295">"Página principal"</string>
+ <string name="sipAddressTypeWork" msgid="6920725730797099047">"Trabajo"</string>
+ <string name="sipAddressTypeOther" msgid="4408436162950119849">"Otro"</string>
<string name="contact_status_update_attribution" msgid="5112589886094402795">"a través de <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
<string name="contact_status_update_attribution_with_date" msgid="5945386376369979909">"<xliff:g id="DATE">%1$s</xliff:g> a través de <xliff:g id="SOURCE">%2$s</xliff:g>"</string>
<string name="keyguard_password_enter_pin_code" msgid="3731488827218876115">"Ingresar el código de PIN"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 0cb4bab..1cf971a 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -267,8 +267,8 @@
<string name="permdesc_clearAppCache" msgid="7740465694193671402">"Permite que una aplicación libere espacio de almacenamiento en el teléfono mediante la eliminación de archivos en el directorio de caché de la aplicación. El acceso al proceso del sistema suele estar muy restringido."</string>
<string name="permlab_movePackage" msgid="728454979946503926">"Mover recursos de aplicaciones"</string>
<string name="permdesc_movePackage" msgid="6323049291923925277">"Permite que una aplicación mueva los recursos de aplicaciones de un medio interno a otro externo y viceversa."</string>
- <!-- outdated translation 4811921703882532070 --> <string name="permlab_readLogs" msgid="6615778543198967614">"leer archivos de registro del sistema"</string>
- <!-- outdated translation 2257937955580475902 --> <string name="permdesc_readLogs" msgid="8896449437464867766">"Permite que una aplicación lea los distintos archivos de registro del sistema. Con este permiso, la aplicación puede ver información general sobre las acciones que realiza el usuario con el teléfono, pero los registros no deberían contener información personal o privada."</string>
+ <string name="permlab_readLogs" msgid="6615778543198967614">"leer datos de registro personales"</string>
+ <string name="permdesc_readLogs" msgid="8896449437464867766">"Permite que una aplicación lea distintos archivos de registro del sistema. Con este permiso, la aplicación puede ver información general sobre las acciones que realizas con el teléfono, que puede incluir datos personales o privados."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"leer/escribir en los recursos propiedad del grupo de diagnóstico"</string>
<string name="permdesc_diagnostic" msgid="3121238373951637049">"Permite que una aplicación lea y escriba en cualquier recurso propiedad del grupo de diagnóstico como, por ejemplo, archivos in/dev. Este permiso podría afectar a la seguridad y estabilidad del sistema. SÓLO se debe utilizar para diagnósticos específicos de hardware realizados por el fabricante o el operador."</string>
<string name="permlab_changeComponentState" msgid="79425198834329406">"habilitar o inhabilitar componentes de la aplicación"</string>
@@ -544,14 +544,10 @@
<string name="orgTypeWork" msgid="29268870505363872">"Trabajo"</string>
<string name="orgTypeOther" msgid="3951781131570124082">"Otra"</string>
<string name="orgTypeCustom" msgid="225523415372088322">"Personalizada"</string>
- <!-- no translation found for sipAddressTypeCustom (2473580593111590945) -->
- <skip />
- <!-- no translation found for sipAddressTypeHome (6093598181069359295) -->
- <skip />
- <!-- no translation found for sipAddressTypeWork (6920725730797099047) -->
- <skip />
- <!-- no translation found for sipAddressTypeOther (4408436162950119849) -->
- <skip />
+ <string name="sipAddressTypeCustom" msgid="2473580593111590945">"Personalizada"</string>
+ <string name="sipAddressTypeHome" msgid="6093598181069359295">"Casa"</string>
+ <string name="sipAddressTypeWork" msgid="6920725730797099047">"Trabajo"</string>
+ <string name="sipAddressTypeOther" msgid="4408436162950119849">"Otro"</string>
<string name="contact_status_update_attribution" msgid="5112589886094402795">"a través de <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
<string name="contact_status_update_attribution_with_date" msgid="5945386376369979909">"<xliff:g id="DATE">%1$s</xliff:g> a través de <xliff:g id="SOURCE">%2$s</xliff:g>"</string>
<string name="keyguard_password_enter_pin_code" msgid="3731488827218876115">"Introduce el código PIN"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 5f3427b..3c567f4 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -267,8 +267,8 @@
<string name="permdesc_clearAppCache" msgid="7740465694193671402">"Permet à une application de libérer de l\'espace dans la mémoire du téléphone en supprimant des fichiers du répertoire du cache des applications. Cet accès est en général limité aux processus système."</string>
<string name="permlab_movePackage" msgid="728454979946503926">"Déplacer des ressources d\'application"</string>
<string name="permdesc_movePackage" msgid="6323049291923925277">"Autorise l\'application à déplacer des ressources d\'application d\'un support interne à un support externe et inversement."</string>
- <!-- outdated translation 4811921703882532070 --> <string name="permlab_readLogs" msgid="6615778543198967614">"Lecture des fichiers journaux du système"</string>
- <!-- outdated translation 2257937955580475902 --> <string name="permdesc_readLogs" msgid="8896449437464867766">"Permet à une application de lire les différents fichiers journaux du système afin d\'obtenir des informations générales sur la façon dont vous utilisez votre téléphone, sans pour autant récupérer des informations d\'ordre personnel ou privé."</string>
+ <string name="permlab_readLogs" msgid="6615778543198967614">"lire les données des journaux à caractère confidentiel"</string>
+ <string name="permdesc_readLogs" msgid="8896449437464867766">"Permet à une application de lire les différents fichiers journaux du système afin d\'obtenir des informations générales sur la façon dont vous utilisez votre téléphone (celles-ci peuvent éventuellement inclure des informations d\'ordre personnel ou privé)."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"Lecture/écriture dans les ressources appartenant aux diagnostics"</string>
<string name="permdesc_diagnostic" msgid="3121238373951637049">"Permet à une application de lire et d\'éditer toute ressource appartenant au groupe de diagnostics (par exemple, les fichiers in/dev). Ceci peut affecter la stabilité et la sécurité du système. Cette fonctionnalité est UNIQUEMENT réservée aux diagnostics matériels effectués par le fabricant ou l\'opérateur."</string>
<string name="permlab_changeComponentState" msgid="79425198834329406">"Activer ou désactiver des éléments de l\'application"</string>
@@ -544,14 +544,10 @@
<string name="orgTypeWork" msgid="29268870505363872">"Bureau"</string>
<string name="orgTypeOther" msgid="3951781131570124082">"Autre"</string>
<string name="orgTypeCustom" msgid="225523415372088322">"Personnalisé"</string>
- <!-- no translation found for sipAddressTypeCustom (2473580593111590945) -->
- <skip />
- <!-- no translation found for sipAddressTypeHome (6093598181069359295) -->
- <skip />
- <!-- no translation found for sipAddressTypeWork (6920725730797099047) -->
- <skip />
- <!-- no translation found for sipAddressTypeOther (4408436162950119849) -->
- <skip />
+ <string name="sipAddressTypeCustom" msgid="2473580593111590945">"Personnalisée"</string>
+ <string name="sipAddressTypeHome" msgid="6093598181069359295">"Accueil"</string>
+ <string name="sipAddressTypeWork" msgid="6920725730797099047">"Professionnelle"</string>
+ <string name="sipAddressTypeOther" msgid="4408436162950119849">"Autre"</string>
<string name="contact_status_update_attribution" msgid="5112589886094402795">"via <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
<string name="contact_status_update_attribution_with_date" msgid="5945386376369979909">"<xliff:g id="DATE">%1$s</xliff:g> via <xliff:g id="SOURCE">%2$s</xliff:g>"</string>
<string name="keyguard_password_enter_pin_code" msgid="3731488827218876115">"Saisissez le code PIN"</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 865b0e8..4e8d19a 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -267,8 +267,8 @@
<string name="permdesc_clearAppCache" msgid="7740465694193671402">"Consente a un\'applicazione di liberare spazio sul telefono eliminando file nella directory della cache dell\'applicazione. L\'accesso è generalmente limitato a processi di sistema."</string>
<string name="permlab_movePackage" msgid="728454979946503926">"Spostare risorse dell\'applicazione"</string>
<string name="permdesc_movePackage" msgid="6323049291923925277">"Consente a un\'applicazione di spostare risorse applicative da supporti interni a esterni e viceversa."</string>
- <!-- outdated translation 4811921703882532070 --> <string name="permlab_readLogs" msgid="6615778543198967614">"lettura file di registro sistema"</string>
- <!-- outdated translation 2257937955580475902 --> <string name="permdesc_readLogs" msgid="8896449437464867766">"Consente a un\'applicazione di leggere vari file di registro del sistema per trovare informazioni generali sulle operazioni effettuate con il telefono. Tali file non dovrebbero contenere informazioni personali o riservate."</string>
+ <string name="permlab_readLogs" msgid="6615778543198967614">"Lettura dati di registro sensibili"</string>
+ <string name="permdesc_readLogs" msgid="8896449437464867766">"Consente a un\'applicazione di leggere vari file di registro del sistema per trovare informazioni generali sulle operazioni effettuate con il telefono. Tali file potrebbero contenere informazioni personali o riservate."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"lettura/scrittura risorse di proprietà di diag"</string>
<string name="permdesc_diagnostic" msgid="3121238373951637049">"Consente a un\'applicazione di leggere le risorse del gruppo diag e scrivere a esse, per esempio i file in /dev. Questa capacità potrebbe influire sulla stabilità e sicurezza del sistema. Dovrebbe essere utilizzata SOLTANTO per diagnostiche specifiche dell\'hardware effettuate dal produttore o dall\'operatore."</string>
<string name="permlab_changeComponentState" msgid="79425198834329406">"attivazione/disattivazione componenti applicazioni"</string>
@@ -544,14 +544,10 @@
<string name="orgTypeWork" msgid="29268870505363872">"Lavoro"</string>
<string name="orgTypeOther" msgid="3951781131570124082">"Altro"</string>
<string name="orgTypeCustom" msgid="225523415372088322">"Personalizzato"</string>
- <!-- no translation found for sipAddressTypeCustom (2473580593111590945) -->
- <skip />
- <!-- no translation found for sipAddressTypeHome (6093598181069359295) -->
- <skip />
- <!-- no translation found for sipAddressTypeWork (6920725730797099047) -->
- <skip />
- <!-- no translation found for sipAddressTypeOther (4408436162950119849) -->
- <skip />
+ <string name="sipAddressTypeCustom" msgid="2473580593111590945">"Personalizzato"</string>
+ <string name="sipAddressTypeHome" msgid="6093598181069359295">"Casa"</string>
+ <string name="sipAddressTypeWork" msgid="6920725730797099047">"Lavoro"</string>
+ <string name="sipAddressTypeOther" msgid="4408436162950119849">"Altro"</string>
<string name="contact_status_update_attribution" msgid="5112589886094402795">"tramite <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
<string name="contact_status_update_attribution_with_date" msgid="5945386376369979909">"<xliff:g id="DATE">%1$s</xliff:g> tramite <xliff:g id="SOURCE">%2$s</xliff:g>"</string>
<string name="keyguard_password_enter_pin_code" msgid="3731488827218876115">"Inserisci il PIN"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 8b0301e..a4d07a8 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -267,8 +267,8 @@
<string name="permdesc_clearAppCache" msgid="7740465694193671402">"アプリケーションのキャッシュディレクトリからファイルを削除して携帯電話のメモリを解放することをアプリケーションに許可します。通常、アクセスはシステムプロセスのみに制限されます。"</string>
<string name="permlab_movePackage" msgid="728454979946503926">"アプリケーションリソースの移動"</string>
<string name="permdesc_movePackage" msgid="6323049291923925277">"内部と外部のメディア間でのアプリケーションリソースの移動をアプリケーションに許可します。"</string>
- <!-- outdated translation 4811921703882532070 --> <string name="permlab_readLogs" msgid="6615778543198967614">"システムログファイルの読み取り"</string>
- <!-- outdated translation 2257937955580475902 --> <string name="permdesc_readLogs" msgid="8896449437464867766">"システムのさまざまなログファイルの読み取りをアプリケーションに許可します。これにより携帯電話の使用状況に関する全般情報が取得されますが、個人情報や非公開情報が含まれることはありません。"</string>
+ <string name="permlab_readLogs" msgid="6615778543198967614">"機密ログデータの読み取り"</string>
+ <string name="permdesc_readLogs" msgid="8896449437464867766">"システムの各種ログファイルの読み取りをアプリケーションに許可します。許可すると端末の使用状況に関する全般的な情報が読み取られます。この情報には個人情報や機密情報が含まれる場合があります。"</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"diagが所有するリソースの読み書き"</string>
<string name="permdesc_diagnostic" msgid="3121238373951637049">"diagグループが所有するリソース(例:/dev内のファイル)への読み書きをアプリケーションに許可します。システムの安定性とセキュリティに影響する恐れがあります。メーカー/オペレーターによるハードウェア固有の診断以外には使用しないでください。"</string>
<string name="permlab_changeComponentState" msgid="79425198834329406">"アプリケーションのコンポーネントを有効/無効にする"</string>
@@ -544,14 +544,10 @@
<string name="orgTypeWork" msgid="29268870505363872">"勤務先"</string>
<string name="orgTypeOther" msgid="3951781131570124082">"その他"</string>
<string name="orgTypeCustom" msgid="225523415372088322">"カスタム"</string>
- <!-- no translation found for sipAddressTypeCustom (2473580593111590945) -->
- <skip />
- <!-- no translation found for sipAddressTypeHome (6093598181069359295) -->
- <skip />
- <!-- no translation found for sipAddressTypeWork (6920725730797099047) -->
- <skip />
- <!-- no translation found for sipAddressTypeOther (4408436162950119849) -->
- <skip />
+ <string name="sipAddressTypeCustom" msgid="2473580593111590945">"カスタム"</string>
+ <string name="sipAddressTypeHome" msgid="6093598181069359295">"自宅"</string>
+ <string name="sipAddressTypeWork" msgid="6920725730797099047">"勤務先"</string>
+ <string name="sipAddressTypeOther" msgid="4408436162950119849">"その他"</string>
<string name="contact_status_update_attribution" msgid="5112589886094402795">"<xliff:g id="SOURCE">%1$s</xliff:g>経由"</string>
<string name="contact_status_update_attribution_with_date" msgid="5945386376369979909">"<xliff:g id="DATE">%1$s</xliff:g>、更新元: <xliff:g id="SOURCE">%2$s</xliff:g>"</string>
<string name="keyguard_password_enter_pin_code" msgid="3731488827218876115">"PINコードを入力"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 75d0da1..56495d6 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -267,8 +267,8 @@
<string name="permdesc_clearAppCache" msgid="7740465694193671402">"애플리케이션이 애플리케이션 캐시 디렉토리에 있는 파일을 삭제하여 휴대전화의 저장공간을 늘릴 수 있도록 합니다. 액세스는 일반적으로 시스템 프로세스로 제한됩니다."</string>
<string name="permlab_movePackage" msgid="728454979946503926">"애플리케이션 리소스 이동"</string>
<string name="permdesc_movePackage" msgid="6323049291923925277">"애플리케이션이 애플리케이션 리소스를 내부에서 외부 미디어로 또는 그 반대로 이동할 수 있도록 합니다."</string>
- <!-- outdated translation 4811921703882532070 --> <string name="permlab_readLogs" msgid="6615778543198967614">"시스템 로그 파일 읽기"</string>
- <!-- outdated translation 2257937955580475902 --> <string name="permdesc_readLogs" msgid="8896449437464867766">"애플리케이션이 시스템의 다양한 로그 파일을 읽을 수 있도록 합니다. 이 경우 애플리케이션은 사용자가 휴대전화로 수행하는 작업에 대한 일반적인 정보를 검색할 수 있습니다. 하지만 로그 파일에 어떠한 개인정보도 포함되어서는 안 됩니다."</string>
+ <string name="permlab_readLogs" msgid="6615778543198967614">"중요한 로그 데이터 읽기"</string>
+ <string name="permdesc_readLogs" msgid="8896449437464867766">"애플리케이션이 시스템의 다양한 로그 파일을 읽을 수 있도록 합니다. 이렇게 되면 애플리케이션은 개인정보 또는 비공개 정보를 포함하여 휴대전화로 수행하는 작업에 대한 일반적인 정보를 검색할 수 있습니다."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"진단 그룹 소유의 리소스 읽기/쓰기"</string>
<string name="permdesc_diagnostic" msgid="3121238373951637049">"애플리케이션이 진단 그룹 소유의 리소스(예: /dev에 있는 파일)를 읽고 쓸 수 있도록 합니다. 이 기능은 시스템 안정성 및 보안에 영향을 미칠 수 있으므로 제조업체 또는 사업자가 하드웨어 관련 진단을 수행하는 경우에만 사용해야 합니다."</string>
<string name="permlab_changeComponentState" msgid="79425198834329406">"애플리케이션 구성 요소 사용 또는 사용 안함"</string>
@@ -544,14 +544,10 @@
<string name="orgTypeWork" msgid="29268870505363872">"직장"</string>
<string name="orgTypeOther" msgid="3951781131570124082">"기타"</string>
<string name="orgTypeCustom" msgid="225523415372088322">"맞춤설정"</string>
- <!-- no translation found for sipAddressTypeCustom (2473580593111590945) -->
- <skip />
- <!-- no translation found for sipAddressTypeHome (6093598181069359295) -->
- <skip />
- <!-- no translation found for sipAddressTypeWork (6920725730797099047) -->
- <skip />
- <!-- no translation found for sipAddressTypeOther (4408436162950119849) -->
- <skip />
+ <string name="sipAddressTypeCustom" msgid="2473580593111590945">"맞춤설정"</string>
+ <string name="sipAddressTypeHome" msgid="6093598181069359295">"홈"</string>
+ <string name="sipAddressTypeWork" msgid="6920725730797099047">"직장"</string>
+ <string name="sipAddressTypeOther" msgid="4408436162950119849">"기타"</string>
<string name="contact_status_update_attribution" msgid="5112589886094402795">"<xliff:g id="SOURCE">%1$s</xliff:g>을(를) 통해"</string>
<string name="contact_status_update_attribution_with_date" msgid="5945386376369979909">"<xliff:g id="DATE">%1$s</xliff:g>(<xliff:g id="SOURCE">%2$s</xliff:g> 사용)"</string>
<string name="keyguard_password_enter_pin_code" msgid="3731488827218876115">"PIN 코드 입력"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index 70ee877..375e592 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -267,8 +267,8 @@
<string name="permdesc_clearAppCache" msgid="7740465694193671402">"Lar applikasjonen frigjøre lagringsplass ved å slette filer i applikasjoners hurtigbufferkatalog. Tilgangen er vanligvis sterkt begrenset, til systemprosesser."</string>
<string name="permlab_movePackage" msgid="728454979946503926">"Flytter programressurser"</string>
<string name="permdesc_movePackage" msgid="6323049291923925277">"Gir et program tillatelse til å flytte programressurser fra interne til eksterne medier og omvendt."</string>
- <!-- outdated translation 4811921703882532070 --> <string name="permlab_readLogs" msgid="6615778543198967614">"lese systemets loggfiler"</string>
- <!-- outdated translation 2257937955580475902 --> <string name="permdesc_readLogs" msgid="8896449437464867766">"Lar applikasjonen lese fra diverse loggfiler på systemet. Disse inneholder generell informasjon om hva som gjøres med telefonen, men skal ikke inneholde personlig eller privat informasjon."</string>
+ <string name="permlab_readLogs" msgid="6615778543198967614">"les sensitive loggdata"</string>
+ <string name="permdesc_readLogs" msgid="8896449437464867766">"Lar programmet lese fra diverse loggfiler på systemet. Disse inneholder generell informasjon om hva som gjøres med telefonen, og kan inneholde personlig eller privat informasjon."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"lese/skrive ressurser eid av diag"</string>
<string name="permdesc_diagnostic" msgid="3121238373951637049">"Lar applikasjonen lese og skrive enhver ressurs eid av gruppen diag; for eksempel, filer i /dev. Dette kan potensielt påvirke systemets sikkerhet og stabilitet. Dette bør KUN brukes for maskinvarespesifikke diagnoseverktøy laget av operatøren eller produsenten."</string>
<string name="permlab_changeComponentState" msgid="79425198834329406">"aktivere eller deaktigere applikasjonskomponenter"</string>
@@ -544,14 +544,10 @@
<string name="orgTypeWork" msgid="29268870505363872">"Arbeid"</string>
<string name="orgTypeOther" msgid="3951781131570124082">"Annen"</string>
<string name="orgTypeCustom" msgid="225523415372088322">"Egendefinert"</string>
- <!-- no translation found for sipAddressTypeCustom (2473580593111590945) -->
- <skip />
- <!-- no translation found for sipAddressTypeHome (6093598181069359295) -->
- <skip />
- <!-- no translation found for sipAddressTypeWork (6920725730797099047) -->
- <skip />
- <!-- no translation found for sipAddressTypeOther (4408436162950119849) -->
- <skip />
+ <string name="sipAddressTypeCustom" msgid="2473580593111590945">"Egendefinert"</string>
+ <string name="sipAddressTypeHome" msgid="6093598181069359295">"Startside"</string>
+ <string name="sipAddressTypeWork" msgid="6920725730797099047">"Arbeid"</string>
+ <string name="sipAddressTypeOther" msgid="4408436162950119849">"Annen"</string>
<string name="contact_status_update_attribution" msgid="5112589886094402795">"via <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
<string name="contact_status_update_attribution_with_date" msgid="5945386376369979909">"<xliff:g id="DATE">%1$s</xliff:g> via <xliff:g id="SOURCE">%2$s</xliff:g>"</string>
<string name="keyguard_password_enter_pin_code" msgid="3731488827218876115">"Skriv inn PIN-kode:"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 2d07166..2dedd7b 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -267,8 +267,8 @@
<string name="permdesc_clearAppCache" msgid="7740465694193671402">"Hiermee kan een toepassing opslagruimte op de telefoon vrij maken door bestanden te verwijderen uit de cachemap van de toepassing. De toegang is doorgaans beperkt tot het systeemproces."</string>
<string name="permlab_movePackage" msgid="728454979946503926">"Toepassingsbronnen verplaatsen"</string>
<string name="permdesc_movePackage" msgid="6323049291923925277">"Een toepassing toestaan toepassingsbronnen te verplaatsen van interne naar externe media en omgekeerd."</string>
- <!-- outdated translation 4811921703882532070 --> <string name="permlab_readLogs" msgid="6615778543198967614">"systeemlogbestanden lezen"</string>
- <!-- outdated translation 2257937955580475902 --> <string name="permdesc_readLogs" msgid="8896449437464867766">"Hiermee kan een toepassing de verschillende logbestanden van het systeem lezen. De toepassing kan op deze manier algemene informatie achterhalen over uw telefoongebruik. Hierin is geen persoonlijke of privé-informatie opgenomen."</string>
+ <string name="permlab_readLogs" msgid="6615778543198967614">"gevoelige logbestandsgegevens lezen"</string>
+ <string name="permdesc_readLogs" msgid="8896449437464867766">"Hiermee kan een toepassing de verschillende logbestanden van het systeem lezen. De toepassing kan op deze manier algemene informatie achterhalen over uw telefoongebruik, mogelijk inclusief persoonlijke of privé-informatie."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"lezen/schrijven naar bronnen van diag"</string>
<string name="permdesc_diagnostic" msgid="3121238373951637049">"Hiermee kan een toepassing lezen en schrijven naar elke bron die hoort bij de diagnostische groep, zoals bestanden in /dev. Hierdoor kan de systeemstabiliteit en -veiligheid worden beïnvloed. Dit mag ALLEEN worden gebruikt voor hardwarespecifieke diagnostiek door de fabrikant of operator."</string>
<string name="permlab_changeComponentState" msgid="79425198834329406">"toepassingscomponenten in- of uitschakelen"</string>
@@ -544,14 +544,10 @@
<string name="orgTypeWork" msgid="29268870505363872">"Werk"</string>
<string name="orgTypeOther" msgid="3951781131570124082">"Overig"</string>
<string name="orgTypeCustom" msgid="225523415372088322">"Aangepast"</string>
- <!-- no translation found for sipAddressTypeCustom (2473580593111590945) -->
- <skip />
- <!-- no translation found for sipAddressTypeHome (6093598181069359295) -->
- <skip />
- <!-- no translation found for sipAddressTypeWork (6920725730797099047) -->
- <skip />
- <!-- no translation found for sipAddressTypeOther (4408436162950119849) -->
- <skip />
+ <string name="sipAddressTypeCustom" msgid="2473580593111590945">"Aangepast"</string>
+ <string name="sipAddressTypeHome" msgid="6093598181069359295">"Startpagina"</string>
+ <string name="sipAddressTypeWork" msgid="6920725730797099047">"Werk"</string>
+ <string name="sipAddressTypeOther" msgid="4408436162950119849">"Overig"</string>
<string name="contact_status_update_attribution" msgid="5112589886094402795">"via <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
<string name="contact_status_update_attribution_with_date" msgid="5945386376369979909">"<xliff:g id="DATE">%1$s</xliff:g> via <xliff:g id="SOURCE">%2$s</xliff:g>"</string>
<string name="keyguard_password_enter_pin_code" msgid="3731488827218876115">"PIN-code invoeren"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 7604c61..4e5256f 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -267,8 +267,8 @@
<string name="permdesc_clearAppCache" msgid="7740465694193671402">"Pozwala aplikacji na zwalnianie pamięci telefonu przez usuwanie plików z katalogu pamięci podręcznej aplikacji. Dostęp jest bardzo ograniczony, z reguły do procesów systemu."</string>
<string name="permlab_movePackage" msgid="728454979946503926">"Przenoszenie zasobów aplikacji"</string>
<string name="permdesc_movePackage" msgid="6323049291923925277">"Zezwala aplikacji na przeniesienie zasobów aplikacji z nośnika wewnętrznego na zewnętrzny i odwrotnie."</string>
- <!-- outdated translation 4811921703882532070 --> <string name="permlab_readLogs" msgid="6615778543198967614">"czytanie plików dziennika systemu"</string>
- <!-- outdated translation 2257937955580475902 --> <string name="permdesc_readLogs" msgid="8896449437464867766">"Umożliwia aplikacji czytanie różnych plików dziennika systemowego. Pozwala to na uzyskanie ogólnych informacji o czynnościach wykonywanych w telefonie, ale bez ujawniania danych osobowych lub osobistych informacji."</string>
+ <string name="permlab_readLogs" msgid="6615778543198967614">"odczyt wrażliwych danych dziennika"</string>
+ <string name="permdesc_readLogs" msgid="8896449437464867766">"Umożliwia aplikacjom odczyt z różnych plików dzienników systemowych. Pozwala to poznać ogólne informacje na temat korzystania z telefonu, co potencjalnie może obejmować również informacje prywatne lub osobiste."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"czytanie/zapisywanie w zasobach należących do diagnostyki"</string>
<string name="permdesc_diagnostic" msgid="3121238373951637049">"Pozwala aplikacji na czytanie i zapisywanie we wszystkich zasobach posiadanych przez diagnozowaną grupę, jak na przykład pliki w katalogu /dev. Może to potencjalnie wpłynąć na stabilność i bezpieczeństwo systemu. Powinno być wykorzystywane TYLKO w celach diagnozowania sprzętu przez producenta lub operatora."</string>
<string name="permlab_changeComponentState" msgid="79425198834329406">"włączanie lub wyłączanie składników aplikacji"</string>
@@ -544,14 +544,10 @@
<string name="orgTypeWork" msgid="29268870505363872">"Służbowy"</string>
<string name="orgTypeOther" msgid="3951781131570124082">"Inny"</string>
<string name="orgTypeCustom" msgid="225523415372088322">"Niestandardowy"</string>
- <!-- no translation found for sipAddressTypeCustom (2473580593111590945) -->
- <skip />
- <!-- no translation found for sipAddressTypeHome (6093598181069359295) -->
- <skip />
- <!-- no translation found for sipAddressTypeWork (6920725730797099047) -->
- <skip />
- <!-- no translation found for sipAddressTypeOther (4408436162950119849) -->
- <skip />
+ <string name="sipAddressTypeCustom" msgid="2473580593111590945">"Niestandardowy"</string>
+ <string name="sipAddressTypeHome" msgid="6093598181069359295">"Domowy"</string>
+ <string name="sipAddressTypeWork" msgid="6920725730797099047">"Służbowy"</string>
+ <string name="sipAddressTypeOther" msgid="4408436162950119849">"Inny"</string>
<string name="contact_status_update_attribution" msgid="5112589886094402795">"przez <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
<string name="contact_status_update_attribution_with_date" msgid="5945386376369979909">"<xliff:g id="DATE">%1$s</xliff:g> przez <xliff:g id="SOURCE">%2$s</xliff:g>"</string>
<string name="keyguard_password_enter_pin_code" msgid="3731488827218876115">"Wprowadź kod PIN"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 892aefd..55fdd18 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -267,8 +267,8 @@
<string name="permdesc_clearAppCache" msgid="7740465694193671402">"Permite a uma aplicação libertar espaço de armazenamento no telefone eliminando ficheiros no directório da cache da aplicação. Geralmente, o acesso é muito limitado para processamento do sistema."</string>
<string name="permlab_movePackage" msgid="728454979946503926">"Mover recursos de aplicações"</string>
<string name="permdesc_movePackage" msgid="6323049291923925277">"Permite que uma aplicação mova recursos de aplicações de meios internos para meios externos e vice-versa."</string>
- <!-- outdated translation 4811921703882532070 --> <string name="permlab_readLogs" msgid="6615778543198967614">"ler ficheiros de registo do sistema"</string>
- <!-- outdated translation 2257937955580475902 --> <string name="permdesc_readLogs" msgid="8896449437464867766">"Permite a uma aplicação ler a partir dos diversos ficheiros de registo do sistema. Isto permite descobrir informações gerais sobre a forma como o utilizador usa o telefone, mas estas não devem conter quaisquer dados pessoais ou privados."</string>
+ <string name="permlab_readLogs" msgid="6615778543198967614">"ler dados sensíveis de registo"</string>
+ <string name="permdesc_readLogs" msgid="8896449437464867766">"Permite a uma aplicação ler a partir dos diversos ficheiros de registo do sistema. Isto permite descobrir informações gerais sobre a forma como o utilizador usa o telefone, podendo, inclusive, incluir dados pessoais ou privados."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"ler/escrever em recursos propriedade de diag"</string>
<string name="permdesc_diagnostic" msgid="3121238373951637049">"Permite a uma aplicação ler e escrever em qualquer recurso que seja propriedade do grupo diag. Por exemplo, ficheiros em /dev. Isto pode afectar potencialmente a estabilidade e a segurança do sistema e deve ser utilizado APENAS para diagnósticos específicos do hardware pelo fabricante ou pelo operador."</string>
<string name="permlab_changeComponentState" msgid="79425198834329406">"activar ou desactivar componentes da aplicação"</string>
@@ -544,14 +544,10 @@
<string name="orgTypeWork" msgid="29268870505363872">"Emprego"</string>
<string name="orgTypeOther" msgid="3951781131570124082">"Outro"</string>
<string name="orgTypeCustom" msgid="225523415372088322">"Personalizado"</string>
- <!-- no translation found for sipAddressTypeCustom (2473580593111590945) -->
- <skip />
- <!-- no translation found for sipAddressTypeHome (6093598181069359295) -->
- <skip />
- <!-- no translation found for sipAddressTypeWork (6920725730797099047) -->
- <skip />
- <!-- no translation found for sipAddressTypeOther (4408436162950119849) -->
- <skip />
+ <string name="sipAddressTypeCustom" msgid="2473580593111590945">"Personalizado"</string>
+ <string name="sipAddressTypeHome" msgid="6093598181069359295">"Página inicial"</string>
+ <string name="sipAddressTypeWork" msgid="6920725730797099047">"Emprego"</string>
+ <string name="sipAddressTypeOther" msgid="4408436162950119849">"Outro"</string>
<string name="contact_status_update_attribution" msgid="5112589886094402795">"através do <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
<string name="contact_status_update_attribution_with_date" msgid="5945386376369979909">"<xliff:g id="DATE">%1$s</xliff:g> através de <xliff:g id="SOURCE">%2$s</xliff:g>"</string>
<string name="keyguard_password_enter_pin_code" msgid="3731488827218876115">"Introduzir código PIN"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 4c18677..d5e1ca0 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -267,8 +267,8 @@
<string name="permdesc_clearAppCache" msgid="7740465694193671402">"Permite que um aplicativo libere o espaço de armazenamento do telefone excluindo arquivos no diretório de cache do aplicativo. O acesso é normalmente muito restrito para o processo do sistema."</string>
<string name="permlab_movePackage" msgid="728454979946503926">"Mover recursos do aplicativo"</string>
<string name="permdesc_movePackage" msgid="6323049291923925277">"Permite que um aplicativo mova os recursos do aplicativo da mídia interna para a externa e vice-versa."</string>
- <!-- outdated translation 4811921703882532070 --> <string name="permlab_readLogs" msgid="6615778543198967614">"ler arquivos de registro do sistema"</string>
- <!-- outdated translation 2257937955580475902 --> <string name="permdesc_readLogs" msgid="8896449437464867766">"Permite que um aplicativo leia os diversos arquivos de registro do sistema. Isso permite que ele descubra informações gerais sobre o que você está fazendo com o telefone, porém esses arquivos não devem conter informações pessoais ou privadas."</string>
+ <string name="permlab_readLogs" msgid="6615778543198967614">"ler dados de registro de informações confidenciais"</string>
+ <string name="permdesc_readLogs" msgid="8896449437464867766">"Permite que um aplicativo leia os diversos arquivos de registro do sistema. Isso permite que ele descubra informações gerais sobre o que você está fazendo com o telefone, inclusive possíveis informações pessoais ou privadas."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"ler/gravar em recursos pertencentes ao diag"</string>
<string name="permdesc_diagnostic" msgid="3121238373951637049">"Permite que um aplicativo leia e grave em qualquer recurso que pertença ao grupo de diagnósticos; por exemplo, arquivos em /dev. Isso possivelmente pode afetar a estabilidade e a segurança do sistema. Isso deve ser usado APENAS para diagnósticos específicos do hardware realizados pelo fabricante ou pelo operador."</string>
<string name="permlab_changeComponentState" msgid="79425198834329406">"ativar ou desativar os componentes do aplicativo"</string>
@@ -544,14 +544,10 @@
<string name="orgTypeWork" msgid="29268870505363872">"Comercial"</string>
<string name="orgTypeOther" msgid="3951781131570124082">"Outros"</string>
<string name="orgTypeCustom" msgid="225523415372088322">"Personalizado"</string>
- <!-- no translation found for sipAddressTypeCustom (2473580593111590945) -->
- <skip />
- <!-- no translation found for sipAddressTypeHome (6093598181069359295) -->
- <skip />
- <!-- no translation found for sipAddressTypeWork (6920725730797099047) -->
- <skip />
- <!-- no translation found for sipAddressTypeOther (4408436162950119849) -->
- <skip />
+ <string name="sipAddressTypeCustom" msgid="2473580593111590945">"Personalizado"</string>
+ <string name="sipAddressTypeHome" msgid="6093598181069359295">"Página inicial"</string>
+ <string name="sipAddressTypeWork" msgid="6920725730797099047">"Comercial"</string>
+ <string name="sipAddressTypeOther" msgid="4408436162950119849">"Outros"</string>
<string name="contact_status_update_attribution" msgid="5112589886094402795">"por meio de <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
<string name="contact_status_update_attribution_with_date" msgid="5945386376369979909">"<xliff:g id="DATE">%1$s</xliff:g> via <xliff:g id="SOURCE">%2$s</xliff:g>"</string>
<string name="keyguard_password_enter_pin_code" msgid="3731488827218876115">"Digite o código PIN"</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index a366a85..b61635f 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -267,8 +267,8 @@
<string name="permdesc_clearAppCache" msgid="7740465694193671402">"Позволяет приложению освобождать память телефона с помощью удаления файлов из каталога кэша приложений. Обычно это разрешается только системным процессам."</string>
<string name="permlab_movePackage" msgid="728454979946503926">"Перемещать ресурсы приложения"</string>
<string name="permdesc_movePackage" msgid="6323049291923925277">"Позволяет приложению перемещать ресурсы приложения с внутренних на внешние носители и наоборот."</string>
- <!-- outdated translation 4811921703882532070 --> <string name="permlab_readLogs" msgid="6615778543198967614">"считывать системные файлы журналов"</string>
- <!-- outdated translation 2257937955580475902 --> <string name="permdesc_readLogs" msgid="8896449437464867766">"Позволяет приложению считывать информацию из различных журналов системы. Приложение может получить сведения о работе пользователя с телефоном, но они не должны содержать какой-либо личной или конфиденциальной информации."</string>
+ <string name="permlab_readLogs" msgid="6615778543198967614">"считывать конфиденциальные данные журнала"</string>
+ <string name="permdesc_readLogs" msgid="8896449437464867766">"Позволяет приложению считывать информацию из различных журналов системы. Приложение может получать сведения о работе пользователя с телефоном, которые могут содержать личную или конфиденциальную информацию."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"считывать/записывать данные в ресурсы, принадлежащие группе диагностики"</string>
<string name="permdesc_diagnostic" msgid="3121238373951637049">"Позволяет приложению считывать и записывать данные в любые ресурсы, принадлежащие группе диагностики (например, файлы в каталоге /dev). Это может повлиять на стабильность и безопасность системы. Эта возможность может быть использована ТОЛЬКО производителем или оператором для диагностики аппаратного обеспечения."</string>
<string name="permlab_changeComponentState" msgid="79425198834329406">"включать или отключать компоненты приложения"</string>
@@ -544,14 +544,10 @@
<string name="orgTypeWork" msgid="29268870505363872">"Работа"</string>
<string name="orgTypeOther" msgid="3951781131570124082">"Другое"</string>
<string name="orgTypeCustom" msgid="225523415372088322">"Создать свой ярлык"</string>
- <!-- no translation found for sipAddressTypeCustom (2473580593111590945) -->
- <skip />
- <!-- no translation found for sipAddressTypeHome (6093598181069359295) -->
- <skip />
- <!-- no translation found for sipAddressTypeWork (6920725730797099047) -->
- <skip />
- <!-- no translation found for sipAddressTypeOther (4408436162950119849) -->
- <skip />
+ <string name="sipAddressTypeCustom" msgid="2473580593111590945">"Особый"</string>
+ <string name="sipAddressTypeHome" msgid="6093598181069359295">"Домашний"</string>
+ <string name="sipAddressTypeWork" msgid="6920725730797099047">"Рабочий"</string>
+ <string name="sipAddressTypeOther" msgid="4408436162950119849">"Другой"</string>
<string name="contact_status_update_attribution" msgid="5112589886094402795">"с помощью <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
<string name="contact_status_update_attribution_with_date" msgid="5945386376369979909">"<xliff:g id="DATE">%1$s</xliff:g> с помощью <xliff:g id="SOURCE">%2$s</xliff:g>"</string>
<string name="keyguard_password_enter_pin_code" msgid="3731488827218876115">"Введите PIN-код"</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index 137f853..8bc598d 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -267,8 +267,8 @@
<string name="permdesc_clearAppCache" msgid="7740465694193671402">"Tillåter att ett program frigör lagringsutrymme i telefonen genom att ta bort filer i programmets katalog för cachelagring. Åtkomst är mycket begränsad, vanligtvis till systemprocesser."</string>
<string name="permlab_movePackage" msgid="728454979946503926">"Flytta programresurser"</string>
<string name="permdesc_movePackage" msgid="6323049291923925277">"Tillåter att ett program flyttar programresurser från interna till externa medier och tvärt om."</string>
- <!-- outdated translation 4811921703882532070 --> <string name="permlab_readLogs" msgid="6615778543198967614">"läsa systemets loggfiler"</string>
- <!-- outdated translation 2257937955580475902 --> <string name="permdesc_readLogs" msgid="8896449437464867766">"Tillåter att ett program läser från systemets olika loggfiler. Det innebär att programmet kan upptäcka allmän information om vad du gör med telefonen, men den bör inte innehålla personlig eller privat information."</string>
+ <string name="permlab_readLogs" msgid="6615778543198967614">"läsa känsliga loggdata"</string>
+ <string name="permdesc_readLogs" msgid="8896449437464867766">"Tillåter att ett program läser från systemets olika loggfiler. Det innebär att programmet kan upptäcka allmän information om vad du gör med telefonen, vilket kan inkludera personlig eller privat information."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"läsa/skriva till resurser som ägs av diag"</string>
<string name="permdesc_diagnostic" msgid="3121238373951637049">"Tillåter att ett program läser och skriver till en resurs som ägs av diag-gruppen; till exempel filer i /dev. Detta kan eventuellt påverka systemets stabilitet och säkerhet. Detta bör ENDAST används av tillverkaren eller operatören för maskinvaruspecifik diagnostik."</string>
<string name="permlab_changeComponentState" msgid="79425198834329406">"aktivera eller inaktivera programkomponenter"</string>
@@ -544,14 +544,10 @@
<string name="orgTypeWork" msgid="29268870505363872">"Arbete"</string>
<string name="orgTypeOther" msgid="3951781131570124082">"Övrigt"</string>
<string name="orgTypeCustom" msgid="225523415372088322">"Anpassad"</string>
- <!-- no translation found for sipAddressTypeCustom (2473580593111590945) -->
- <skip />
- <!-- no translation found for sipAddressTypeHome (6093598181069359295) -->
- <skip />
- <!-- no translation found for sipAddressTypeWork (6920725730797099047) -->
- <skip />
- <!-- no translation found for sipAddressTypeOther (4408436162950119849) -->
- <skip />
+ <string name="sipAddressTypeCustom" msgid="2473580593111590945">"Anpassad"</string>
+ <string name="sipAddressTypeHome" msgid="6093598181069359295">"Startsida"</string>
+ <string name="sipAddressTypeWork" msgid="6920725730797099047">"Arbete"</string>
+ <string name="sipAddressTypeOther" msgid="4408436162950119849">"Övrigt"</string>
<string name="contact_status_update_attribution" msgid="5112589886094402795">"via <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
<string name="contact_status_update_attribution_with_date" msgid="5945386376369979909">"<xliff:g id="DATE">%1$s</xliff:g> via <xliff:g id="SOURCE">%2$s</xliff:g>"</string>
<string name="keyguard_password_enter_pin_code" msgid="3731488827218876115">"Ange PIN-kod"</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index ad3b5e2..58eb42a 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -267,8 +267,8 @@
<string name="permdesc_clearAppCache" msgid="7740465694193671402">"Uygulamaların uygulama önbelleği dizinindeki dosyaları silerek telefonda yer açmasına izin verir. Erişim genellikle sistem işlemlerine ve yüksek düzeyde kısıtlı olarak verilir."</string>
<string name="permlab_movePackage" msgid="728454979946503926">"Uygulama kaynaklarını taşı"</string>
<string name="permdesc_movePackage" msgid="6323049291923925277">"Bir uygulamanın, uygulama kaynaklarını dahili ve harici ortamlar arasında taşımasına olanak tanır."</string>
- <!-- outdated translation 4811921703882532070 --> <string name="permlab_readLogs" msgid="6615778543198967614">"sistem günlük dosyalarını oku"</string>
- <!-- outdated translation 2257937955580475902 --> <string name="permdesc_readLogs" msgid="8896449437464867766">"Uygulamaların sistemin çeşitli günlük dosyalarından okumalarına izin verir. Bu, uygulamaların telefon ile neler yaptığınız ile ilgili genel bilgi bulmasına izin verir, ancak bunlar kişisel veya özel bir bilgi içermemelidir."</string>
+ <string name="permlab_readLogs" msgid="6615778543198967614">"hassas günlük verilerini okuma"</string>
+ <string name="permdesc_readLogs" msgid="8896449437464867766">"Bir uygulamanın, sistemin çeşitli günlük dosyalarındaki bilgileri okumasına izin verir. Bu izin, uygulamanın, telefonda yaptıklarınızla ilgili genel bilgileri bulmasına olanak sağlar ve bunlar kişisel ve gizli bilgilerinizi de içerebilir."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"sahibi tanılama olan kaynakları oku/bunlara yaz"</string>
<string name="permdesc_diagnostic" msgid="3121238373951637049">"Uygulamanın tanılama grubundaki bir kaynağa ait herhangi bir kaynağı; örneğin /dev içindeki dosyaları okumasına ve bunlara yazmasına izin verir. Bu işlevin sistem kararlılığını ve güvenliğini olumsuz etkileme olasılığı vardır. Üretici veya operatör tarafından YALNIZCA donanıma özgü tanılama için kullanılmalıdır."</string>
<string name="permlab_changeComponentState" msgid="79425198834329406">"uygulama bileşenlerini etkinleştir veya devre dışı bırak"</string>
@@ -544,14 +544,10 @@
<string name="orgTypeWork" msgid="29268870505363872">"İş"</string>
<string name="orgTypeOther" msgid="3951781131570124082">"Diğer"</string>
<string name="orgTypeCustom" msgid="225523415372088322">"Özel"</string>
- <!-- no translation found for sipAddressTypeCustom (2473580593111590945) -->
- <skip />
- <!-- no translation found for sipAddressTypeHome (6093598181069359295) -->
- <skip />
- <!-- no translation found for sipAddressTypeWork (6920725730797099047) -->
- <skip />
- <!-- no translation found for sipAddressTypeOther (4408436162950119849) -->
- <skip />
+ <string name="sipAddressTypeCustom" msgid="2473580593111590945">"Özel"</string>
+ <string name="sipAddressTypeHome" msgid="6093598181069359295">"Ev"</string>
+ <string name="sipAddressTypeWork" msgid="6920725730797099047">"İş"</string>
+ <string name="sipAddressTypeOther" msgid="4408436162950119849">"Diğer"</string>
<string name="contact_status_update_attribution" msgid="5112589886094402795">"<xliff:g id="SOURCE">%1$s</xliff:g> aracılığıyla"</string>
<string name="contact_status_update_attribution_with_date" msgid="5945386376369979909">"<xliff:g id="SOURCE">%2$s</xliff:g> ile <xliff:g id="DATE">%1$s</xliff:g> tarihinde"</string>
<string name="keyguard_password_enter_pin_code" msgid="3731488827218876115">"PIN kodunu gir"</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 4c7d72a..aad56fd 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -267,8 +267,8 @@
<string name="permdesc_clearAppCache" msgid="7740465694193671402">"允许应用程序通过删除应用程序缓存目录中的文件释放手机存储空间。通常此权限只适用于系统进程。"</string>
<string name="permlab_movePackage" msgid="728454979946503926">"移动应用程序资源"</string>
<string name="permdesc_movePackage" msgid="6323049291923925277">"允许应用程序在内部介质和外部介质之间移动应用程序资源。"</string>
- <!-- outdated translation 4811921703882532070 --> <string name="permlab_readLogs" msgid="6615778543198967614">"读取系统日志文件"</string>
- <!-- outdated translation 2257937955580475902 --> <string name="permdesc_readLogs" msgid="8896449437464867766">"允许应用程序从系统的各日志文件中读取信息。这样应用程序可以发现您的手机使用情况,但这些信息不应包含任何个人信息或保密信息。"</string>
+ <string name="permlab_readLogs" msgid="6615778543198967614">"查阅敏感日志数据"</string>
+ <string name="permdesc_readLogs" msgid="8896449437464867766">"允许应用程序从系统的各个日志文件中读取信息。这样,应用程序就可以发现关于您手机使用情况的一般信息,其中可能包含个人信息或私密信息。"</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"读取/写入诊断所拥有的资源"</string>
<string name="permdesc_diagnostic" msgid="3121238373951637049">"允许应用程序读取/写入诊断组所拥有的任何资源(例如,/dev 中的文件)。这可能会影响系统稳定性和安全性。此权限仅供制造商或运营商诊断硬件问题。"</string>
<string name="permlab_changeComponentState" msgid="79425198834329406">"启用或停用应用程序组件"</string>
@@ -544,14 +544,10 @@
<string name="orgTypeWork" msgid="29268870505363872">"公司"</string>
<string name="orgTypeOther" msgid="3951781131570124082">"其他"</string>
<string name="orgTypeCustom" msgid="225523415372088322">"自定义"</string>
- <!-- no translation found for sipAddressTypeCustom (2473580593111590945) -->
- <skip />
- <!-- no translation found for sipAddressTypeHome (6093598181069359295) -->
- <skip />
- <!-- no translation found for sipAddressTypeWork (6920725730797099047) -->
- <skip />
- <!-- no translation found for sipAddressTypeOther (4408436162950119849) -->
- <skip />
+ <string name="sipAddressTypeCustom" msgid="2473580593111590945">"自定义"</string>
+ <string name="sipAddressTypeHome" msgid="6093598181069359295">"住宅"</string>
+ <string name="sipAddressTypeWork" msgid="6920725730797099047">"单位"</string>
+ <string name="sipAddressTypeOther" msgid="4408436162950119849">"其他"</string>
<string name="contact_status_update_attribution" msgid="5112589886094402795">"通过 <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
<string name="contact_status_update_attribution_with_date" msgid="5945386376369979909">"时间:<xliff:g id="DATE">%1$s</xliff:g>,方式:<xliff:g id="SOURCE">%2$s</xliff:g>"</string>
<string name="keyguard_password_enter_pin_code" msgid="3731488827218876115">"输入 PIN 码"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 2439042..6490c55 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -267,8 +267,8 @@
<string name="permdesc_clearAppCache" msgid="7740465694193671402">"允許應用程式刪除快取目錄裡的檔案,釋放儲存空間。此操作通常受到系統程序嚴格限制。"</string>
<string name="permlab_movePackage" msgid="728454979946503926">"移動應用程式資源"</string>
<string name="permdesc_movePackage" msgid="6323049291923925277">"允許應用程式將應用程式資源從內部媒體移到外部媒體,反之亦可。"</string>
- <!-- outdated translation 4811921703882532070 --> <string name="permlab_readLogs" msgid="6615778543198967614">"讀取系統記錄檔"</string>
- <!-- outdated translation 2257937955580475902 --> <string name="permdesc_readLogs" msgid="8896449437464867766">"允許應用程式讀取系統記錄檔。此項操作可讓應用程式了解目前手機操作狀態,但內容應不含任何個人或隱私資訊。"</string>
+ <string name="permlab_readLogs" msgid="6615778543198967614">"讀取機密記錄資料"</string>
+ <string name="permdesc_readLogs" msgid="8896449437464867766">"允許應用程式讀取系統的各種記錄檔。這會允許應用程式搜尋一般性的電話使用資訊,可能包含您的個人或私人資訊。"</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"讀寫 diag 擁有的資源"</string>
<string name="permdesc_diagnostic" msgid="3121238373951637049">"允許應用程式讀寫 diag 群組的資源;例如:/dev 裡的檔案。這可能會影響系統穩定性與安全性。此功能僅供製造商或技術人員用於硬體規格偵測。"</string>
<string name="permlab_changeComponentState" msgid="79425198834329406">"啟用或停用應用程式元件"</string>
@@ -544,14 +544,10 @@
<string name="orgTypeWork" msgid="29268870505363872">"公司"</string>
<string name="orgTypeOther" msgid="3951781131570124082">"其他"</string>
<string name="orgTypeCustom" msgid="225523415372088322">"自訂"</string>
- <!-- no translation found for sipAddressTypeCustom (2473580593111590945) -->
- <skip />
- <!-- no translation found for sipAddressTypeHome (6093598181069359295) -->
- <skip />
- <!-- no translation found for sipAddressTypeWork (6920725730797099047) -->
- <skip />
- <!-- no translation found for sipAddressTypeOther (4408436162950119849) -->
- <skip />
+ <string name="sipAddressTypeCustom" msgid="2473580593111590945">"自訂"</string>
+ <string name="sipAddressTypeHome" msgid="6093598181069359295">"住家"</string>
+ <string name="sipAddressTypeWork" msgid="6920725730797099047">"公司"</string>
+ <string name="sipAddressTypeOther" msgid="4408436162950119849">"其他"</string>
<string name="contact_status_update_attribution" msgid="5112589886094402795">"透過 <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
<string name="contact_status_update_attribution_with_date" msgid="5945386376369979909">"<xliff:g id="DATE">%1$s</xliff:g>透過「<xliff:g id="SOURCE">%2$s</xliff:g>」"</string>
<string name="keyguard_password_enter_pin_code" msgid="3731488827218876115">"輸入 PIN 碼"</string>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 6f0ce71..6370696 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -1351,16 +1351,17 @@
(typically, your Activity). -->
<attr name="onClick" format="string" />
- <!-- Defines overscrolling behavior. This property is used only if the
- View is scrollable. Overscrolling is the ability for the user to
- scroll a View beyond its content boundaries into empty space. -->
- <attr name="overscrollMode">
- <!-- Always allow the user to overscroll the content. -->
+ <!-- Defines over-scrolling behavior. This property is used only if the
+ View is scrollable. Over-scrolling is the ability for the user to
+ receive feedback when attempting to scroll beyond meaningful content. -->
+ <attr name="overScrollMode">
+ <!-- Always show over-scroll effects, even if the content fits entirely
+ within the available space. -->
<enum name="always" value="0" />
- <!-- Only allow the user to overscroll content if the content is large
+ <!-- Only show over-scroll effects if the content is large
enough to meaningfully scroll. -->
<enum name="ifContentScrolls" value="1" />
- <!-- Never overscroll. -->
+ <!-- Never show over-scroll effects. -->
<enum name="never" value="2" />
</attr>
</declare-styleable>
@@ -1797,9 +1798,9 @@
The default value is true. -->
<attr name="footerDividersEnabled" format="boolean" />
<!-- Drawable to draw above list content. -->
- <attr name="overscrollHeader" format="reference|color" />
+ <attr name="overScrollHeader" format="reference|color" />
<!-- Drawable to draw below list content. -->
- <attr name="overscrollFooter" format="reference|color" />
+ <attr name="overScrollFooter" format="reference|color" />
</declare-styleable>
<declare-styleable name="MenuView">
<!-- Default appearance of menu item text. -->
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 6e6dc26..340e23c 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -352,4 +352,8 @@
<!-- Enables SIP on WIFI only -->
<bool name="config_sip_wifi_only">false</bool>
+
+ <!-- Boolean indicating if restoring network selection should be skipped -->
+ <!-- The restoring is handled by modem if it is true-->
+ <bool translatable="false" name="skip_restoring_network_selection">false</bool>
</resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 10cb446..cc91fb7 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1251,9 +1251,9 @@
<public type="attr" name="logo" id="0x010102be" />
<public type="attr" name="xlargeScreens" id="0x010102bf" />
<public type="attr" name="immersive" id="0x010102c0" />
- <public type="attr" name="overscrollMode" id="0x010102c1" />
- <public type="attr" name="overscrollHeader" id="0x010102c2" />
- <public type="attr" name="overscrollFooter" id="0x010102c3" />
+ <public type="attr" name="overScrollMode" id="0x010102c1" />
+ <public type="attr" name="overScrollHeader" id="0x010102c2" />
+ <public type="attr" name="overScrollFooter" id="0x010102c3" />
<public type="attr" name="filterTouchesWhenObscured" id="0x010102c4" />
<public type="attr" name="textSelectHandleLeft" id="0x010102c5" />
<public type="attr" name="textSelectHandleRight" id="0x010102c6" />
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index d9177e7..5c60fd5 100755
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1240,6 +1240,11 @@
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permdesc_cache_filesystem">Allows an application to read and write the cache filesystem.</string>
+ <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permlab_use_sip">make/receive Internet calls</string>
+ <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permdesc_use_sip">Allows an application to use the SIP service to make/receive Internet calls.</string>
+
<!-- Policy administration -->
<!-- Title of policy access to limiting the user's password choices -->
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index a8cd7ce..52c046d 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -247,7 +247,6 @@
<item name="android:clickable">true</item>
<item name="android:textAppearance">?android:attr/textAppearanceSmallInverse</item>
<item name="android:textColor">@android:color/primary_text_light</item>
- <item name="android:textStyle">bold</item>
<item name="android:gravity">center_vertical|center_horizontal</item>
</style>
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index e7cb593..040e732 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -137,8 +137,8 @@
<item name="scrollbarTrackVertical">@null</item>
<!-- Text selection handle attributes -->
- <item name="textSelectHandleLeft">@android:drawable/text_select_handle_middle</item>
- <item name="textSelectHandleRight">@android:drawable/text_select_handle_middle</item>
+ <item name="textSelectHandleLeft">@android:drawable/text_select_handle_left</item>
+ <item name="textSelectHandleRight">@android:drawable/text_select_handle_right</item>
<item name="textSelectHandle">@android:drawable/text_select_handle_middle</item>
<item name="textSelectHandleWindowStyle">@android:style/Widget.TextSelectHandle</item>
diff --git a/core/tests/coretests/res/raw/test1.obb b/core/tests/coretests/res/raw/test1.obb
new file mode 100644
index 0000000..170e36f
--- /dev/null
+++ b/core/tests/coretests/res/raw/test1.obb
Binary files differ
diff --git a/core/tests/coretests/res/raw/test1_nosig.obb b/core/tests/coretests/res/raw/test1_nosig.obb
new file mode 100644
index 0000000..5c3573f7
--- /dev/null
+++ b/core/tests/coretests/res/raw/test1_nosig.obb
Binary files differ
diff --git a/core/tests/coretests/res/raw/test1_wrongpackage.obb b/core/tests/coretests/res/raw/test1_wrongpackage.obb
new file mode 100644
index 0000000..2e02eaa
--- /dev/null
+++ b/core/tests/coretests/res/raw/test1_wrongpackage.obb
Binary files differ
diff --git a/core/tests/coretests/src/android/bluetooth/BluetoothTestUtils.java b/core/tests/coretests/src/android/bluetooth/BluetoothTestUtils.java
index e9311e0..2d0424d 100644
--- a/core/tests/coretests/src/android/bluetooth/BluetoothTestUtils.java
+++ b/core/tests/coretests/src/android/bluetooth/BluetoothTestUtils.java
@@ -133,14 +133,12 @@
private class HeadsetServiceListener implements ServiceListener {
private boolean mConnected = false;
- @Override
public void onServiceConnected() {
synchronized (this) {
mConnected = true;
}
}
- @Override
public void onServiceDisconnected() {
synchronized (this) {
mConnected = false;
@@ -321,6 +319,9 @@
filter.addAction(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED);
filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
mContext.registerReceiver(mReceiver, filter);
+
+ mA2dp = new BluetoothA2dp(mContext);
+ mHeadset = new BluetoothHeadset(mContext, mHeadsetServiceListener);
}
public void close() {
diff --git a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
index 1289a9e..d5f385b 100755
--- a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
+++ b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
@@ -45,6 +45,7 @@
import android.util.Log;
import java.io.File;
+import java.io.IOException;
import java.io.InputStream;
public class PackageManagerTests extends AndroidTestCase {
@@ -378,6 +379,18 @@
assertEquals(publicSrcPath, appInstallPath);
assertFalse((info.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0);
assertTrue(info.nativeLibraryDir.startsWith(dataDir.getPath()));
+
+ // Make sure the native library dir is not a symlink
+ final File nativeLibDir = new File(info.nativeLibraryDir);
+ assertTrue("Native library dir should exist at " + info.nativeLibraryDir,
+ nativeLibDir.exists());
+ try {
+ assertEquals("Native library dir should not be a symlink",
+ info.nativeLibraryDir,
+ nativeLibDir.getCanonicalPath());
+ } catch (IOException e) {
+ fail("Can't read " + nativeLibDir.getPath());
+ }
} else if (rLoc == INSTALL_LOC_SD){
assertTrue("Application flags (" + info.flags
+ ") should contain FLAG_EXTERNAL_STORAGE",
@@ -391,6 +404,19 @@
assertTrue("The native library path (" + info.nativeLibraryDir
+ ") should start with " + SECURE_CONTAINERS_PREFIX,
info.nativeLibraryDir.startsWith(SECURE_CONTAINERS_PREFIX));
+
+ // Make sure the native library in /data/data/<app>/lib is a
+ // symlink to the ASEC
+ final File nativeLibSymLink = new File(info.dataDir, "lib");
+ assertTrue("Native library symlink should exist at " + nativeLibSymLink.getPath(),
+ nativeLibSymLink.exists());
+ try {
+ assertEquals(nativeLibSymLink.getPath() + " should be a symlink to "
+ + info.nativeLibraryDir, info.nativeLibraryDir, nativeLibSymLink
+ .getCanonicalPath());
+ } catch (IOException e) {
+ fail("Can't read " + nativeLibSymLink.getPath());
+ }
} else {
// TODO handle error. Install should have failed.
fail("Install should have failed");
@@ -579,7 +605,6 @@
private InstallParams installFromRawResource(String outFileName,
int rawResId, int flags, boolean cleanUp, boolean fail, int result,
int expInstallLocation) {
- PackageManager pm = mContext.getPackageManager();
InstallParams ip = new InstallParams(outFileName, rawResId);
installFromRawResource(ip, flags, cleanUp, fail, result, expInstallLocation);
return ip;
@@ -1407,13 +1432,21 @@
receiver);
assertTrue(retCode);
ApplicationInfo info = getPm().getApplicationInfo(ip.pkg.packageName, 0);
- assertNotNull(info);
+ assertNotNull("ApplicationInfo for recently installed application should exist",
+ info);
if ((moveFlags & PackageManager.MOVE_INTERNAL) != 0) {
- assertTrue((info.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) == 0);
- assertTrue(info.nativeLibraryDir.startsWith(info.dataDir));
+ assertTrue("ApplicationInfo.FLAG_EXTERNAL_STORAGE flag should NOT be set",
+ (info.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) == 0);
+ assertTrue("ApplicationInfo.nativeLibraryDir should start with " + info.dataDir,
+ info.nativeLibraryDir.startsWith(info.dataDir));
} else if ((moveFlags & PackageManager.MOVE_EXTERNAL_MEDIA) != 0){
- assertTrue((info.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0);
- assertTrue(info.nativeLibraryDir.startsWith(SECURE_CONTAINERS_PREFIX));
+ assertTrue("ApplicationInfo.FLAG_EXTERNAL_STORAGE flag should be set",
+ (info.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0);
+ assertTrue("ApplicationInfo.nativeLibraryDir should start with " + SECURE_CONTAINERS_PREFIX,
+ info.nativeLibraryDir.startsWith(SECURE_CONTAINERS_PREFIX));
+ final File nativeLibSymLink = new File(info.dataDir, "lib");
+ assertTrue("The data directory should have a 'lib' symlink that points to the ASEC container",
+ nativeLibSymLink.getCanonicalPath().startsWith(SECURE_CONTAINERS_PREFIX));
}
}
} catch (NameNotFoundException e) {
diff --git a/core/tests/coretests/src/com/android/server/MountServiceTests.java b/core/tests/coretests/src/com/android/server/MountServiceTests.java
new file mode 100644
index 0000000..83e9d18
--- /dev/null
+++ b/core/tests/coretests/src/com/android/server/MountServiceTests.java
@@ -0,0 +1,210 @@
+/*
+ * 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.server;
+
+import com.android.frameworks.coretests.R;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.content.res.Resources.NotFoundException;
+import android.os.Environment;
+import android.os.FileUtils;
+import android.os.storage.OnObbStateChangeListener;
+import android.os.storage.StorageManager;
+import android.test.AndroidTestCase;
+import android.test.ComparisonFailure;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.util.Log;
+
+import java.io.File;
+import java.io.InputStream;
+
+public class MountServiceTests extends AndroidTestCase {
+ private static final String TAG = "MountServiceTests";
+
+ private static final long MAX_WAIT_TIME = 25*1000;
+ private static final long WAIT_TIME_INCR = 5*1000;
+
+ private static final String OBB_MOUNT_PREFIX = "/mnt/obb/";
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ }
+
+ private static void assertStartsWith(String message, String prefix, String actual) {
+ if (!actual.startsWith(prefix)) {
+ throw new ComparisonFailure(message, prefix, actual);
+ }
+ }
+
+ private interface CompletableTask {
+ public boolean isDone();
+ }
+
+ private static class ObbObserver extends OnObbStateChangeListener implements CompletableTask {
+ public String path;
+ public String state;
+ boolean done = false;
+
+ @Override
+ public void onObbStateChange(String path, String state) {
+ synchronized (this) {
+ this.path = path;
+ this.state = state;
+ done = true;
+ notifyAll();
+ }
+ }
+
+ public void reset() {
+ this.path = null;
+ this.state = null;
+ done = false;
+ }
+
+ public boolean isDone() {
+ return done;
+ }
+ }
+
+ private boolean waitForCompletion(CompletableTask task) {
+ long waitTime = 0;
+ synchronized (task) {
+ while (!task.isDone() && waitTime < MAX_WAIT_TIME) {
+ try {
+ task.wait(WAIT_TIME_INCR);
+ waitTime += WAIT_TIME_INCR;
+ } catch (InterruptedException e) {
+ Log.i(TAG, "Interrupted during sleep", e);
+ }
+ }
+ }
+
+ return task.isDone();
+ }
+ private File getFilePath(String name) {
+ final File filesDir = mContext.getFilesDir();
+ final File outFile = new File(filesDir, name);
+ return outFile;
+ }
+
+ private void copyRawToFile(int rawResId, File outFile) {
+ Resources res = mContext.getResources();
+ InputStream is = null;
+ try {
+ is = res.openRawResource(rawResId);
+ } catch (NotFoundException e) {
+ fail("Failed to load resource with id: " + rawResId);
+ }
+ FileUtils.setPermissions(outFile.getPath(), FileUtils.S_IRWXU | FileUtils.S_IRWXG
+ | FileUtils.S_IRWXO, -1, -1);
+ assertTrue(FileUtils.copyToFile(is, outFile));
+ FileUtils.setPermissions(outFile.getPath(), FileUtils.S_IRWXU | FileUtils.S_IRWXG
+ | FileUtils.S_IRWXO, -1, -1);
+ }
+
+ private StorageManager getStorageManager() {
+ return (StorageManager) getContext().getSystemService(Context.STORAGE_SERVICE);
+ }
+
+ private void mountObb(StorageManager sm, final int resource, final File file,
+ String expectedState) {
+ copyRawToFile(resource, file);
+
+ ObbObserver observer = new ObbObserver();
+ assertTrue("mountObb call on " + file.getPath() + " should succeed",
+ sm.mountObb(file.getPath(), null, observer));
+
+ assertTrue("Mount should have completed",
+ waitForCompletion(observer));
+
+ assertEquals("Actual file and resolved file should be the same",
+ file.getPath(), observer.path);
+
+ assertEquals(expectedState, observer.state);
+ }
+
+ private String checkMountedPath(StorageManager sm, File file) {
+ final String mountPath = sm.getMountedObbPath(file.getPath());
+ assertStartsWith("Path should be in " + OBB_MOUNT_PREFIX,
+ OBB_MOUNT_PREFIX,
+ mountPath);
+ return mountPath;
+ }
+
+ private void unmountObb(StorageManager sm, final File outFile) {
+ ObbObserver observer = new ObbObserver();
+ assertTrue("unmountObb call on test1.obb should succeed",
+ sm.unmountObb(outFile.getPath(), false, observer));
+
+ assertTrue("Unmount should have completed",
+ waitForCompletion(observer));
+ }
+
+ @LargeTest
+ public void testMountAndUnmountObbNormal() {
+ StorageManager sm = getStorageManager();
+
+ final File outFile = getFilePath("test1.obb");
+
+ mountObb(sm, R.raw.test1, outFile, Environment.MEDIA_MOUNTED);
+
+ final String mountPath = checkMountedPath(sm, outFile);
+ final File mountDir = new File(mountPath);
+
+ assertTrue("OBB mounted path should be a directory",
+ mountDir.isDirectory());
+
+ unmountObb(sm, outFile);
+ }
+
+ @LargeTest
+ public void testAttemptMountNonObb() {
+ StorageManager sm = getStorageManager();
+
+ final File outFile = getFilePath("test1_nosig.obb");
+
+ mountObb(sm, R.raw.test1_nosig, outFile, Environment.MEDIA_BAD_REMOVAL);
+
+ assertFalse("OBB should not be mounted",
+ sm.isObbMounted(outFile.getPath()));
+
+ assertNull("OBB's mounted path should be null",
+ sm.getMountedObbPath(outFile.getPath()));
+ }
+
+ @LargeTest
+ public void testAttemptMountObbWrongPackage() {
+ StorageManager sm = getStorageManager();
+
+ final File outFile = getFilePath("test1_wrongpackage.obb");
+
+ mountObb(sm, R.raw.test1_wrongpackage, outFile, Environment.MEDIA_BAD_REMOVAL);
+
+ assertFalse("OBB should not be mounted",
+ sm.isObbMounted(outFile.getPath()));
+
+ assertNull("OBB's mounted path should be null",
+ sm.getMountedObbPath(outFile.getPath()));
+ }
+}
diff --git a/docs/html/guide/guide_toc.cs b/docs/html/guide/guide_toc.cs
index 35ce17e..43a5e8d 100644
--- a/docs/html/guide/guide_toc.cs
+++ b/docs/html/guide/guide_toc.cs
@@ -257,6 +257,9 @@
<li><a href="<?cs var:toroot?>guide/topics/testing/testing_android.html">
<span class="en">Testing and Instrumentation</span></a>
<span class="new">new!</span></li>
+ <li><a href="<?cs var:toroot?>guide/topics/admin/device-admin.html">
+ <span class="en">Device Administration</span></a>
+ <span class="new">new!</span></li>
</ul>
</li>
diff --git a/docs/html/guide/topics/admin/device-admin.jd b/docs/html/guide/topics/admin/device-admin.jd
new file mode 100644
index 0000000..4d9a14f
--- /dev/null
+++ b/docs/html/guide/topics/admin/device-admin.jd
@@ -0,0 +1,494 @@
+page.title=Android Device Administration API
+@jd:body
+<div id="qv-wrapper">
+<div id="qv">
+ <h2>In this document</h2>
+ <ol>
+<li><a href="#overview">Device Administration API Overview</a>
+ <ol>
+ <li><a href="#policies">Policies</a></li>
+ </ol>
+ </li>
+ <li><a href="#how">How Does It Work?</a></li>
+ <li><a href="#sample">Sample Application</a></li>
+ <li><a href="#developing">Developing a Device Administration Application</a>
+ <ol>
+ <li><a href="#manifest">Creating the Manifest</a></li>
+ <li><a href="#code">Implementing the Code</a>
+ </li>
+ </ol>
+ </ol>
+ </div>
+</div>
+
+<p>Android 2.2 introduces support for enterprise applications by offering the
+Android Device Administration API. The Device Administration API provides device
+administration features at the system level. These APIs allow you to create
+security-aware applications that are useful in enterprise settings, in which IT
+professionals require rich control over employee devices. For example, the
+built-in Android Email application has leveraged the new APIs to improve
+Exchange support. Through the Email application, Exchange administrators can
+enforce password policies — including alphanumeric passwords or numeric
+PINs — across devices. Administrators can also remotely wipe (that is,
+restore factory defaults on) lost or stolen handsets. Exchange users can sync
+their email and calendar data.</p>
+
+<p>This document is intended for developers who want to develop enterprise
+solutions for Android-powered devices. It discusses the various features
+provided by the Device Administration API to provide stronger security for
+employee devices that are powered by Android.</p>
+<h2 id="overview">Device Administration API Overview</h2>
+<p>Here are examples of the types of applications that might use the Device Administration API:</p>
+<ul>
+ <li>Email clients.</li>
+ <li>Security applications that do remote wipe.</li>
+ <li>Device management services and applications.</li>
+</ul>
+
+<h3 id="how">How Does it Work?</h3>
+<p>You use the Device Administration API to write device admin applications that users
+install on their devices. The device admin application enforces the desired
+policies. Here's how it works:</p> <ul>
+ <li>A system administrator writes a device admin application that enforces
+remote/local device security policies. These policies could be hard-coded into
+the app, or the application could dynamically fetch policies from a third-party
+server. </li>
+<li>The application is installed on users' devices. Android does
+not currently have an automated provisioning solution. Some of the ways a sysadmin might
+distribute the application to users are as follows:
+<ul>
+<li>Android Market.</li>
+<li>Enabling non-market installation.</li>
+<li>Distributing the application through other means, such as email or websites.</li>
+
+</ul>
+
+
+</li>
+ <li>The system prompts the user to enable the device admin application. How
+and when this happens depends on how the application is implemented.</li>
+<li>Once users enable the device admin application, they are subject to
+its policies. Complying with those policies typically confers benefits, such as
+access to sensitive systems and data.</li>
+</ul>
+<p>If users do not enable the device admin app, it remains on the device, but in an inactive state. Users will not be subject to its policies, and they will conversely not get any of the application's benefits—for example, they may not be able to sync data.</p>
+<p>If a user fails to comply with the policies (for example, if a user sets a
+password that violates the guidelines), it is up to the application to decide
+how to handle this. However, typically this will result in the user not being
+able to sync data.</p>
+<p>If a device attempts to connect to a server that requires policies not
+supported in the Device Administration API, the connection will not
+be allowed. The Device Administration API does not currently allow partial
+provisioning. In other words, if a device (for example, a legacy device) does
+not support all of the stated policies, there is no way to allow the
+device to connect.</p>
+<p>If a device contains multiple enabled admin applications, the strictest policy is
+enforced. There is no way to target a particular admin
+application.</p>
+<p>To uninstall an existing device admin application, users need to
+first unregister the application as an administrator. </p>
+
+<h3 id ="policies">Policies</h3>
+<p>In an enterprise setting, it's often the case that employee devices must
+adhere to a strict set of policies that govern the use of the device. The
+Device Administration API supports the policies listed in Table 1.
+Note that the Device Administration API currently only supports passwords for screen
+lock:</p>
+<p class="table-caption"><strong>Table 1.</strong> Policies supported by the Device Administration API.</p>
+<table border="1">
+ <tr>
+ <th>Policy</th>
+ <th>Description</th>
+ </tr>
+ <tr>
+ <td>Password enabled</td>
+ <td>Requires that devices ask for PIN or passwords.</td>
+ </tr>
+ <tr>
+ <td>Minimum password length</td>
+ <td>Set the required number of characters for the password. For example, you
+can require PIN or passwords to have at least six characters. </td> </tr>
+ <tr>
+ <td>Alphanumeric password required</td>
+ <td>Requires that passwords have a
+combination of letters and numbers. They may include symbolic characters.
+ </td>
+ </tr>
+ <tr>
+ <td>Maximum failed password attempts </td>
+ <td>Specifies how many times a user can enter the wrong password before the
+device wipes its data. The Device Administration API also allows administrators to
+remotely reset the device to factory defaults. This secures data in case the
+device is lost or stolen.</td>
+ </tr>
+ <tr>
+ <td>Maximum inactivity time lock</td>
+ <td>Sets the length of time since the user last touched the screen or
+pressed a button before the device locks the screen. When this happens, users
+need to enter their PIN or passwords again before they can use their devices and
+access data. The value can be between 1 and 60 minutes.</td> </tr>
+</table>
+<h4>Other Features</h4>
+<p>In addition to supporting the policies listed in the above table, the Device
+Administration API lets you do the following:</p> <ul>
+ <li>Prompt user to set a new password.</li>
+ <li>Lock device immediately.</li>
+ <li>Wipe the device's data (that is, restore the device to its factory defaults).</li>
+</ul>
+
+
+<h2 id="sample">Sample Application</h2>
+<p>The examples used in this document are based on the <a
+href="{@docRoot}resources/samples/ApiDemos/src/com/example/
+android/apis/app/DeviceAdminSample.html">Device Administration API
+sample</a>, which is included in the SDK samples. For information on downloading and
+installing the SDK samples, see <a
+href="{@docRoot}resources/samples/get.html">
+Getting the Samples</a>. Here is the <a
+href="{@docRoot}resources/samples/ApiDemos/src/com/example/
+android/apis/app/DeviceAdminSample.html">complete code</a> for
+the sample. </p>
+<p>The
+sample application offers a demo of device admin features. It presents users
+with a user interface that lets them enable the device admin application. Once
+they've enabled the application, they can use the buttons in the user interface
+to do the following:</p>
+<ul>
+ <li>Set password quality.</li>
+ <li>Specify the minimum length for the user's password.</li>
+ <li>Set the password. If the password does not conform to the specified
+policies, the system returns an error.</li>
+ <li>Set how many failed password attempts can occur before the device is wiped
+(that is, restored to factory settings).</li>
+ <li>Set the maximum amount of inactive time that can elapse before the device
+locks.</li>
+ <li>Make the device lock immediately.</li>
+ <li>Wipe the device's data (that is, restore factory settings).</li>
+</ul>
+
+<img src="{@docRoot}images/admin/device-admin-app.png"/>
+<p class="img-caption"><strong>Figure 1.</strong> Screenshot of the Sample Application</p>
+
+<h2 id="developing">Developing a Device Administration Application</h2>
+
+<p>System administrators can use the Device Administration API to write an application
+that enforces remote/local device security policy enforcement. This section
+summarizes the steps involved in creating a device administration
+application.</p>
+<h3 id="manifest">Creating the Manifest</h3>
+<p>To use the Device Administration API, the application's
+manifest must include the following:</p>
+<ul>
+ <li>A subclass of {@link android.app.admin.DeviceAdminReceiver} that includes the following:
+ <ul>
+ <li>The {@link android.Manifest.permission#BIND_DEVICE_ADMIN} permission.</li>
+ <li>The ability to respond to the {@link android.app.admin.DeviceAdminReceiver#ACTION_DEVICE_ADMIN_ENABLED}
+intent, expressed in the manifest as an intent filter.</li>
+ </ul>
+ </li>
+ <li>A declaration of security policies used in metadata.</li>
+</ul>
+<p>Here is an excerpt from the Device Administration sample manifest:</p>
+<pre><activity android:name=".app.DeviceAdminSample$Controller"
+ android:label="@string/activity_sample_device_admin">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.SAMPLE_CODE" />
+ </intent-filter>
+</activity>
+
+<receiver android:name=".app.DeviceAdminSample"
+ android:label="@string/sample_device_admin"
+ android:description="@string/sample_device_admin_description"
+ android:permission="android.permission.BIND_DEVICE_ADMIN">
+ <meta-data android:name="android.app.device_admin"
+ android:resource="@xml/device_admin_sample" />
+ <intent-filter>
+ <action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
+ </intent-filter>
+</receiver></pre>
+
+ <p>Note that:</p>
+<ul>
+ <li>The activity in the sample application is an {@link android.app.Activity}
+subclass called <code>Controller</code>. The syntax
+<code>".app.DeviceAdminSample$Controller"</code> indicates that
+<code>Controller</code> is an inner class that is nested inside the
+<code>DeviceAdminSample</code> class. Note that an Activity does not need to be
+an inner class; it just is in this example.</li>
+
+<li>The following attributes refer to string resources that for the sample application reside in
+<code>ApiDemos/res/values/strings.xml</code>. For more information about resources, see
+<a
+href="{@docRoot}guide/topics/resources/index.html">Application Resources</a>.
+<ul>
+<li><code>android:label="@string/activity_sample_device_admin"</code> refers to the
+user-readable label for the activity.</li>
+
+<li><code>android:label="@string/sample_device_admin"</code> refers to the
+user-readable label for the permission.</li>
+
+<li><code>android:description="@string/sample_device_admin_description"</code> refers to
+the user-readable description of the permission. A descripton is typically longer and more
+informative than
+a label.</li>
+</ul>
+
+
+<li><code>android:permission="android.permission.BIND_DEVICE_ADMIN"
+</code> is a permission that a {@link android.app.admin.DeviceAdminReceiver} subclass must
+have, to ensure that only the system can interact with the receiver (no application can be granted this permission). This
+prevents other applications from abusing your device admin app.</li>
+<li><code>android.app.action.DEVICE_ADMIN_ENABLED</code> is the the primary
+action that a {@link android.app.admin.DeviceAdminReceiver} subclass must handle to be
+allowed to manage a device. This is set to the receiver when the user enables
+the device admin app. Your code typically handles this in
+{@link android.app.admin.DeviceAdminReceiver#onEnabled onEnabled()}. To be supported, the receiver must also
+require the {@link android.Manifest.permission#BIND_DEVICE_ADMIN} permission so that other applications
+cannot abuse it. </li>
+<li>When a user enables the device admin application, that gives the receiver
+permission to perform actions in response to the broadcast of particular system
+events. When suitable event arises, the application can impose a policy. For
+example, if the user attempts to set a new password that doesn't meet the policy
+requirements, the application can prompt the user to pick a different password
+that does meet the requirements.</li>
+
+ <li><code>android:resource="@xml/device_admin_sample"</code>
+declares the security policies used in metadata. The metadata provides additional
+information specific to the device administrator, as parsed by the {@link
+android.app.admin.DeviceAdminInfo} class. Here are the contents of
+<code>device_admin_sample.xml</code>:</li>
+</ul>
+<pre><device-admin xmlns:android="http://schemas.android.com/apk/res/android">
+ <uses-policies>
+ <limit-password />
+ <watch-login />
+ <reset-password />
+ <force-lock />
+ <wipe-data />
+ </uses-policies>
+</device-admin>
+</pre>
+<p> In designing your device administration application, you don't need to
+include all of the policies, just the ones that are relevant for your app.
+</p>
+For more discussion of the manifest file, see the <a
+href="{@docRoot}guide/topics/manifest/manifest-intro.html">Android Developers Guide</a>.
+<h2 id="code">Implementing the Code</h2>
+<p>The Device Administration API includes the following classes:</p>
+<dl>
+ <dt>{@link android.app.admin.DeviceAdminReceiver}</dt>
+ <dd>Base class for implementing a device administration component. This class provides
+a convenience for interpreting the raw intent actions that are sent by the
+system. Your Device Administration application must include a
+{@link android.app.admin.DeviceAdminReceiver} subclass.</dd>
+ <dt>{@link android.app.admin.DevicePolicyManager}</dt>
+<dd>A class for managing policies enforced on a device. Most clients of
+this class must have published a {@link android.app.admin.DeviceAdminReceiver} that the user
+has currently enabled. The {@link android.app.admin.DevicePolicyManager} manages policies for
+one or more {@link android.app.admin.DeviceAdminReceiver} instances</dd>
+ <dt>{@link android.app.admin.DeviceAdminInfo}</dt>
+<dd>This class is used to specify metadata
+for a device administrator component.</dd>
+</dl>
+<p>These classes provide the foundation for a fully functional device administration application.
+The rest of this section describes how you use the {@link
+android.app.admin.DeviceAdminReceiver} and
+{@link android.app.admin.DevicePolicyManager} APIs to write a device admin application.</p>
+<h4 id="receiver">Subclassing DeviceAdminReceiver</h4>
+<p>To create a device admin application, you must subclass
+{@link android.app.admin.DeviceAdminReceiver}. The {@link android.app.admin.DeviceAdminReceiver} class
+consists of a series of callbacks that are triggered when particular events
+occur.</p>
+<p>In its {@link android.app.admin.DeviceAdminReceiver} subclass, the sample application
+simply displays a {@link android.widget.Toast} notification in response to particular
+events. For example:</p>
+<pre>public class DeviceAdminSample extends DeviceAdminReceiver {
+
+...
+ @Override
+ public void onEnabled(Context context, Intent intent) {
+ showToast(context, "Sample Device Admin: enabled");
+ }
+
+ @Override
+ public CharSequence onDisableRequested(Context context, Intent intent) {
+ return "This is an optional message to warn the user about disabling.";
+ }
+
+ @Override
+ public void onDisabled(Context context, Intent intent) {
+ showToast(context, "Sample Device Admin: disabled");
+ }
+
+ @Override
+ public void onPasswordChanged(Context context, Intent intent) {
+ showToast(context, "Sample Device Admin: pw changed");
+ }
+
+ void showToast(Context context, CharSequence msg) {
+ Toast.makeText(context, msg, Toast.LENGTH_SHORT).show();
+ }
+...
+}</pre>
+<h4 id="enabling">Enabling the Application</h4>
+<p>One of the major events a device admin application has to handle is the user
+enabling the application. The user must explicitly enable the application for
+the policies to be enforced. If the user chooses not to enable the application
+it will still be present on the device, but its policies will not be enforced, and the user will not
+get any of the application's benefits.</p>
+<p>The process of enabling the application begins when the user performs an
+action that triggers the {@link android.app.admin.DevicePolicyManager#ACTION_ADD_DEVICE_ADMIN}
+intent. In the
+sample application, this happens when the user clicks the <strong>Enable
+Admin</strong> button. </p>
+<p>When the user clicks the <strong>Enable Admin</strong> button, the display
+changes to prompt the user to enable the device admin application, as shown in <strong>Figure 2</strong>.</p>
+
+<img src="{@docRoot}images/admin/device-admin-activate-prompt.png"/>
+<p class="img-caption"><strong>Figure 2.</strong> Sample Application: Activating the Application</p>
+<p>Below is the code that gets executed when the user clicks the <strong>Enable
+Admin</strong> button shown in <strong>Figure 1</strong>. </p>
+
+<pre> private OnClickListener mEnableListener = new OnClickListener() {
+ public void onClick(View v) {
+ // Launch the activity to have the user enable our admin.
+ Intent intent = new Intent(DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN);
+ intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN,
+ mDeviceAdminSample);
+ intent.putExtra(DevicePolicyManager.EXTRA_ADD_EXPLANATION,
+ "Additional text explaining why this needs to be added.");
+ startActivityForResult(intent, RESULT_ENABLE);
+ }
+};
+
+...
+// This code checks whether the device admin app was successfully enabled.
+@Override
+protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+ switch (requestCode) {
+ case RESULT_ENABLE:
+ if (resultCode == Activity.RESULT_OK) {
+ Log.i("DeviceAdminSample", "Administration enabled!");
+ } else {
+ Log.i("DeviceAdminSample", "Administration enable FAILED!");
+ }
+ return;
+ }
+ super.onActivityResult(requestCode, resultCode, data);
+}</pre>
+
+<p>The line
+<code>intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN,
+mDeviceAdminSample)</code> states that <code>mDeviceAdminSample</code> (which is
+a {@link android.app.admin.DeviceAdminReceiver} component) is the target policy.
+This line invokes the user interface shown in <strong>Figure 2</strong>, which guides users through
+adding the device administrator to the system (or allows them to reject it).</p>
+
+<p>When the application needs to perform an operation that is contingent on the
+device admin application being enabled, it confirms that the application is
+active. To do this it uses the {@link android.app.admin.DevicePolicyManager} method
+{@link android.app.admin.DevicePolicyManager#isAdminActive(android.content.ComponentName) isAdminActive()}. Notice that the {@link android.app.admin.DevicePolicyManager}
+method {@link android.app.admin.DevicePolicyManager#isAdminActive(android.content.ComponentName) isAdminActive()} takes a {@link android.app.admin.DeviceAdminReceiver}
+component as its argument:</p>
+<pre>
+DevicePolicyManager mDPM;
+...
+boolean active = mDPM.isAdminActive(mDeviceAdminSample);
+if (active) {
+ // Admin app is active, so do some admin stuff
+ ...
+} else {
+ // do something else
+}
+</pre>
+<h3 id="admin_ops">Managing Policies</h3>
+<p>{@link android.app.admin.DevicePolicyManager} is a public class for managing policies
+enforced on a device. {@link android.app.admin.DevicePolicyManager} manages policies for one
+or more {@link android.app.admin.DeviceAdminReceiver} instances. </p>
+<p>You get a handle to the {@link android.app.admin.DevicePolicyManager} as follows: </p>
+<pre>DevicePolicyManager mDPM =
+(DevicePolicyManager)getSystemService(Context.DEVICE_POLICY_SERVICE);<br
+/></pre>
+<p>This section describes how to use {@link android.app.admin.DevicePolicyManager} to perform
+ administrative tasks:</p>
+<ul>
+ <li><a href="#pwd">Set password policies</a></li>
+ <li><a href="#lock">Set device lock</a></li>
+ <li><a href="#wipe">Perform data wipe</a></li>
+</ul>
+<h4 id="pwd">Set password policies</h4>
+<p>{@link android.app.admin.DevicePolicyManager} includes APIs for setting and enforcing the
+device password policy. In the Device Administration API, the password only applies to
+screen lock. This section describes common password-related tasks.</p>
+<h5>Set a password for the device</h5>
+<p>This code displays a user interface prompting the user to set a password:</p>
+<pre>Intent intent = new Intent(DevicePolicyManager.ACTION_SET_NEW_PASSWORD);
+startActivity(intent);
+</pre>
+<h5>Set the password quality</h5>
+<p>The password quality can be one of the following {@link android.app.admin.DevicePolicyManager} constants: </p>
+<dl>
+ <dt>{@link android.app.admin.DevicePolicyManager#PASSWORD_QUALITY_ALPHABETIC}</dt><dd>The user must enter a
+password containing at least alphabetic (or other symbol) characters.</dd>
+ <dt>{@link android.app.admin.DevicePolicyManager#PASSWORD_QUALITY_ALPHANUMERIC}</dt><dd>The user must enter a
+password containing at least <em>both</em> numeric <em>and</em> alphabetic (or
+other symbol) characters.</dd>
+ <dt>{@link android.app.admin.DevicePolicyManager#PASSWORD_QUALITY_NUMERIC}</dt><dd>The user must enter a password
+containing at least numeric characters.</dd>
+ <dt>{@link android.app.admin.DevicePolicyManager#PASSWORD_QUALITY_SOMETHING}</dt><dd>The policy requires some kind
+of password, but doesn't care what it is.</dd>
+ <dt>{@link android.app.admin.DevicePolicyManager#PASSWORD_QUALITY_UNSPECIFIED}</dt><dd>
+ The policy has no requirements for the password. </dd>
+</dl>
+<p>For example, this is how you would set the password policy to require an alphanumeric password:</p>
+<pre>
+DevicePolicyManager mDPM;
+ComponentName mDeviceAdminSample;
+...
+mDPM.setPasswordQuality(mDeviceAdminSample, DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC);
+</pre>
+<h5>Set the minimum password length</h5>
+<p>You can specify that a password must be at least the specified minimum
+length. For example:</p>
+<pre>DevicePolicyManager mDPM;
+ComponentName mDeviceAdminSample;
+int pwLength;
+...
+mDPM.setPasswordMinimumLength(mDeviceAdminSample, pwLength);
+</pre>
+<h5>Set maximum failed password attempts</h5>
+<p>You can set the maximum number of allowed failed password attempts before the
+device is wiped (that is, reset to factory settings). For example:</p>
+<pre>DevicePolicyManager mDPM;
+ComponentName mDeviceAdminSample;
+int maxFailedPw;
+ ...
+mDPM.setMaximumFailedPasswordsForWipe(mDeviceAdminSample, maxFailedPw);</pre>
+<h4 id="lock">Set device lock</h4>
+<p>You can set the maximum period of user inactivity that can occur before the
+device locks. For example:</p>
+<pre>
+DevicePolicyManager mDPM;
+ComponentName mDeviceAdminSample;
+...
+long timeMs = 1000L*Long.parseLong(mTimeout.getText().toString());
+mDPM.setMaximumTimeToLock(mDeviceAdminSample, timeMs);
+</pre>
+<p>You can also programmatically tell the device to lock immediately:</p>
+<pre>
+DevicePolicyManager mDPM;
+mDPM.lockNow();</pre>
+<h4 id="wipe">Perform data wipe</h4>
+<p>You can use the {@link android.app.admin.DevicePolicyManager} method
+{@link android.app.admin.DevicePolicyManager#wipeData wipeData()} to reset the device to factory settings. This is useful
+if the device is lost or stolen. Often the decision to wipe the device is the
+result of certain conditions being met. For example, you can use
+{@link android.app.admin.DevicePolicyManager#setMaximumFailedPasswordsForWipe setMaximumFailedPasswordsForWipe()} to state that a device should be
+wiped after a specific number of failed password attempts.</p>
+<p>You wipe data as follows:</p>
+<pre>
+DevicePolicyManager mDPM;
+mDPM.wipeData(0);</pre>
+<p>The {@link android.app.admin.DevicePolicyManager#wipeData wipeData()} method takes as its parameter a bit mask of
+additional options. Currently the value must be 0. </p>
diff --git a/docs/html/images/admin/device-admin-activate-prompt.png b/docs/html/images/admin/device-admin-activate-prompt.png
new file mode 100755
index 0000000..fd001bd
--- /dev/null
+++ b/docs/html/images/admin/device-admin-activate-prompt.png
Binary files differ
diff --git a/docs/html/images/admin/device-admin-app.png b/docs/html/images/admin/device-admin-app.png
new file mode 100755
index 0000000..d966a28
--- /dev/null
+++ b/docs/html/images/admin/device-admin-app.png
Binary files differ
diff --git a/include/media/MediaPlayerInterface.h b/include/media/MediaPlayerInterface.h
index 3662983..0521709 100644
--- a/include/media/MediaPlayerInterface.h
+++ b/include/media/MediaPlayerInterface.h
@@ -76,6 +76,7 @@
virtual uint32_t latency() const = 0;
virtual float msecsPerFrame() const = 0;
virtual status_t getPosition(uint32_t *position) = 0;
+ virtual int getSessionId() = 0;
// If no callback is specified, use the "write" API below to submit
// audio data.
diff --git a/include/media/Metadata.h b/include/media/Metadata.h
index 241868a..9c915ce 100644
--- a/include/media/Metadata.h
+++ b/include/media/Metadata.h
@@ -91,6 +91,7 @@
static const Type kPauseAvailable = 29; // Boolean
static const Type kSeekBackwardAvailable = 30; // Boolean
static const Type kSeekForwardAvailable = 31; // Boolean
+ static const Type kSeekAvailable = 32; // Boolean
// @param p[inout] The parcel to append the metadata records
// to. The global metadata header should have been set already.
diff --git a/include/media/stagefright/AudioPlayer.h b/include/media/stagefright/AudioPlayer.h
index ed2f7d7..37af032 100644
--- a/include/media/stagefright/AudioPlayer.h
+++ b/include/media/stagefright/AudioPlayer.h
@@ -49,11 +49,9 @@
status_t start(bool sourceAlreadyStarted = false);
- void pause();
+ void pause(bool playPendingSamples = false);
void resume();
- void stop();
-
// Returns the timestamp of the last buffer played (in us).
int64_t getMediaTimeUs();
@@ -107,6 +105,8 @@
int64_t getRealTimeUsLocked() const;
+ void reset();
+
AudioPlayer(const AudioPlayer &);
AudioPlayer &operator=(const AudioPlayer &);
};
diff --git a/include/media/stagefright/MediaErrors.h b/include/media/stagefright/MediaErrors.h
index 73d0f77..e44122d 100644
--- a/include/media/stagefright/MediaErrors.h
+++ b/include/media/stagefright/MediaErrors.h
@@ -39,6 +39,7 @@
// Not technically an error.
INFO_FORMAT_CHANGED = MEDIA_ERROR_BASE - 12,
+ INFO_DISCONTINUITY = MEDIA_ERROR_BASE - 13,
};
} // namespace android
diff --git a/include/media/stagefright/MediaExtractor.h b/include/media/stagefright/MediaExtractor.h
index 21338ca..16b0a4c 100644
--- a/include/media/stagefright/MediaExtractor.h
+++ b/include/media/stagefright/MediaExtractor.h
@@ -45,13 +45,14 @@
virtual sp<MetaData> getMetaData();
enum Flags {
- CAN_SEEK_BACKWARD = 1,
- CAN_SEEK_FORWARD = 2,
+ CAN_SEEK_BACKWARD = 1, // the "seek 10secs back button"
+ CAN_SEEK_FORWARD = 2, // the "seek 10secs forward button"
CAN_PAUSE = 4,
+ CAN_SEEK = 8, // the "seek bar"
};
// If subclasses do _not_ override this, the default is
- // CAN_SEEK_BACKWARD | CAN_SEEK_FORWARD | CAN_PAUSE
+ // CAN_SEEK_BACKWARD | CAN_SEEK_FORWARD | CAN_SEEK | CAN_PAUSE
virtual uint32_t flags() const;
protected:
diff --git a/include/media/stagefright/MetaData.h b/include/media/stagefright/MetaData.h
index ab2f11d..d2bd9f2 100644
--- a/include/media/stagefright/MetaData.h
+++ b/include/media/stagefright/MetaData.h
@@ -97,6 +97,8 @@
kKeyAutoLoop = 'autL', // bool (int32_t)
kKeyValidSamples = 'valD', // int32_t
+
+ kKeyIsUnreadable = 'unre', // bool (int32_t)
};
enum {
diff --git a/include/media/stagefright/OMXCodec.h b/include/media/stagefright/OMXCodec.h
index 875bc5b..2bb7783 100644
--- a/include/media/stagefright/OMXCodec.h
+++ b/include/media/stagefright/OMXCodec.h
@@ -32,7 +32,8 @@
struct OMXCodec : public MediaSource,
public MediaBufferObserver {
enum CreationFlags {
- kPreferSoftwareCodecs = 1,
+ kPreferSoftwareCodecs = 1,
+ kIgnoreCodecSpecificData = 2
};
static sp<MediaSource> Create(
const sp<IOMX> &omx,
@@ -103,6 +104,7 @@
kSupportsMultipleFramesPerInputBuffer = 1024,
kAvoidMemcopyInputRecordingFrames = 2048,
kRequiresLargerEncoderOutputBuffer = 4096,
+ kOutputBuffersAreUnreadable = 8192,
};
struct BufferInfo {
@@ -247,9 +249,10 @@
void dumpPortStatus(OMX_U32 portIndex);
- status_t configureCodec(const sp<MetaData> &meta);
+ status_t configureCodec(const sp<MetaData> &meta, uint32_t flags);
- static uint32_t getComponentQuirks(const char *componentName);
+ static uint32_t getComponentQuirks(
+ const char *componentName, bool isEncoder);
static void findMatchingCodecs(
const char *mime,
diff --git a/include/ui/InputDispatcher.h b/include/ui/InputDispatcher.h
index cc16012..47c5326 100644
--- a/include/ui/InputDispatcher.h
+++ b/include/ui/InputDispatcher.h
@@ -212,8 +212,15 @@
int32_t ownerPid;
int32_t ownerUid;
- bool visibleFrameIntersects(const InputWindow* other) const;
bool touchableAreaContainsPoint(int32_t x, int32_t y) const;
+ bool frameContainsPoint(int32_t x, int32_t y) const;
+
+ /* Returns true if the window is of a trusted type that is allowed to silently
+ * overlay other windows for the purpose of implementing the secure views feature.
+ * Trusted overlays, such as IME windows, can partly obscure other windows without causing
+ * motion events to be delivered to them with AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED.
+ */
+ bool isTrustedOverlay() const;
};
@@ -962,7 +969,7 @@
bool shouldPokeUserActivityForCurrentInputTargetsLocked();
void pokeUserActivityLocked(nsecs_t eventTime, int32_t eventType);
bool checkInjectionPermission(const InputWindow* window, const InjectionState* injectionState);
- bool isWindowObscuredLocked(const InputWindow* window);
+ bool isWindowObscuredAtPointLocked(const InputWindow* window, int32_t x, int32_t y) const;
bool isWindowFinishedWithPreviousInputLocked(const InputWindow* window);
String8 getApplicationWindowLabelLocked(const InputApplication* application,
const InputWindow* window);
diff --git a/include/utils/Looper.h b/include/utils/Looper.h
index 3f00b78..cc51490 100644
--- a/include/utils/Looper.h
+++ b/include/utils/Looper.h
@@ -20,9 +20,22 @@
#include <utils/threads.h>
#include <utils/RefBase.h>
#include <utils/KeyedVector.h>
+#include <utils/Timers.h>
#include <android/looper.h>
+// Currently using poll() instead of epoll_wait() since it does a better job of meeting a
+// timeout deadline. epoll_wait() typically causes additional delays of up to 10ms
+// beyond the requested timeout.
+//#define LOOPER_USES_EPOLL
+//#define LOOPER_STATISTICS
+
+#ifdef LOOPER_USES_EPOLL
+#include <sys/epoll.h>
+#else
+#include <sys/poll.h>
+#endif
+
/*
* Declare a concrete type for the NDK's looper forward declaration.
*/
@@ -190,13 +203,54 @@
const bool mAllowNonCallbacks; // immutable
- int mEpollFd; // immutable
int mWakeReadPipeFd; // immutable
int mWakeWritePipeFd; // immutable
+ Mutex mLock;
+
+#ifdef LOOPER_USES_EPOLL
+ int mEpollFd; // immutable
// Locked list of file descriptor monitoring requests.
- Mutex mLock;
- KeyedVector<int, Request> mRequests;
+ KeyedVector<int, Request> mRequests; // guarded by mLock
+#else
+ // The lock guards state used to track whether there is a poll() in progress and whether
+ // there are any other threads waiting in wakeAndLock(). The condition variables
+ // are used to transfer control among these threads such that all waiters are
+ // serviced before a new poll can begin.
+ // The wakeAndLock() method increments mWaiters, wakes the poll, blocks on mAwake
+ // until mPolling becomes false, then decrements mWaiters again.
+ // The poll() method blocks on mResume until mWaiters becomes 0, then sets
+ // mPolling to true, blocks until the poll completes, then resets mPolling to false
+ // and signals mResume if there are waiters.
+ bool mPolling; // guarded by mLock
+ uint32_t mWaiters; // guarded by mLock
+ Condition mAwake; // guarded by mLock
+ Condition mResume; // guarded by mLock
+
+ Vector<struct pollfd> mRequestedFds; // must hold mLock and mPolling must be false to modify
+ Vector<Request> mRequests; // must hold mLock and mPolling must be false to modify
+
+ ssize_t getRequestIndexLocked(int fd);
+ void wakeAndLock();
+#endif
+
+#ifdef LOOPER_STATISTICS
+ static const int SAMPLED_WAKE_CYCLES_TO_AGGREGATE = 100;
+ static const int SAMPLED_POLLS_TO_AGGREGATE = 1000;
+
+ nsecs_t mPendingWakeTime;
+ int mPendingWakeCount;
+
+ int mSampledWakeCycles;
+ int mSampledWakeCountSum;
+ nsecs_t mSampledWakeLatencySum;
+
+ int mSampledPolls;
+ int mSampledZeroPollCount;
+ int mSampledZeroPollLatencySum;
+ int mSampledTimeoutPollCount;
+ int mSampledTimeoutPollLatencySum;
+#endif
// This state is only used privately by pollOnce and does not require a lock since
// it runs on a single thread.
@@ -204,6 +258,8 @@
size_t mResponseIndex;
int pollInner(int timeoutMillis);
+ void awoken();
+ void pushResponse(int events, const Request& request);
static void initTLSKey();
static void threadDestructor(void *st);
diff --git a/keystore/java/android/security/Credentials.java b/keystore/java/android/security/Credentials.java
index 43042c0b..ef19579 100644
--- a/keystore/java/android/security/Credentials.java
+++ b/keystore/java/android/security/Credentials.java
@@ -80,9 +80,16 @@
}
}
+ private Intent createInstallIntent() {
+ Intent intent = new Intent(INSTALL_ACTION);
+ intent.setClassName("com.android.certinstaller",
+ "com.android.certinstaller.CertInstallerMain");
+ return intent;
+ }
+
public void install(Context context, KeyPair pair) {
try {
- Intent intent = new Intent(INSTALL_ACTION);
+ Intent intent = createInstallIntent();
intent.putExtra(PRIVATE_KEY, pair.getPrivate().getEncoded());
intent.putExtra(PUBLIC_KEY, pair.getPublic().getEncoded());
context.startActivity(intent);
@@ -93,7 +100,7 @@
public void install(Context context, String type, byte[] value) {
try {
- Intent intent = new Intent(INSTALL_ACTION);
+ Intent intent = createInstallIntent();
intent.putExtra(type, value);
context.startActivity(intent);
} catch (ActivityNotFoundException e) {
@@ -103,7 +110,7 @@
public void installFromSdCard(Context context) {
try {
- context.startActivity(new Intent(INSTALL_ACTION));
+ context.startActivity(createInstallIntent());
} catch (ActivityNotFoundException e) {
Log.w(LOGTAG, e.toString());
}
diff --git a/libs/ui/InputDispatcher.cpp b/libs/ui/InputDispatcher.cpp
index aa54f82..fe8555d 100644
--- a/libs/ui/InputDispatcher.cpp
+++ b/libs/ui/InputDispatcher.cpp
@@ -134,18 +134,21 @@
// --- InputWindow ---
-bool InputWindow::visibleFrameIntersects(const InputWindow* other) const {
- return visibleFrameRight > other->visibleFrameLeft
- && visibleFrameLeft < other->visibleFrameRight
- && visibleFrameBottom > other->visibleFrameTop
- && visibleFrameTop < other->visibleFrameBottom;
-}
-
bool InputWindow::touchableAreaContainsPoint(int32_t x, int32_t y) const {
return x >= touchableAreaLeft && x <= touchableAreaRight
&& y >= touchableAreaTop && y <= touchableAreaBottom;
}
+bool InputWindow::frameContainsPoint(int32_t x, int32_t y) const {
+ return x >= frameLeft && x <= frameRight
+ && y >= frameTop && y <= frameBottom;
+}
+
+bool InputWindow::isTrustedOverlay() const {
+ return layoutParamsType == TYPE_INPUT_METHOD
+ || layoutParamsType == TYPE_INPUT_METHOD_DIALOG;
+}
+
// --- InputDispatcher ---
@@ -1053,8 +1056,12 @@
if (maskedAction == AMOTION_EVENT_ACTION_DOWN
&& (flags & InputWindow::FLAG_WATCH_OUTSIDE_TOUCH)) {
- mTempTouchState.addOrUpdateWindow(window,
- InputTarget::FLAG_OUTSIDE, BitSet32(0));
+ int32_t outsideTargetFlags = InputTarget::FLAG_OUTSIDE;
+ if (isWindowObscuredAtPointLocked(window, x, y)) {
+ outsideTargetFlags |= InputTarget::FLAG_WINDOW_IS_OBSCURED;
+ }
+
+ mTempTouchState.addOrUpdateWindow(window, outsideTargetFlags, BitSet32(0));
}
}
}
@@ -1083,10 +1090,6 @@
// (May be NULL which is why we put this code block before the next check.)
newTouchedWindow = mTempTouchState.getFirstForegroundWindow();
}
- int32_t targetFlags = InputTarget::FLAG_FOREGROUND;
- if (isSplit) {
- targetFlags |= InputTarget::FLAG_SPLIT;
- }
// If we did not find a touched window then fail.
if (! newTouchedWindow) {
@@ -1106,6 +1109,15 @@
goto Failed;
}
+ // Set target flags.
+ int32_t targetFlags = InputTarget::FLAG_FOREGROUND;
+ if (isSplit) {
+ targetFlags |= InputTarget::FLAG_SPLIT;
+ }
+ if (isWindowObscuredAtPointLocked(newTouchedWindow, x, y)) {
+ targetFlags |= InputTarget::FLAG_WINDOW_IS_OBSCURED;
+ }
+
// Update the temporary touch state.
BitSet32 pointerIds;
if (isSplit) {
@@ -1186,23 +1198,13 @@
for (size_t i = 0; i < mWindows.size(); i++) {
const InputWindow* window = & mWindows[i];
if (window->layoutParamsType == InputWindow::TYPE_WALLPAPER) {
- mTempTouchState.addOrUpdateWindow(window, 0, BitSet32(0));
+ mTempTouchState.addOrUpdateWindow(window,
+ InputTarget::FLAG_WINDOW_IS_OBSCURED, BitSet32(0));
}
}
}
}
- // If a touched window has been obscured at any point during the touch gesture, set
- // the appropriate flag so we remember it for the entire gesture.
- for (size_t i = 0; i < mTempTouchState.windows.size(); i++) {
- TouchedWindow& touchedWindow = mTempTouchState.windows.editItemAt(i);
- if ((touchedWindow.targetFlags & InputTarget::FLAG_WINDOW_IS_OBSCURED) == 0) {
- if (isWindowObscuredLocked(touchedWindow.window)) {
- touchedWindow.targetFlags |= InputTarget::FLAG_WINDOW_IS_OBSCURED;
- }
- }
- }
-
// Success! Output targets.
injectionResult = INPUT_EVENT_INJECTION_SUCCEEDED;
@@ -1326,14 +1328,15 @@
return true;
}
-bool InputDispatcher::isWindowObscuredLocked(const InputWindow* window) {
+bool InputDispatcher::isWindowObscuredAtPointLocked(
+ const InputWindow* window, int32_t x, int32_t y) const {
size_t numWindows = mWindows.size();
for (size_t i = 0; i < numWindows; i++) {
const InputWindow* other = & mWindows.itemAt(i);
if (other == window) {
break;
}
- if (other->visible && window->visibleFrameIntersects(other)) {
+ if (other->visible && ! other->isTrustedOverlay() && other->frameContainsPoint(x, y)) {
return true;
}
}
diff --git a/libs/ui/InputReader.cpp b/libs/ui/InputReader.cpp
index 8e173aa..7adc764 100644
--- a/libs/ui/InputReader.cpp
+++ b/libs/ui/InputReader.cpp
@@ -2447,7 +2447,7 @@
yPrecision = mLocked.orientedYPrecision;
} // release lock
- getDispatcher()->notifyMotion(when, getDeviceId(), AINPUT_SOURCE_TOUCHSCREEN, policyFlags,
+ getDispatcher()->notifyMotion(when, getDeviceId(), getSources(), policyFlags,
motionEventAction, 0, getContext()->getGlobalMetaState(), motionEventEdgeFlags,
pointerCount, pointerIds, pointerCoords,
xPrecision, yPrecision, mDownTime);
diff --git a/libs/utils/Looper.cpp b/libs/utils/Looper.cpp
index d2dd6eb..a5363d6 100644
--- a/libs/utils/Looper.cpp
+++ b/libs/utils/Looper.cpp
@@ -19,16 +19,17 @@
#include <unistd.h>
#include <fcntl.h>
-#include <sys/epoll.h>
namespace android {
+#ifdef LOOPER_USES_EPOLL
// Hint for number of file descriptors to be associated with the epoll instance.
static const int EPOLL_SIZE_HINT = 8;
// Maximum number of file descriptors for which to retrieve poll events each iteration.
static const int EPOLL_MAX_EVENTS = 16;
+#endif
static pthread_once_t gTLSOnce = PTHREAD_ONCE_INIT;
static pthread_key_t gTLSKey = 0;
@@ -36,9 +37,6 @@
Looper::Looper(bool allowNonCallbacks) :
mAllowNonCallbacks(allowNonCallbacks),
mResponseIndex(0) {
- mEpollFd = epoll_create(EPOLL_SIZE_HINT);
- LOG_ALWAYS_FATAL_IF(mEpollFd < 0, "Could not create epoll instance. errno=%d", errno);
-
int wakeFds[2];
int result = pipe(wakeFds);
LOG_ALWAYS_FATAL_IF(result != 0, "Could not create wake pipe. errno=%d", errno);
@@ -54,6 +52,11 @@
LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake write pipe non-blocking. errno=%d",
errno);
+#ifdef LOOPER_USES_EPOLL
+ // Allocate the epoll instance and register the wake pipe.
+ mEpollFd = epoll_create(EPOLL_SIZE_HINT);
+ LOG_ALWAYS_FATAL_IF(mEpollFd < 0, "Could not create epoll instance. errno=%d", errno);
+
struct epoll_event eventItem;
memset(& eventItem, 0, sizeof(epoll_event)); // zero out unused members of data field union
eventItem.events = EPOLLIN;
@@ -61,12 +64,45 @@
result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeReadPipeFd, & eventItem);
LOG_ALWAYS_FATAL_IF(result != 0, "Could not add wake read pipe to epoll instance. errno=%d",
errno);
+#else
+ // Add the wake pipe to the head of the request list with a null callback.
+ struct pollfd requestedFd;
+ requestedFd.fd = mWakeReadPipeFd;
+ requestedFd.events = POLLIN;
+ mRequestedFds.push(requestedFd);
+
+ Request request;
+ request.fd = mWakeReadPipeFd;
+ request.callback = NULL;
+ request.ident = 0;
+ request.data = NULL;
+ mRequests.push(request);
+
+ mPolling = false;
+ mWaiters = 0;
+#endif
+
+#ifdef LOOPER_STATISTICS
+ mPendingWakeTime = -1;
+ mPendingWakeCount = 0;
+ mSampledWakeCycles = 0;
+ mSampledWakeCountSum = 0;
+ mSampledWakeLatencySum = 0;
+
+ mSampledPolls = 0;
+ mSampledZeroPollCount = 0;
+ mSampledZeroPollLatencySum = 0;
+ mSampledTimeoutPollCount = 0;
+ mSampledTimeoutPollLatencySum = 0;
+#endif
}
Looper::~Looper() {
close(mWakeReadPipeFd);
close(mWakeWritePipeFd);
+#ifdef LOOPER_USES_EPOLL
close(mEpollFd);
+#endif
}
void Looper::initTLSKey() {
@@ -157,45 +193,61 @@
#if DEBUG_POLL_AND_WAKE
LOGD("%p ~ pollOnce - waiting: timeoutMillis=%d", this, timeoutMillis);
#endif
+
+ int result = ALOOPER_POLL_WAKE;
+ mResponses.clear();
+ mResponseIndex = 0;
+
+#ifdef LOOPER_STATISTICS
+ nsecs_t pollStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+#endif
+
+#ifdef LOOPER_USES_EPOLL
struct epoll_event eventItems[EPOLL_MAX_EVENTS];
int eventCount = epoll_wait(mEpollFd, eventItems, EPOLL_MAX_EVENTS, timeoutMillis);
+ bool acquiredLock = false;
+#else
+ // Wait for wakeAndLock() waiters to run then set mPolling to true.
+ mLock.lock();
+ while (mWaiters != 0) {
+ mResume.wait(mLock);
+ }
+ mPolling = true;
+ mLock.unlock();
+
+ size_t requestedCount = mRequestedFds.size();
+ int eventCount = poll(mRequestedFds.editArray(), requestedCount, timeoutMillis);
+#endif
+
if (eventCount < 0) {
if (errno == EINTR) {
- return ALOOPER_POLL_WAKE;
+ goto Done;
}
LOGW("Poll failed with an unexpected error, errno=%d", errno);
- return ALOOPER_POLL_ERROR;
+ result = ALOOPER_POLL_ERROR;
+ goto Done;
}
if (eventCount == 0) {
#if DEBUG_POLL_AND_WAKE
LOGD("%p ~ pollOnce - timeout", this);
#endif
- return ALOOPER_POLL_TIMEOUT;
+ result = ALOOPER_POLL_TIMEOUT;
+ goto Done;
}
- int result = ALOOPER_POLL_WAKE;
- mResponses.clear();
- mResponseIndex = 0;
-
#if DEBUG_POLL_AND_WAKE
LOGD("%p ~ pollOnce - handling events from %d fds", this, eventCount);
#endif
- bool acquiredLock = false;
+
+#ifdef LOOPER_USES_EPOLL
for (int i = 0; i < eventCount; i++) {
int fd = eventItems[i].data.fd;
uint32_t epollEvents = eventItems[i].events;
if (fd == mWakeReadPipeFd) {
if (epollEvents & EPOLLIN) {
-#if DEBUG_POLL_AND_WAKE
- LOGD("%p ~ pollOnce - awoken", this);
-#endif
- char buffer[16];
- ssize_t nRead;
- do {
- nRead = read(mWakeReadPipeFd, buffer, sizeof(buffer));
- } while ((nRead == -1 && errno == EINTR) || nRead == sizeof(buffer));
+ awoken();
} else {
LOGW("Ignoring unexpected epoll events 0x%x on wake read pipe.", epollEvents);
}
@@ -212,11 +264,7 @@
if (epollEvents & EPOLLOUT) events |= ALOOPER_EVENT_OUTPUT;
if (epollEvents & EPOLLERR) events |= ALOOPER_EVENT_ERROR;
if (epollEvents & EPOLLHUP) events |= ALOOPER_EVENT_HANGUP;
-
- Response response;
- response.events = events;
- response.request = mRequests.valueAt(requestIndex);
- mResponses.push(response);
+ pushResponse(events, mRequests.valueAt(requestIndex));
} else {
LOGW("Ignoring unexpected epoll events 0x%x on fd %d that is "
"no longer registered.", epollEvents, fd);
@@ -226,6 +274,66 @@
if (acquiredLock) {
mLock.unlock();
}
+Done: ;
+#else
+ for (size_t i = 0; i < requestedCount; i++) {
+ const struct pollfd& requestedFd = mRequestedFds.itemAt(i);
+
+ short pollEvents = requestedFd.revents;
+ if (pollEvents) {
+ if (requestedFd.fd == mWakeReadPipeFd) {
+ if (pollEvents & POLLIN) {
+ awoken();
+ } else {
+ LOGW("Ignoring unexpected poll events 0x%x on wake read pipe.", pollEvents);
+ }
+ } else {
+ int events = 0;
+ if (pollEvents & POLLIN) events |= ALOOPER_EVENT_INPUT;
+ if (pollEvents & POLLOUT) events |= ALOOPER_EVENT_OUTPUT;
+ if (pollEvents & POLLERR) events |= ALOOPER_EVENT_ERROR;
+ if (pollEvents & POLLHUP) events |= ALOOPER_EVENT_HANGUP;
+ if (pollEvents & POLLNVAL) events |= ALOOPER_EVENT_INVALID;
+ pushResponse(events, mRequests.itemAt(i));
+ }
+ if (--eventCount == 0) {
+ break;
+ }
+ }
+ }
+
+Done:
+ // Set mPolling to false and wake up the wakeAndLock() waiters.
+ mLock.lock();
+ mPolling = false;
+ if (mWaiters != 0) {
+ mAwake.broadcast();
+ }
+ mLock.unlock();
+#endif
+
+#ifdef LOOPER_STATISTICS
+ nsecs_t pollEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ mSampledPolls += 1;
+ if (timeoutMillis == 0) {
+ mSampledZeroPollCount += 1;
+ mSampledZeroPollLatencySum += pollEndTime - pollStartTime;
+ } else if (timeoutMillis > 0 && result == ALOOPER_POLL_TIMEOUT) {
+ mSampledTimeoutPollCount += 1;
+ mSampledTimeoutPollLatencySum += pollEndTime - pollStartTime
+ - milliseconds_to_nanoseconds(timeoutMillis);
+ }
+ if (mSampledPolls == SAMPLED_POLLS_TO_AGGREGATE) {
+ LOGD("%p ~ poll latency statistics: %0.3fms zero timeout, %0.3fms non-zero timeout", this,
+ 0.000001f * float(mSampledZeroPollLatencySum) / mSampledZeroPollCount,
+ 0.000001f * float(mSampledTimeoutPollLatencySum) / mSampledTimeoutPollCount);
+ mSampledPolls = 0;
+ mSampledZeroPollCount = 0;
+ mSampledZeroPollLatencySum = 0;
+ mSampledTimeoutPollCount = 0;
+ mSampledTimeoutPollLatencySum = 0;
+ }
+#endif
for (size_t i = 0; i < mResponses.size(); i++) {
const Response& response = mResponses.itemAt(i);
@@ -278,6 +386,13 @@
LOGD("%p ~ wake", this);
#endif
+#ifdef LOOPER_STATISTICS
+ // FIXME: Possible race with awoken() but this code is for testing only and is rarely enabled.
+ if (mPendingWakeCount++ == 0) {
+ mPendingWakeTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ }
+#endif
+
ssize_t nWrite;
do {
nWrite = write(mWakeWritePipeFd, "W", 1);
@@ -290,23 +405,51 @@
}
}
+void Looper::awoken() {
+#if DEBUG_POLL_AND_WAKE
+ LOGD("%p ~ awoken", this);
+#endif
+
+#ifdef LOOPER_STATISTICS
+ if (mPendingWakeCount == 0) {
+ LOGD("%p ~ awoken: spurious!", this);
+ } else {
+ mSampledWakeCycles += 1;
+ mSampledWakeCountSum += mPendingWakeCount;
+ mSampledWakeLatencySum += systemTime(SYSTEM_TIME_MONOTONIC) - mPendingWakeTime;
+ mPendingWakeCount = 0;
+ mPendingWakeTime = -1;
+ if (mSampledWakeCycles == SAMPLED_WAKE_CYCLES_TO_AGGREGATE) {
+ LOGD("%p ~ wake statistics: %0.3fms wake latency, %0.3f wakes per cycle", this,
+ 0.000001f * float(mSampledWakeLatencySum) / mSampledWakeCycles,
+ float(mSampledWakeCountSum) / mSampledWakeCycles);
+ mSampledWakeCycles = 0;
+ mSampledWakeCountSum = 0;
+ mSampledWakeLatencySum = 0;
+ }
+ }
+#endif
+
+ char buffer[16];
+ ssize_t nRead;
+ do {
+ nRead = read(mWakeReadPipeFd, buffer, sizeof(buffer));
+ } while ((nRead == -1 && errno == EINTR) || nRead == sizeof(buffer));
+}
+
+void Looper::pushResponse(int events, const Request& request) {
+ Response response;
+ response.events = events;
+ response.request = request;
+ mResponses.push(response);
+}
+
int Looper::addFd(int fd, int ident, int events, ALooper_callbackFunc callback, void* data) {
#if DEBUG_CALLBACKS
LOGD("%p ~ addFd - fd=%d, ident=%d, events=0x%x, callback=%p, data=%p", this, fd, ident,
events, callback, data);
#endif
- int epollEvents = 0;
- if (events & ALOOPER_EVENT_INPUT) epollEvents |= EPOLLIN;
- if (events & ALOOPER_EVENT_OUTPUT) epollEvents |= EPOLLOUT;
- if (events & ALOOPER_EVENT_ERROR) epollEvents |= EPOLLERR;
- if (events & ALOOPER_EVENT_HANGUP) epollEvents |= EPOLLHUP;
-
- if (epollEvents == 0) {
- LOGE("Invalid attempt to set a callback with no selected poll events.");
- return -1;
- }
-
if (! callback) {
if (! mAllowNonCallbacks) {
LOGE("Invalid attempt to set NULL callback but not allowed for this looper.");
@@ -319,6 +462,11 @@
}
}
+#ifdef LOOPER_USES_EPOLL
+ int epollEvents = 0;
+ if (events & ALOOPER_EVENT_INPUT) epollEvents |= EPOLLIN;
+ if (events & ALOOPER_EVENT_OUTPUT) epollEvents |= EPOLLOUT;
+
{ // acquire lock
AutoMutex _l(mLock);
@@ -350,6 +498,33 @@
mRequests.replaceValueAt(requestIndex, request);
}
} // release lock
+#else
+ int pollEvents = 0;
+ if (events & ALOOPER_EVENT_INPUT) pollEvents |= POLLIN;
+ if (events & ALOOPER_EVENT_OUTPUT) pollEvents |= POLLOUT;
+
+ wakeAndLock(); // acquire lock
+
+ struct pollfd requestedFd;
+ requestedFd.fd = fd;
+ requestedFd.events = pollEvents;
+
+ Request request;
+ request.fd = fd;
+ request.ident = ident;
+ request.callback = callback;
+ request.data = data;
+ ssize_t index = getRequestIndexLocked(fd);
+ if (index < 0) {
+ mRequestedFds.push(requestedFd);
+ mRequests.push(request);
+ } else {
+ mRequestedFds.replaceAt(requestedFd, size_t(index));
+ mRequests.replaceAt(request, size_t(index));
+ }
+
+ mLock.unlock(); // release lock
+#endif
return 1;
}
@@ -358,6 +533,7 @@
LOGD("%p ~ removeFd - fd=%d", this, fd);
#endif
+#ifdef LOOPER_USES_EPOLL
{ // acquire lock
AutoMutex _l(mLock);
ssize_t requestIndex = mRequests.indexOfKey(fd);
@@ -372,8 +548,49 @@
}
mRequests.removeItemsAt(requestIndex);
- } // request lock
+ } // release lock
return 1;
+#else
+ wakeAndLock(); // acquire lock
+
+ ssize_t index = getRequestIndexLocked(fd);
+ if (index >= 0) {
+ mRequestedFds.removeAt(size_t(index));
+ mRequests.removeAt(size_t(index));
+ }
+
+ mLock.unlock(); // release lock
+ return index >= 0;
+#endif
}
+#ifndef LOOPER_USES_EPOLL
+ssize_t Looper::getRequestIndexLocked(int fd) {
+ size_t requestCount = mRequestedFds.size();
+
+ for (size_t i = 0; i < requestCount; i++) {
+ if (mRequestedFds.itemAt(i).fd == fd) {
+ return i;
+ }
+ }
+
+ return -1;
+}
+
+void Looper::wakeAndLock() {
+ mLock.lock();
+
+ mWaiters += 1;
+ while (mPolling) {
+ wake();
+ mAwake.wait(mLock);
+ }
+
+ mWaiters -= 1;
+ if (mWaiters == 0) {
+ mResume.signal();
+ }
+}
+#endif
+
} // namespace android
diff --git a/libs/utils/tests/Looper_test.cpp b/libs/utils/tests/Looper_test.cpp
index afc92f8..cea1313 100644
--- a/libs/utils/tests/Looper_test.cpp
+++ b/libs/utils/tests/Looper_test.cpp
@@ -354,14 +354,6 @@
<< "addFd should return 1 because FD was added";
}
-TEST_F(LooperTest, AddFd_WhenEventsIsZero_ReturnsError) {
- Pipe pipe;
- int result = mLooper->addFd(pipe.receiveFd, 0, 0, NULL, NULL);
-
- EXPECT_EQ(-1, result)
- << "addFd should return -1 because arguments were invalid";
-}
-
TEST_F(LooperTest, AddFd_WhenIdentIsNegativeAndCallbackIsNull_ReturnsError) {
Pipe pipe;
int result = mLooper->addFd(pipe.receiveFd, -1, ALOOPER_EVENT_INPUT, NULL, NULL);
diff --git a/media/java/android/media/Metadata.java b/media/java/android/media/Metadata.java
index bd25da2..8d408c2 100644
--- a/media/java/android/media/Metadata.java
+++ b/media/java/android/media/Metadata.java
@@ -102,8 +102,9 @@
public static final int PAUSE_AVAILABLE = 29; // Boolean
public static final int SEEK_BACKWARD_AVAILABLE = 30; // Boolean
public static final int SEEK_FORWARD_AVAILABLE = 31; // Boolean
+ public static final int SEEK_AVAILABLE = 32; // Boolean
- private static final int LAST_SYSTEM = 31;
+ private static final int LAST_SYSTEM = 32;
private static final int FIRST_CUSTOM = 8192;
// Shorthands to set the MediaPlayer's metadata filter.
diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp
index 6f94e8b..49e5e89 100644
--- a/media/jni/android_media_MediaPlayer.cpp
+++ b/media/jni/android_media_MediaPlayer.cpp
@@ -727,7 +727,7 @@
}
static void android_media_MediaPlayer_attachAuxEffect(JNIEnv *env, jobject thiz, jint effectId) {
- LOGV("attachAuxEffect(): %d", sessionId);
+ LOGV("attachAuxEffect(): %d", effectId);
sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
if (mp == NULL ) {
jniThrowException(env, "java/lang/IllegalStateException", NULL);
diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp
index c6b2efb..cc41e66 100644
--- a/media/libmedia/mediaplayer.cpp
+++ b/media/libmedia/mediaplayer.cpp
@@ -56,6 +56,7 @@
mVideoWidth = mVideoHeight = 0;
mLockThreadId = 0;
mAudioSessionId = AudioSystem::newAudioSessionId();
+ mSendLevel = 0;
}
MediaPlayer::~MediaPlayer()
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index d975cb9..c43e9bb 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -1546,6 +1546,11 @@
}
+int MediaPlayerService::AudioOutput::getSessionId()
+{
+ return mSessionId;
+}
+
#undef LOG_TAG
#define LOG_TAG "AudioCache"
MediaPlayerService::AudioCache::AudioCache(const char* name) :
@@ -1733,4 +1738,9 @@
p->mSignal.signal();
}
+int MediaPlayerService::AudioCache::getSessionId()
+{
+ return 0;
+}
+
} // namespace android
diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h
index a967ee2..4492e20 100644
--- a/media/libmediaplayerservice/MediaPlayerService.h
+++ b/media/libmediaplayerservice/MediaPlayerService.h
@@ -77,6 +77,7 @@
virtual uint32_t latency() const;
virtual float msecsPerFrame() const;
virtual status_t getPosition(uint32_t *position);
+ virtual int getSessionId();
virtual status_t open(
uint32_t sampleRate, int channelCount,
@@ -133,6 +134,7 @@
virtual uint32_t latency() const;
virtual float msecsPerFrame() const;
virtual status_t getPosition(uint32_t *position);
+ virtual int getSessionId();
virtual status_t open(
uint32_t sampleRate, int channelCount, int format,
diff --git a/media/libmediaplayerservice/StagefrightPlayer.cpp b/media/libmediaplayerservice/StagefrightPlayer.cpp
index 2c96d6d..6bded09 100644
--- a/media/libmediaplayerservice/StagefrightPlayer.cpp
+++ b/media/libmediaplayerservice/StagefrightPlayer.cpp
@@ -180,6 +180,10 @@
Metadata::kSeekForwardAvailable,
flags & MediaExtractor::CAN_SEEK_FORWARD);
+ metadata.appendBool(
+ Metadata::kSeekAvailable,
+ flags & MediaExtractor::CAN_SEEK);
+
return OK;
}
diff --git a/media/libstagefright/AMRWriter.cpp b/media/libstagefright/AMRWriter.cpp
index 71d48b3..c0b1abe 100644
--- a/media/libstagefright/AMRWriter.cpp
+++ b/media/libstagefright/AMRWriter.cpp
@@ -15,7 +15,6 @@
*/
#include <media/stagefright/AMRWriter.h>
-
#include <media/stagefright/MediaBuffer.h>
#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaDefs.h>
@@ -23,6 +22,8 @@
#include <media/stagefright/MediaSource.h>
#include <media/stagefright/MetaData.h>
#include <media/mediarecorder.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
namespace android {
@@ -194,6 +195,7 @@
int64_t maxTimestampUs = 0;
status_t err = OK;
+ prctl(PR_SET_NAME, (unsigned long)"AMRWriter", 0, 0, 0);
while (!mDone) {
MediaBuffer *buffer;
err = mSource->read(&buffer);
diff --git a/media/libstagefright/AudioPlayer.cpp b/media/libstagefright/AudioPlayer.cpp
index b314114..5ff934d 100644
--- a/media/libstagefright/AudioPlayer.cpp
+++ b/media/libstagefright/AudioPlayer.cpp
@@ -55,7 +55,7 @@
AudioPlayer::~AudioPlayer() {
if (mStarted) {
- stop();
+ reset();
}
}
@@ -165,13 +165,21 @@
return OK;
}
-void AudioPlayer::pause() {
+void AudioPlayer::pause(bool playPendingSamples) {
CHECK(mStarted);
- if (mAudioSink.get() != NULL) {
- mAudioSink->pause();
+ if (playPendingSamples) {
+ if (mAudioSink.get() != NULL) {
+ mAudioSink->stop();
+ } else {
+ mAudioTrack->stop();
+ }
} else {
- mAudioTrack->stop();
+ if (mAudioSink.get() != NULL) {
+ mAudioSink->pause();
+ } else {
+ mAudioTrack->pause();
+ }
}
}
@@ -185,7 +193,7 @@
}
}
-void AudioPlayer::stop() {
+void AudioPlayer::reset() {
CHECK(mStarted);
if (mAudioSink.get() != NULL) {
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index 040e27d..53543b3 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -561,6 +561,39 @@
postBufferingEvent_l();
}
+void AwesomePlayer::partial_reset_l() {
+ // Only reset the video renderer and shut down the video decoder.
+ // Then instantiate a new video decoder and resume video playback.
+
+ mVideoRenderer.clear();
+
+ if (mLastVideoBuffer) {
+ mLastVideoBuffer->release();
+ mLastVideoBuffer = NULL;
+ }
+
+ if (mVideoBuffer) {
+ mVideoBuffer->release();
+ mVideoBuffer = NULL;
+ }
+
+ {
+ mVideoSource->stop();
+
+ // The following hack is necessary to ensure that the OMX
+ // component is completely released by the time we may try
+ // to instantiate it again.
+ wp<MediaSource> tmp = mVideoSource;
+ mVideoSource.clear();
+ while (tmp.promote() != NULL) {
+ usleep(1000);
+ }
+ IPCThreadState::self()->flushCommands();
+ }
+
+ CHECK_EQ(OK, initVideoDecoder(OMXCodec::kIgnoreCodecSpecificData));
+}
+
void AwesomePlayer::onStreamDone() {
// Posted whenever any stream finishes playing.
@@ -570,13 +603,27 @@
}
mStreamDoneEventPending = false;
- if (mStreamDoneStatus != ERROR_END_OF_STREAM) {
+ if (mStreamDoneStatus == INFO_DISCONTINUITY) {
+ // This special status is returned because an http live stream's
+ // video stream switched to a different bandwidth at this point
+ // and future data may have been encoded using different parameters.
+ // This requires us to shutdown the video decoder and reinstantiate
+ // a fresh one.
+
+ LOGV("INFO_DISCONTINUITY");
+
+ CHECK(mVideoSource != NULL);
+
+ partial_reset_l();
+ postVideoEvent_l();
+ return;
+ } else if (mStreamDoneStatus != ERROR_END_OF_STREAM) {
LOGV("MEDIA_ERROR %d", mStreamDoneStatus);
notifyListener_l(
MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, mStreamDoneStatus);
- pause_l();
+ pause_l(true /* at eos */);
mFlags |= AT_EOS;
return;
@@ -600,7 +647,7 @@
LOGV("MEDIA_PLAYBACK_COMPLETE");
notifyListener_l(MEDIA_PLAYBACK_COMPLETE);
- pause_l();
+ pause_l(true /* at eos */);
mFlags |= AT_EOS;
}
@@ -738,7 +785,7 @@
return pause_l();
}
-status_t AwesomePlayer::pause_l() {
+status_t AwesomePlayer::pause_l(bool at_eos) {
if (!(mFlags & PLAYING)) {
return OK;
}
@@ -746,7 +793,14 @@
cancelPlayerEvents(true /* keepBufferingGoing */);
if (mAudioPlayer != NULL) {
- mAudioPlayer->pause();
+ if (at_eos) {
+ // If we played the audio stream to completion we
+ // want to make sure that all samples remaining in the audio
+ // track's queue are played out.
+ mAudioPlayer->pause(true /* playPendingSamples */);
+ } else {
+ mAudioPlayer->pause();
+ }
}
mFlags &= ~PLAYING;
@@ -814,9 +868,7 @@
}
status_t AwesomePlayer::seekTo(int64_t timeUs) {
- if (mExtractorFlags
- & (MediaExtractor::CAN_SEEK_FORWARD
- | MediaExtractor::CAN_SEEK_BACKWARD)) {
+ if (mExtractorFlags & MediaExtractor::CAN_SEEK) {
Mutex::Autolock autoLock(mLock);
return seekTo_l(timeUs);
}
@@ -932,8 +984,7 @@
mVideoTrack = source;
}
-status_t AwesomePlayer::initVideoDecoder() {
- uint32_t flags = 0;
+status_t AwesomePlayer::initVideoDecoder(uint32_t flags) {
mVideoSource = OMXCodec::Create(
mClient.interface(), mVideoTrack->getFormat(),
false, // createEncoder
@@ -1564,21 +1615,30 @@
if (mLastVideoBuffer) {
size_t size = mLastVideoBuffer->range_length();
+
if (size) {
- state->mLastVideoFrameSize = size;
- state->mLastVideoFrame = malloc(size);
- memcpy(state->mLastVideoFrame,
- (const uint8_t *)mLastVideoBuffer->data()
- + mLastVideoBuffer->range_offset(),
- size);
+ int32_t unreadable;
+ if (!mLastVideoBuffer->meta_data()->findInt32(
+ kKeyIsUnreadable, &unreadable)
+ || unreadable == 0) {
+ state->mLastVideoFrameSize = size;
+ state->mLastVideoFrame = malloc(size);
+ memcpy(state->mLastVideoFrame,
+ (const uint8_t *)mLastVideoBuffer->data()
+ + mLastVideoBuffer->range_offset(),
+ size);
- state->mVideoWidth = mVideoWidth;
- state->mVideoHeight = mVideoHeight;
+ state->mVideoWidth = mVideoWidth;
+ state->mVideoHeight = mVideoHeight;
- sp<MetaData> meta = mVideoSource->getFormat();
- CHECK(meta->findInt32(kKeyColorFormat, &state->mColorFormat));
- CHECK(meta->findInt32(kKeyWidth, &state->mDecodedWidth));
- CHECK(meta->findInt32(kKeyHeight, &state->mDecodedHeight));
+ sp<MetaData> meta = mVideoSource->getFormat();
+ CHECK(meta->findInt32(kKeyColorFormat, &state->mColorFormat));
+ CHECK(meta->findInt32(kKeyWidth, &state->mDecodedWidth));
+ CHECK(meta->findInt32(kKeyHeight, &state->mDecodedHeight));
+ } else {
+ LOGV("Unable to save last video frame, we have no access to "
+ "the decoded video data.");
+ }
}
}
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index 6d00d7c..e53b0a0 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -20,8 +20,9 @@
#include <arpa/inet.h>
-#include <ctype.h>
#include <pthread.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
#include <media/stagefright/MPEG4Writer.h>
#include <media/stagefright/MediaBuffer.h>
@@ -1104,6 +1105,7 @@
void MPEG4Writer::threadFunc() {
LOGV("threadFunc");
+ prctl(PR_SET_NAME, (unsigned long)"MPEG4Writer", 0, 0, 0);
while (!mDone) {
{
Mutex::Autolock autolock(mLock);
@@ -1632,6 +1634,11 @@
int64_t previousPausedDurationUs = 0;
int64_t timestampUs;
+ if (mIsAudio) {
+ prctl(PR_SET_NAME, (unsigned long)"AudioTrackEncoding", 0, 0, 0);
+ } else {
+ prctl(PR_SET_NAME, (unsigned long)"VideoTrackEncoding", 0, 0, 0);
+ }
sp<MetaData> meta_data;
mNumSamples = 0;
diff --git a/media/libstagefright/MediaExtractor.cpp b/media/libstagefright/MediaExtractor.cpp
index 9bc94de..8a5fb11 100644
--- a/media/libstagefright/MediaExtractor.cpp
+++ b/media/libstagefright/MediaExtractor.cpp
@@ -41,7 +41,7 @@
}
uint32_t MediaExtractor::flags() const {
- return CAN_SEEK_BACKWARD | CAN_SEEK_FORWARD | CAN_PAUSE;
+ return CAN_SEEK_BACKWARD | CAN_SEEK_FORWARD | CAN_PAUSE | CAN_SEEK;
}
// static
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index 76c8870..4648ad3 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -346,7 +346,8 @@
}
// static
-uint32_t OMXCodec::getComponentQuirks(const char *componentName) {
+uint32_t OMXCodec::getComponentQuirks(
+ const char *componentName, bool isEncoder) {
uint32_t quirks = 0;
if (!strcmp(componentName, "OMX.PV.avcdec")) {
@@ -404,6 +405,13 @@
quirks |= kInputBufferSizesAreBogus;
}
+ if (!strncmp(componentName, "OMX.SEC.", 8) && !isEncoder) {
+ // These output buffers contain no video data, just some
+ // opaque information that allows the overlay to display their
+ // contents.
+ quirks |= kOutputBuffersAreUnreadable;
+ }
+
return quirks;
}
@@ -490,13 +498,13 @@
LOGV("Successfully allocated OMX node '%s'", componentName);
sp<OMXCodec> codec = new OMXCodec(
- omx, node, getComponentQuirks(componentName),
+ omx, node, getComponentQuirks(componentName, createEncoder),
createEncoder, mime, componentName,
source);
observer->setCodec(codec);
- err = codec->configureCodec(meta);
+ err = codec->configureCodec(meta, flags);
if (err == OK) {
return codec;
@@ -509,93 +517,95 @@
return NULL;
}
-status_t OMXCodec::configureCodec(const sp<MetaData> &meta) {
- uint32_t type;
- const void *data;
- size_t size;
- if (meta->findData(kKeyESDS, &type, &data, &size)) {
- ESDS esds((const char *)data, size);
- CHECK_EQ(esds.InitCheck(), OK);
+status_t OMXCodec::configureCodec(const sp<MetaData> &meta, uint32_t flags) {
+ if (!(flags & kIgnoreCodecSpecificData)) {
+ uint32_t type;
+ const void *data;
+ size_t size;
+ if (meta->findData(kKeyESDS, &type, &data, &size)) {
+ ESDS esds((const char *)data, size);
+ CHECK_EQ(esds.InitCheck(), OK);
- const void *codec_specific_data;
- size_t codec_specific_data_size;
- esds.getCodecSpecificInfo(
- &codec_specific_data, &codec_specific_data_size);
+ const void *codec_specific_data;
+ size_t codec_specific_data_size;
+ esds.getCodecSpecificInfo(
+ &codec_specific_data, &codec_specific_data_size);
- addCodecSpecificData(
- codec_specific_data, codec_specific_data_size);
- } else if (meta->findData(kKeyAVCC, &type, &data, &size)) {
- // Parse the AVCDecoderConfigurationRecord
+ addCodecSpecificData(
+ codec_specific_data, codec_specific_data_size);
+ } else if (meta->findData(kKeyAVCC, &type, &data, &size)) {
+ // Parse the AVCDecoderConfigurationRecord
- const uint8_t *ptr = (const uint8_t *)data;
+ const uint8_t *ptr = (const uint8_t *)data;
- CHECK(size >= 7);
- CHECK_EQ(ptr[0], 1); // configurationVersion == 1
- uint8_t profile = ptr[1];
- uint8_t level = ptr[3];
+ CHECK(size >= 7);
+ CHECK_EQ(ptr[0], 1); // configurationVersion == 1
+ uint8_t profile = ptr[1];
+ uint8_t level = ptr[3];
- // There is decodable content out there that fails the following
- // assertion, let's be lenient for now...
- // CHECK((ptr[4] >> 2) == 0x3f); // reserved
+ // There is decodable content out there that fails the following
+ // assertion, let's be lenient for now...
+ // CHECK((ptr[4] >> 2) == 0x3f); // reserved
- size_t lengthSize = 1 + (ptr[4] & 3);
+ size_t lengthSize = 1 + (ptr[4] & 3);
- // commented out check below as H264_QVGA_500_NO_AUDIO.3gp
- // violates it...
- // CHECK((ptr[5] >> 5) == 7); // reserved
+ // commented out check below as H264_QVGA_500_NO_AUDIO.3gp
+ // violates it...
+ // CHECK((ptr[5] >> 5) == 7); // reserved
- size_t numSeqParameterSets = ptr[5] & 31;
+ size_t numSeqParameterSets = ptr[5] & 31;
- ptr += 6;
- size -= 6;
+ ptr += 6;
+ size -= 6;
- for (size_t i = 0; i < numSeqParameterSets; ++i) {
- CHECK(size >= 2);
- size_t length = U16_AT(ptr);
+ for (size_t i = 0; i < numSeqParameterSets; ++i) {
+ CHECK(size >= 2);
+ size_t length = U16_AT(ptr);
- ptr += 2;
- size -= 2;
+ ptr += 2;
+ size -= 2;
- CHECK(size >= length);
+ CHECK(size >= length);
- addCodecSpecificData(ptr, length);
+ addCodecSpecificData(ptr, length);
- ptr += length;
- size -= length;
- }
+ ptr += length;
+ size -= length;
+ }
- CHECK(size >= 1);
- size_t numPictureParameterSets = *ptr;
- ++ptr;
- --size;
+ CHECK(size >= 1);
+ size_t numPictureParameterSets = *ptr;
+ ++ptr;
+ --size;
- for (size_t i = 0; i < numPictureParameterSets; ++i) {
- CHECK(size >= 2);
- size_t length = U16_AT(ptr);
+ for (size_t i = 0; i < numPictureParameterSets; ++i) {
+ CHECK(size >= 2);
+ size_t length = U16_AT(ptr);
- ptr += 2;
- size -= 2;
+ ptr += 2;
+ size -= 2;
- CHECK(size >= length);
+ CHECK(size >= length);
- addCodecSpecificData(ptr, length);
+ addCodecSpecificData(ptr, length);
- ptr += length;
- size -= length;
- }
+ ptr += length;
+ size -= length;
+ }
- CODEC_LOGV(
- "AVC profile = %d (%s), level = %d",
- (int)profile, AVCProfileToString(profile), level);
+ CODEC_LOGV(
+ "AVC profile = %d (%s), level = %d",
+ (int)profile, AVCProfileToString(profile), level);
- if (!strcmp(mComponentName, "OMX.TI.Video.Decoder")
- && (profile != kAVCProfileBaseline || level > 30)) {
- // This stream exceeds the decoder's capabilities. The decoder
- // does not handle this gracefully and would clobber the heap
- // and wreak havoc instead...
+ if (!strcmp(mComponentName, "OMX.TI.Video.Decoder")
+ && (profile != kAVCProfileBaseline || level > 30)) {
+ // This stream exceeds the decoder's capabilities. The decoder
+ // does not handle this gracefully and would clobber the heap
+ // and wreak havoc instead...
- LOGE("Profile and/or level exceed the decoder's capabilities.");
- return ERROR_UNSUPPORTED;
+ LOGE("Profile and/or level exceed the decoder's capabilities.");
+ return ERROR_UNSUPPORTED;
+ }
}
}
@@ -1747,6 +1757,10 @@
buffer->meta_data()->setInt32(kKeyIsCodecConfig, true);
}
+ if (mQuirks & kOutputBuffersAreUnreadable) {
+ buffer->meta_data()->setInt32(kKeyIsUnreadable, true);
+ }
+
buffer->meta_data()->setPointer(
kKeyPlatformPrivate,
msg.u.extended_buffer_data.platform_private);
diff --git a/media/libstagefright/StagefrightMetadataRetriever.cpp b/media/libstagefright/StagefrightMetadataRetriever.cpp
index 9d89c20..af9c70c 100644
--- a/media/libstagefright/StagefrightMetadataRetriever.cpp
+++ b/media/libstagefright/StagefrightMetadataRetriever.cpp
@@ -159,6 +159,20 @@
LOGV("successfully decoded video frame.");
+ int32_t unreadable;
+ if (buffer->meta_data()->findInt32(kKeyIsUnreadable, &unreadable)
+ && unreadable != 0) {
+ LOGV("video frame is unreadable, decoder does not give us access "
+ "to the video data.");
+
+ buffer->release();
+ buffer = NULL;
+
+ decoder->stop();
+
+ return NULL;
+ }
+
int64_t timeUs;
CHECK(buffer->meta_data()->findInt64(kKeyTime, &timeUs));
if (thumbNailTime >= 0) {
diff --git a/media/libstagefright/avc_utils.cpp b/media/libstagefright/avc_utils.cpp
index a8f1104..8762d29 100644
--- a/media/libstagefright/avc_utils.cpp
+++ b/media/libstagefright/avc_utils.cpp
@@ -41,10 +41,12 @@
br.skipBits(16);
parseUE(&br); // seq_parameter_set_id
+ unsigned chroma_format_idc = 1; // 4:2:0 chroma format
+
if (profile_idc == 100 || profile_idc == 110
|| profile_idc == 122 || profile_idc == 244
|| profile_idc == 44 || profile_idc == 83 || profile_idc == 86) {
- unsigned chroma_format_idc = parseUE(&br);
+ chroma_format_idc = parseUE(&br);
if (chroma_format_idc == 3) {
br.skipBits(1); // residual_colour_transform_flag
}
@@ -85,6 +87,41 @@
*height = (2 - frame_mbs_only_flag)
* (pic_height_in_map_units_minus1 * 16 + 16);
+
+ if (!frame_mbs_only_flag) {
+ br.getBits(1); // mb_adaptive_frame_field_flag
+ }
+
+ br.getBits(1); // direct_8x8_inference_flag
+
+ if (br.getBits(1)) { // frame_cropping_flag
+ unsigned frame_crop_left_offset = parseUE(&br);
+ unsigned frame_crop_right_offset = parseUE(&br);
+ unsigned frame_crop_top_offset = parseUE(&br);
+ unsigned frame_crop_bottom_offset = parseUE(&br);
+
+ unsigned cropUnitX, cropUnitY;
+ if (chroma_format_idc == 0 /* monochrome */) {
+ cropUnitX = 1;
+ cropUnitY = 2 - frame_mbs_only_flag;
+ } else {
+ unsigned subWidthC = (chroma_format_idc == 3) ? 1 : 2;
+ unsigned subHeightC = (chroma_format_idc == 1) ? 2 : 1;
+
+ cropUnitX = subWidthC;
+ cropUnitY = subHeightC * (2 - frame_mbs_only_flag);
+ }
+
+ LOGV("frame_crop = (%u, %u, %u, %u), cropUnitX = %u, cropUnitY = %u",
+ frame_crop_left_offset, frame_crop_right_offset,
+ frame_crop_top_offset, frame_crop_bottom_offset,
+ cropUnitX, cropUnitY);
+
+ *width -=
+ (frame_crop_left_offset + frame_crop_right_offset) * cropUnitX;
+ *height -=
+ (frame_crop_top_offset + frame_crop_bottom_offset) * cropUnitY;
+ }
}
} // namespace android
diff --git a/media/libstagefright/codecs/mp3dec/src/pvmp3_reorder.cpp b/media/libstagefright/codecs/mp3dec/src/pvmp3_reorder.cpp
index 35b6475..286c636 100644
--- a/media/libstagefright/codecs/mp3dec/src/pvmp3_reorder.cpp
+++ b/media/libstagefright/codecs/mp3dec/src/pvmp3_reorder.cpp
@@ -40,7 +40,7 @@
int32 xr[ ], rescaled data
struct gr_info_s *gr_info, granule structure
mp3Header *info, mp3 header info
- int32 Scratch_mem[168] for temporary usage
+ int32 Scratch_mem[198] for temporary usage
Outputs:
@@ -120,7 +120,7 @@
granuleInfo *gr_info,
int32 *used_freq_lines,
mp3Header *info,
- int32 Scratch_mem[168])
+ int32 Scratch_mem[198])
{
int32 sfreq = info->version_x + (info->version_x << 1);
sfreq += info->sampling_frequency;
diff --git a/media/libstagefright/codecs/mp3dec/src/pvmp3_reorder.h b/media/libstagefright/codecs/mp3dec/src/pvmp3_reorder.h
index ba6ec16..5248951 100644
--- a/media/libstagefright/codecs/mp3dec/src/pvmp3_reorder.h
+++ b/media/libstagefright/codecs/mp3dec/src/pvmp3_reorder.h
@@ -89,7 +89,7 @@
granuleInfo *gr_info,
int32 *used_freq_lines,
mp3Header *info,
- int32 Scratch_mem[168]);
+ int32 Scratch_mem[198]);
#ifdef __cplusplus
}
diff --git a/media/libstagefright/codecs/mp3dec/src/s_tmp3dec_file.h b/media/libstagefright/codecs/mp3dec/src/s_tmp3dec_file.h
index 805cedb..611e08f 100644
--- a/media/libstagefright/codecs/mp3dec/src/s_tmp3dec_file.h
+++ b/media/libstagefright/codecs/mp3dec/src/s_tmp3dec_file.h
@@ -87,7 +87,7 @@
int32 num_channels;
int32 predicted_frame_size;
int32 frame_start;
- int32 Scratch_mem[168];
+ int32 Scratch_mem[198];
tmp3dec_chan perChan[CHAN];
mp3ScaleFactors scaleFactors[CHAN];
mp3SideInfo sideInfo;
diff --git a/media/libstagefright/httplive/LiveSource.cpp b/media/libstagefright/httplive/LiveSource.cpp
index 9103927..943a0fc 100644
--- a/media/libstagefright/httplive/LiveSource.cpp
+++ b/media/libstagefright/httplive/LiveSource.cpp
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+//#define LOG_NDEBUG 0
#define LOG_TAG "LiveSource"
#include <utils/Log.h>
@@ -22,18 +23,21 @@
#include "include/NuHTTPDataSource.h"
#include <media/stagefright/foundation/ABuffer.h>
+#include <media/stagefright/FileSource.h>
#include <media/stagefright/MediaDebug.h>
namespace android {
LiveSource::LiveSource(const char *url)
- : mURL(url),
+ : mMasterURL(url),
mInitCheck(NO_INIT),
mPlaylistIndex(0),
mLastFetchTimeUs(-1),
mSource(new NuHTTPDataSource),
mSourceSize(0),
- mOffsetBias(0) {
+ mOffsetBias(0),
+ mSignalDiscontinuity(false),
+ mPrevBandwidthIndex(-1) {
if (switchToNext()) {
mInitCheck = OK;
}
@@ -46,21 +50,129 @@
return mInitCheck;
}
-bool LiveSource::loadPlaylist() {
+// static
+int LiveSource::SortByBandwidth(const BandwidthItem *a, const BandwidthItem *b) {
+ if (a->mBandwidth < b->mBandwidth) {
+ return -1;
+ } else if (a->mBandwidth == b->mBandwidth) {
+ return 0;
+ }
+
+ return 1;
+}
+
+static double uniformRand() {
+ return (double)rand() / RAND_MAX;
+}
+
+bool LiveSource::loadPlaylist(bool fetchMaster) {
+ mSignalDiscontinuity = false;
+
mPlaylist.clear();
mPlaylistIndex = 0;
- sp<ABuffer> buffer;
- status_t err = fetchM3U(mURL.c_str(), &buffer);
+ if (fetchMaster) {
+ mPrevBandwidthIndex = -1;
- if (err != OK) {
- return false;
+ sp<ABuffer> buffer;
+ status_t err = fetchM3U(mMasterURL.c_str(), &buffer);
+
+ if (err != OK) {
+ return false;
+ }
+
+ mPlaylist = new M3UParser(
+ mMasterURL.c_str(), buffer->data(), buffer->size());
+
+ if (mPlaylist->initCheck() != OK) {
+ return false;
+ }
+
+ if (mPlaylist->isVariantPlaylist()) {
+ for (size_t i = 0; i < mPlaylist->size(); ++i) {
+ BandwidthItem item;
+
+ sp<AMessage> meta;
+ mPlaylist->itemAt(i, &item.mURI, &meta);
+
+ unsigned long bandwidth;
+ CHECK(meta->findInt32("bandwidth", (int32_t *)&item.mBandwidth));
+
+ mBandwidthItems.push(item);
+ }
+ mPlaylist.clear();
+
+ // fall through
+ if (mBandwidthItems.size() == 0) {
+ return false;
+ }
+
+ mBandwidthItems.sort(SortByBandwidth);
+
+ for (size_t i = 0; i < mBandwidthItems.size(); ++i) {
+ const BandwidthItem &item = mBandwidthItems.itemAt(i);
+ LOGV("item #%d: %s", i, item.mURI.c_str());
+ }
+ }
}
- mPlaylist = new M3UParser(mURL.c_str(), buffer->data(), buffer->size());
+ if (mBandwidthItems.size() > 0) {
+#if 0
+ // Change bandwidth at random()
+ size_t index = uniformRand() * mBandwidthItems.size();
+#elif 0
+ // There's a 50% chance to stay on the current bandwidth and
+ // a 50% chance to switch to the next higher bandwidth (wrapping around
+ // to lowest)
+ size_t index;
+ if (uniformRand() < 0.5) {
+ index = mPrevBandwidthIndex < 0 ? 0 : (size_t)mPrevBandwidthIndex;
+ } else {
+ if (mPrevBandwidthIndex < 0) {
+ index = 0;
+ } else {
+ index = mPrevBandwidthIndex + 1;
+ if (index == mBandwidthItems.size()) {
+ index = 0;
+ }
+ }
+ }
+#else
+ // Stay on the lowest bandwidth available.
+ size_t index = 0; // Lowest bandwidth stream
+#endif
- if (mPlaylist->initCheck() != OK) {
- return false;
+ mURL = mBandwidthItems.editItemAt(index).mURI;
+
+ if (mPrevBandwidthIndex >= 0 && (size_t)mPrevBandwidthIndex != index) {
+ // If we switched streams because of bandwidth changes,
+ // we'll signal this discontinuity by inserting a
+ // special transport stream packet into the stream.
+ mSignalDiscontinuity = true;
+ }
+
+ mPrevBandwidthIndex = index;
+ } else {
+ mURL = mMasterURL;
+ }
+
+ if (mPlaylist == NULL) {
+ sp<ABuffer> buffer;
+ status_t err = fetchM3U(mURL.c_str(), &buffer);
+
+ if (err != OK) {
+ return false;
+ }
+
+ mPlaylist = new M3UParser(mURL.c_str(), buffer->data(), buffer->size());
+
+ if (mPlaylist->initCheck() != OK) {
+ return false;
+ }
+
+ if (mPlaylist->isVariantPlaylist()) {
+ return false;
+ }
}
if (!mPlaylist->meta()->findInt32(
@@ -79,6 +191,8 @@
}
bool LiveSource::switchToNext() {
+ mSignalDiscontinuity = false;
+
mOffsetBias += mSourceSize;
mSourceSize = 0;
@@ -87,7 +201,7 @@
int32_t nextSequenceNumber =
mPlaylistIndex + mFirstItemSequenceNumber;
- if (!loadPlaylist()) {
+ if (!loadPlaylist(mLastFetchTimeUs < 0)) {
LOGE("failed to reload playlist");
return false;
}
@@ -111,35 +225,62 @@
}
AString uri;
- CHECK(mPlaylist->itemAt(mPlaylistIndex, &uri));
- LOGI("switching to %s", uri.c_str());
+ sp<AMessage> itemMeta;
+ CHECK(mPlaylist->itemAt(mPlaylistIndex, &uri, &itemMeta));
+ LOGV("switching to %s", uri.c_str());
if (mSource->connect(uri.c_str()) != OK
|| mSource->getSize(&mSourceSize) != OK) {
return false;
}
+ int32_t val;
+ if (itemMeta->findInt32("discontinuity", &val) && val != 0) {
+ mSignalDiscontinuity = true;
+ }
+
mPlaylistIndex++;
return true;
}
+static const ssize_t kHeaderSize = 188;
+
ssize_t LiveSource::readAt(off_t offset, void *data, size_t size) {
CHECK(offset >= mOffsetBias);
offset -= mOffsetBias;
- if (offset >= mSourceSize) {
- CHECK_EQ(offset, mSourceSize);
+ off_t delta = mSignalDiscontinuity ? kHeaderSize : 0;
- offset -= mSourceSize;
+ if (offset >= mSourceSize + delta) {
+ CHECK_EQ(offset, mSourceSize + delta);
+
+ offset -= mSourceSize + delta;
if (!switchToNext()) {
return ERROR_END_OF_STREAM;
}
+
+ if (mSignalDiscontinuity) {
+ LOGV("switchToNext changed streams");
+ } else {
+ LOGV("switchToNext stayed within the same stream");
+ }
+
+ mOffsetBias += delta;
+
+ delta = mSignalDiscontinuity ? kHeaderSize : 0;
+ }
+
+ if (offset < delta) {
+ size_t avail = delta - offset;
+ memset(data, 0, avail);
+ return avail;
}
size_t numRead = 0;
while (numRead < size) {
ssize_t n = mSource->readAt(
- offset + numRead, (uint8_t *)data + numRead, size - numRead);
+ offset + numRead - delta,
+ (uint8_t *)data + numRead, size - numRead);
if (n <= 0) {
break;
@@ -154,14 +295,24 @@
status_t LiveSource::fetchM3U(const char *url, sp<ABuffer> *out) {
*out = NULL;
- status_t err = mSource->connect(url);
+ sp<DataSource> source;
- if (err != OK) {
- return err;
+ if (!strncasecmp(url, "file://", 7)) {
+ source = new FileSource(url + 7);
+ } else {
+ CHECK(!strncasecmp(url, "http://", 7));
+
+ status_t err = mSource->connect(url);
+
+ if (err != OK) {
+ return err;
+ }
+
+ source = mSource;
}
off_t size;
- err = mSource->getSize(&size);
+ status_t err = source->getSize(&size);
if (err != OK) {
return err;
@@ -170,7 +321,7 @@
sp<ABuffer> buffer = new ABuffer(size);
size_t offset = 0;
while (offset < (size_t)size) {
- ssize_t n = mSource->readAt(
+ ssize_t n = source->readAt(
offset, buffer->data() + offset, size - offset);
if (n <= 0) {
diff --git a/media/libstagefright/httplive/M3UParser.cpp b/media/libstagefright/httplive/M3UParser.cpp
index edd8648..0d7daa9 100644
--- a/media/libstagefright/httplive/M3UParser.cpp
+++ b/media/libstagefright/httplive/M3UParser.cpp
@@ -74,7 +74,8 @@
static bool MakeURL(const char *baseURL, const char *url, AString *out) {
out->clear();
- if (strncasecmp("http://", baseURL, 7)) {
+ if (strncasecmp("http://", baseURL, 7)
+ && strncasecmp("file://", baseURL, 7)) {
// Base URL must be absolute
return false;
}
@@ -128,7 +129,12 @@
line.setTo(&data[offset], offsetLF - offset);
}
- LOGI("#%s#", line.c_str());
+ // LOGI("#%s#", line.c_str());
+
+ if (line.empty()) {
+ offset = offsetLF + 1;
+ continue;
+ }
if (lineNo == 0 && line == "#EXTM3U") {
mIsExtM3U = true;
@@ -152,11 +158,20 @@
return ERROR_MALFORMED;
}
err = parseMetaData(line, &itemMeta, "duration");
+ } else if (line.startsWith("#EXT-X-DISCONTINUITY")) {
+ if (mIsVariantPlaylist) {
+ return ERROR_MALFORMED;
+ }
+ if (itemMeta == NULL) {
+ itemMeta = new AMessage;
+ }
+ itemMeta->setInt32("discontinuity", true);
} else if (line.startsWith("#EXT-X-STREAM-INF")) {
if (mMeta != NULL) {
return ERROR_MALFORMED;
}
mIsVariantPlaylist = true;
+ err = parseStreamInf(line, &itemMeta);
}
if (err != OK) {
@@ -215,6 +230,61 @@
}
// static
+status_t M3UParser::parseStreamInf(
+ const AString &line, sp<AMessage> *meta) {
+ ssize_t colonPos = line.find(":");
+
+ if (colonPos < 0) {
+ return ERROR_MALFORMED;
+ }
+
+ size_t offset = colonPos + 1;
+
+ while (offset < line.size()) {
+ ssize_t end = line.find(",", offset);
+ if (end < 0) {
+ end = line.size();
+ }
+
+ AString attr(line, offset, end - offset);
+ attr.trim();
+
+ offset = end + 1;
+
+ ssize_t equalPos = attr.find("=");
+ if (equalPos < 0) {
+ continue;
+ }
+
+ AString key(attr, 0, equalPos);
+ key.trim();
+
+ AString val(attr, equalPos + 1, attr.size() - equalPos - 1);
+ val.trim();
+
+ LOGV("key=%s value=%s", key.c_str(), val.c_str());
+
+ if (!strcasecmp("bandwidth", key.c_str())) {
+ const char *s = val.c_str();
+ char *end;
+ unsigned long x = strtoul(s, &end, 10);
+
+ if (end == s || *end != '\0') {
+ // malformed
+ continue;
+ }
+
+ if (meta->get() == NULL) {
+ *meta = new AMessage;
+ }
+ (*meta)->setInt32("bandwidth", x);
+ }
+ }
+
+ return OK;
+}
+
+// static
status_t M3UParser::ParseInt32(const char *s, int32_t *x) {
char *end;
long lval = strtol(s, &end, 10);
diff --git a/media/libstagefright/include/ARTSPController.h b/media/libstagefright/include/ARTSPController.h
index 300d8f7..c2f3090 100644
--- a/media/libstagefright/include/ARTSPController.h
+++ b/media/libstagefright/include/ARTSPController.h
@@ -46,6 +46,14 @@
void onMessageReceived(const sp<AMessage> &msg);
+ virtual uint32_t flags() const {
+ // Seeking 10secs forward or backward is a very expensive operation
+ // for rtsp, so let's not enable that.
+ // The user can always use the seek bar.
+
+ return CAN_PAUSE | CAN_SEEK;
+ }
+
protected:
virtual ~ARTSPController();
diff --git a/media/libstagefright/include/AwesomePlayer.h b/media/libstagefright/include/AwesomePlayer.h
index 600faca..bbf482d 100644
--- a/media/libstagefright/include/AwesomePlayer.h
+++ b/media/libstagefright/include/AwesomePlayer.h
@@ -220,8 +220,9 @@
status_t setDataSource_l(const sp<DataSource> &dataSource);
status_t setDataSource_l(const sp<MediaExtractor> &extractor);
void reset_l();
+ void partial_reset_l();
status_t seekTo_l(int64_t timeUs);
- status_t pause_l();
+ status_t pause_l(bool at_eos = false);
void initRenderer_l();
void seekAudioIfNecessary_l();
@@ -231,7 +232,7 @@
status_t initAudioDecoder();
void setVideoSource(sp<MediaSource> source);
- status_t initVideoDecoder();
+ status_t initVideoDecoder(uint32_t flags = 0);
void onStreamDone();
diff --git a/media/libstagefright/include/LiveSource.h b/media/libstagefright/include/LiveSource.h
index c55508c..5e89581 100644
--- a/media/libstagefright/include/LiveSource.h
+++ b/media/libstagefright/include/LiveSource.h
@@ -44,6 +44,13 @@
virtual ~LiveSource();
private:
+ struct BandwidthItem {
+ AString mURI;
+ unsigned long mBandwidth;
+ };
+ Vector<BandwidthItem> mBandwidthItems;
+
+ AString mMasterURL;
AString mURL;
status_t mInitCheck;
@@ -56,10 +63,15 @@
off_t mSourceSize;
off_t mOffsetBias;
+ bool mSignalDiscontinuity;
+ ssize_t mPrevBandwidthIndex;
+
status_t fetchM3U(const char *url, sp<ABuffer> *buffer);
+ static int SortByBandwidth(const BandwidthItem *a, const BandwidthItem *b);
+
bool switchToNext();
- bool loadPlaylist();
+ bool loadPlaylist(bool fetchMaster);
DISALLOW_EVIL_CONSTRUCTORS(LiveSource);
};
diff --git a/media/libstagefright/include/M3UParser.h b/media/libstagefright/include/M3UParser.h
index 36553de..69199ab 100644
--- a/media/libstagefright/include/M3UParser.h
+++ b/media/libstagefright/include/M3UParser.h
@@ -61,6 +61,9 @@
static status_t parseMetaData(
const AString &line, sp<AMessage> *meta, const char *key);
+ static status_t parseStreamInf(
+ const AString &line, sp<AMessage> *meta);
+
static status_t ParseInt32(const char *s, int32_t *x);
DISALLOW_EVIL_CONSTRUCTORS(M3UParser);
diff --git a/media/libstagefright/mpeg2ts/ATSParser.cpp b/media/libstagefright/mpeg2ts/ATSParser.cpp
index bcaab9f..7c9b83a 100644
--- a/media/libstagefright/mpeg2ts/ATSParser.cpp
+++ b/media/libstagefright/mpeg2ts/ATSParser.cpp
@@ -49,6 +49,8 @@
unsigned pid, unsigned payload_unit_start_indicator,
ABitReader *br);
+ void signalDiscontinuity();
+
sp<MediaSource> getSource(SourceType type);
private:
@@ -67,6 +69,8 @@
unsigned payload_unit_start_indicator,
ABitReader *br);
+ void signalDiscontinuity();
+
sp<MediaSource> getSource(SourceType type);
protected:
@@ -124,6 +128,12 @@
return true;
}
+void ATSParser::Program::signalDiscontinuity() {
+ for (size_t i = 0; i < mStreams.size(); ++i) {
+ mStreams.editValueAt(i)->signalDiscontinuity();
+ }
+}
+
void ATSParser::Program::parseProgramMap(ABitReader *br) {
unsigned table_id = br->getBits(8);
LOGV(" table_id = %u", table_id);
@@ -271,6 +281,19 @@
mBuffer->setRange(0, mBuffer->size() + payloadSizeBits / 8);
}
+void ATSParser::Stream::signalDiscontinuity() {
+ LOGV("Stream discontinuity");
+ mPayloadStarted = false;
+ mBuffer->setRange(0, 0);
+
+ mQueue.clear();
+
+ if (mStreamType == 0x1b && mSource != NULL) {
+ // Don't signal discontinuities on audio streams.
+ mSource->queueDiscontinuity();
+ }
+}
+
void ATSParser::Stream::parsePES(ABitReader *br) {
unsigned packet_startcode_prefix = br->getBits(24);
@@ -459,7 +482,10 @@
mSource = new AnotherPacketSource(meta);
mSource->queueAccessUnit(accessUnit);
}
- } else {
+ } else if (mQueue.getFormat() != NULL) {
+ // After a discontinuity we invalidate the queue's format
+ // and won't enqueue any access units to the source until
+ // the queue has reestablished the new format.
mSource->queueAccessUnit(accessUnit);
}
}
@@ -489,6 +515,12 @@
parseTS(&br);
}
+void ATSParser::signalDiscontinuity() {
+ for (size_t i = 0; i < mPrograms.size(); ++i) {
+ mPrograms.editItemAt(i)->signalDiscontinuity();
+ }
+}
+
void ATSParser::parseProgramAssociationTable(ABitReader *br) {
unsigned table_id = br->getBits(8);
LOGV(" table_id = %u", table_id);
diff --git a/media/libstagefright/mpeg2ts/ATSParser.h b/media/libstagefright/mpeg2ts/ATSParser.h
index 1e22e7b..9ec6d7b 100644
--- a/media/libstagefright/mpeg2ts/ATSParser.h
+++ b/media/libstagefright/mpeg2ts/ATSParser.h
@@ -33,6 +33,7 @@
ATSParser();
void feedTSPacket(const void *data, size_t size);
+ void signalDiscontinuity();
enum SourceType {
AVC_VIDEO,
diff --git a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
index 3d51177..3f76820 100644
--- a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
+++ b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
@@ -59,21 +59,26 @@
if (!mBuffers.empty()) {
const sp<ABuffer> buffer = *mBuffers.begin();
-
- uint64_t timeUs;
- CHECK(buffer->meta()->findInt64(
- "time", (int64_t *)&timeUs));
-
- MediaBuffer *mediaBuffer = new MediaBuffer(buffer->size());
- mediaBuffer->meta_data()->setInt64(kKeyTime, timeUs);
-
- // hexdump(buffer->data(), buffer->size());
-
- memcpy(mediaBuffer->data(), buffer->data(), buffer->size());
- *out = mediaBuffer;
-
mBuffers.erase(mBuffers.begin());
- return OK;
+
+ int32_t discontinuity;
+ if (buffer->meta()->findInt32("discontinuity", &discontinuity)
+ && discontinuity) {
+ return INFO_DISCONTINUITY;
+ } else {
+ uint64_t timeUs;
+ CHECK(buffer->meta()->findInt64(
+ "time", (int64_t *)&timeUs));
+
+ MediaBuffer *mediaBuffer = new MediaBuffer(buffer->size());
+ mediaBuffer->meta_data()->setInt64(kKeyTime, timeUs);
+
+ // hexdump(buffer->data(), buffer->size());
+
+ memcpy(mediaBuffer->data(), buffer->data(), buffer->size());
+ *out = mediaBuffer;
+ return OK;
+ }
}
return mEOSResult;
@@ -91,6 +96,15 @@
mCondition.signal();
}
+void AnotherPacketSource::queueDiscontinuity() {
+ sp<ABuffer> buffer = new ABuffer(0);
+ buffer->meta()->setInt32("discontinuity", true);
+
+ Mutex::Autolock autoLock(mLock);
+ mBuffers.push_back(buffer);
+ mCondition.signal();
+}
+
void AnotherPacketSource::signalEOS(status_t result) {
CHECK(result != OK);
diff --git a/media/libstagefright/mpeg2ts/AnotherPacketSource.h b/media/libstagefright/mpeg2ts/AnotherPacketSource.h
index ce83d21..6b43c4e 100644
--- a/media/libstagefright/mpeg2ts/AnotherPacketSource.h
+++ b/media/libstagefright/mpeg2ts/AnotherPacketSource.h
@@ -40,6 +40,7 @@
bool hasBufferAvailable(status_t *finalResult);
void queueAccessUnit(const sp<ABuffer> &buffer);
+ void queueDiscontinuity();
void signalEOS(status_t result);
protected:
diff --git a/media/libstagefright/mpeg2ts/ESQueue.cpp b/media/libstagefright/mpeg2ts/ESQueue.cpp
index d87040b..4a75ee4 100644
--- a/media/libstagefright/mpeg2ts/ESQueue.cpp
+++ b/media/libstagefright/mpeg2ts/ESQueue.cpp
@@ -115,6 +115,11 @@
return OK;
}
+void ElementaryStreamQueue::clear() {
+ mBuffer->setRange(0, 0);
+ mFormat.clear();
+}
+
status_t ElementaryStreamQueue::appendData(
const void *data, size_t size, int64_t timeUs) {
if (mBuffer == NULL || mBuffer->size() == 0) {
@@ -147,7 +152,7 @@
if (mBuffer == NULL || neededSize > mBuffer->capacity()) {
neededSize = (neededSize + 65535) & ~65535;
- LOGI("resizing buffer to size %d", neededSize);
+ LOGV("resizing buffer to size %d", neededSize);
sp<ABuffer> buffer = new ABuffer(neededSize);
if (mBuffer != NULL) {
@@ -498,6 +503,8 @@
meta->setInt32(kKeyWidth, width);
meta->setInt32(kKeyHeight, height);
+ LOGI("found AVC codec config (%d x %d)", width, height);
+
return meta;
}
diff --git a/media/libstagefright/mpeg2ts/ESQueue.h b/media/libstagefright/mpeg2ts/ESQueue.h
index d2e87f2..246c390 100644
--- a/media/libstagefright/mpeg2ts/ESQueue.h
+++ b/media/libstagefright/mpeg2ts/ESQueue.h
@@ -35,6 +35,7 @@
ElementaryStreamQueue(Mode mode);
status_t appendData(const void *data, size_t size, int64_t timeUs);
+ void clear();
sp<ABuffer> dequeueAccessUnit();
diff --git a/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp b/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp
index c5257bb..0d96bd1 100644
--- a/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp
+++ b/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp
@@ -165,18 +165,26 @@
LOGI("haveAudio=%d, haveVideo=%d", haveAudio, haveVideo);
}
+static bool isDiscontinuity(const uint8_t *data, ssize_t size) {
+ return size == 188 && data[0] == 0x00;
+}
+
status_t MPEG2TSExtractor::feedMore() {
Mutex::Autolock autoLock(mLock);
uint8_t packet[kTSPacketSize];
ssize_t n = mDataSource->readAt(mOffset, packet, kTSPacketSize);
- if (n < (ssize_t)kTSPacketSize) {
+ if (isDiscontinuity(packet, n)) {
+ LOGI("XXX discontinuity detected");
+ mParser->signalDiscontinuity();
+ } else if (n < (ssize_t)kTSPacketSize) {
return (n < 0) ? (status_t)n : ERROR_END_OF_STREAM;
+ } else {
+ mParser->feedTSPacket(packet, kTSPacketSize);
}
- mOffset += kTSPacketSize;
- mParser->feedTSPacket(packet, kTSPacketSize);
+ mOffset += n;
return OK;
}
diff --git a/media/libstagefright/rtsp/MyHandler.h b/media/libstagefright/rtsp/MyHandler.h
index a31b2b2..2c9cfd3 100644
--- a/media/libstagefright/rtsp/MyHandler.h
+++ b/media/libstagefright/rtsp/MyHandler.h
@@ -86,6 +86,7 @@
mFirstAccessUnitNTP(0),
mNumAccessUnitsReceived(0),
mCheckPending(false),
+ mCheckGeneration(0),
mTryTCPInterleaving(false),
mReceivedFirstRTCPPacket(false) {
mNetLooper->setName("rtsp net");
@@ -434,6 +435,13 @@
case 'chek':
{
+ int32_t generation;
+ CHECK(msg->findInt32("generation", &generation));
+ if (generation != mCheckGeneration) {
+ // This is an outdated message. Ignore.
+ break;
+ }
+
if (mNumAccessUnitsReceived == 0) {
LOGI("stream ended? aborting.");
(new AMessage('abor', id()))->post();
@@ -454,12 +462,7 @@
}
++mNumAccessUnitsReceived;
-
- if (!mCheckPending) {
- mCheckPending = true;
- sp<AMessage> check = new AMessage('chek', id());
- check->post(kAccessUnitTimeoutUs);
- }
+ postAccessUnitTimeoutCheck();
size_t trackIndex;
CHECK(msg->findSize("track-index", &trackIndex));
@@ -557,6 +560,11 @@
mSeekPending = true;
+ // Disable the access unit timeout until we resumed
+ // playback again.
+ mCheckPending = true;
+ ++mCheckGeneration;
+
AString request = "PAUSE ";
request.append(mSessionURL);
request.append(" RTSP/1.0\r\n");
@@ -612,6 +620,9 @@
LOGI("PLAY completed with result %d (%s)",
result, strerror(-result));
+ mCheckPending = false;
+ postAccessUnitTimeoutCheck();
+
if (result == OK) {
sp<RefBase> obj;
CHECK(msg->findObject("response", &obj));
@@ -674,6 +685,17 @@
}
}
+ void postAccessUnitTimeoutCheck() {
+ if (mCheckPending) {
+ return;
+ }
+
+ mCheckPending = true;
+ sp<AMessage> check = new AMessage('chek', id());
+ check->setInt32("generation", mCheckGeneration);
+ check->post(kAccessUnitTimeoutUs);
+ }
+
static void SplitString(
const AString &s, const char *separator, List<AString> *items) {
items->clear();
@@ -783,6 +805,7 @@
uint64_t mFirstAccessUnitNTP;
int64_t mNumAccessUnitsReceived;
bool mCheckPending;
+ int32_t mCheckGeneration;
bool mTryTCPInterleaving;
bool mReceivedFirstRTCPPacket;
diff --git a/native/include/android/looper.h b/native/include/android/looper.h
index a63b744..a9d8426 100644
--- a/native/include/android/looper.h
+++ b/native/include/android/looper.h
@@ -135,6 +135,15 @@
* to specify this event flag in the requested event set.
*/
ALOOPER_EVENT_HANGUP = 1 << 3,
+
+ /**
+ * The file descriptor is invalid.
+ * For example, the file descriptor was closed prematurely.
+ *
+ * The looper always sends notifications about invalid file descriptors; it is not necessary
+ * to specify this event flag in the requested event set.
+ */
+ ALOOPER_EVENT_INVALID = 1 << 4,
};
/**
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_1x.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_1x.png
index 3fe08c2..818e292 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_1x.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_1x.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_e.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_e.png
index 1a69d13..016b30b 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_e.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_e.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_g.png
index 09094d1..ec672eb 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_g.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_h.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_h.png
index 0f64e0f..27bab73 100755
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_h.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_h.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_connected_1x.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_connected_1x.png
index 90454b0..0e6849b 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_connected_1x.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_connected_1x.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_connected_3g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_connected_3g.png
index 5524e26..a86a324 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_connected_3g.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_connected_3g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_connected_e.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_connected_e.png
index a43c233..24902d6 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_connected_e.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_connected_e.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_connected_g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_connected_g.png
index 03a06a0..4160a95 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_connected_g.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_connected_g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_connected_h.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_connected_h.png
index be7eed4..d459ee3 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_connected_h.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_connected_h.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_in_1x.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_in_1x.png
index 2d77956..7b64751 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_in_1x.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_in_1x.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_in_3g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_in_3g.png
index a8411fc6..d82930c 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_in_3g.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_in_3g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_in_e.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_in_e.png
index ae90cc8..8096846 100755
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_in_e.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_in_e.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_in_g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_in_g.png
index b135a81..e94e146 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_in_g.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_in_g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_in_h.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_in_h.png
index 9ef67d1d..8805a40 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_in_h.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_in_h.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_inandout_1x.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_inandout_1x.png
index c9196b2..07545d5 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_inandout_1x.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_inandout_1x.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_inandout_3g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_inandout_3g.png
index f7dda73..7629cef 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_inandout_3g.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_inandout_3g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_inandout_e.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_inandout_e.png
index cf17eea..28578c6 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_inandout_e.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_inandout_e.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_inandout_g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_inandout_g.png
index 9e0d73c..d9f7a30 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_inandout_g.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_inandout_g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_inandout_h.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_inandout_h.png
index c506f75..505ccd4 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_inandout_h.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_inandout_h.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_out_1x.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_out_1x.png
index 6258164..783c2b6 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_out_1x.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_out_1x.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_out_3g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_out_3g.png
index eb5150f..001eaea 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_out_3g.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_out_3g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_out_e.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_out_e.png
index 2496714..cbae7dc 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_out_e.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_out_e.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_out_g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_out_g.png
index 4aba1b1..11f3a5c 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_out_g.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_out_g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_out_h.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_out_h.png
index 3624a8d..eb42294 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_out_h.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_out_h.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_in_1x.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_in_1x.png
index 720f578..66fb60e 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_in_1x.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_in_1x.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_in_e.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_in_e.png
index f8779a6..e39767a 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_in_e.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_in_e.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_in_g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_in_g.png
index f6fe4b2..47c1fca 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_in_g.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_in_g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_in_h.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_in_h.png
index 393963f..ac80dce 100755
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_in_h.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_in_h.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_inandout_1x.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_inandout_1x.png
index abe961a..f88091b 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_inandout_1x.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_inandout_1x.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_inandout_e.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_inandout_e.png
index e6e9df4..0ef4701 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_inandout_e.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_inandout_e.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_inandout_g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_inandout_g.png
index a14e8d6..31b926b 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_inandout_g.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_inandout_g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_inandout_h.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_inandout_h.png
index 404afff..ed02984 100755
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_inandout_h.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_inandout_h.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_out_1x.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_out_1x.png
index a47a482..0ee5b08 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_out_1x.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_out_1x.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_out_e.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_out_e.png
index 41e86cc..df6e195 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_out_e.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_out_e.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_out_g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_out_g.png
index 6c4203d..4a2f867 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_out_g.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_out_g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_out_h.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_out_h.png
index 9927dbf..2b4628f 100755
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_out_h.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_out_h.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_gps_acquiring.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_gps_acquiring.png
index 56943ea..c43fc3b 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_gps_acquiring.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_gps_acquiring.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_0.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_0.png
index 95ba181..1ef75d3 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_0.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_0.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_0_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_0_fully.png
index 95ba181..1ef75d3 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_0_fully.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_0_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_1.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_1.png
index adf668d..a7dc07e 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_1.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_1.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_1_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_1_fully.png
index eeb7f67..f1f4c4e 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_1_fully.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_1_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_2.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_2.png
index 7bf6b51..918a476 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_2.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_2.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_2_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_2_fully.png
index aee093a..6e34e66 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_2_fully.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_2_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_3.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_3.png
index 78738ac..5b2acc6 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_3.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_3.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_3_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_3_fully.png
index a40017f..3664ab4 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_3_fully.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_3_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_4.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_4.png
index ac88143..f1ff548 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_4.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_4.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_4_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_4_fully.png
index c3b44ee..b4fa481 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_4_fully.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_4_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml
index c3f4205..c744e4b 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded.xml
@@ -71,7 +71,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fadingEdge="none"
- android:overscrollMode="ifContentScrolls"
+ android:overScrollMode="ifContentScrolls"
>
<com.android.systemui.statusbar.NotificationLinearLayout
android:id="@+id/notificationLinearLayout"
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarView.java
index 1e140b9..117b126 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarView.java
@@ -42,10 +42,6 @@
View mDate;
FixedSizeDrawable mBackground;
- boolean mNightMode = false;
- int mStartAlpha = 0, mEndAlpha = 0;
- long mEndTime = 0;
-
public StatusBarView(Context context, AttributeSet attrs) {
super(context, attrs);
}
@@ -69,29 +65,6 @@
}
@Override
- protected void onConfigurationChanged(Configuration newConfig) {
- super.onConfigurationChanged(newConfig);
- boolean nightMode = (newConfig.uiMode & Configuration.UI_MODE_NIGHT_MASK)
- == Configuration.UI_MODE_NIGHT_YES;
- if (mNightMode != nightMode) {
- mNightMode = nightMode;
- mStartAlpha = getCurAlpha();
- mEndAlpha = mNightMode ? 0x80 : 0x00;
- mEndTime = SystemClock.uptimeMillis() + DIM_ANIM_TIME;
- invalidate();
- }
- }
-
- int getCurAlpha() {
- long time = SystemClock.uptimeMillis();
- if (time > mEndTime) {
- return mEndAlpha;
- }
- return mEndAlpha
- - (int)(((mEndAlpha-mStartAlpha) * (mEndTime-time) / DIM_ANIM_TIME));
- }
-
- @Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mService.updateExpandedViewPos(StatusBarService.EXPANDED_LEAVE_ALONE);
@@ -127,18 +100,6 @@
mBackground.setFixedBounds(-mDate.getLeft(), -mDate.getTop(), (r-l), (b-t));
}
- @Override
- protected void dispatchDraw(Canvas canvas) {
- super.dispatchDraw(canvas);
- int alpha = getCurAlpha();
- if (alpha != 0) {
- canvas.drawARGB(alpha, 0, 0, 0);
- }
- if (alpha != mEndAlpha) {
- invalidate();
- }
- }
-
/**
* Gets the left position of v in this view. Throws if v is not
* a child of this.
diff --git a/packages/SystemUI/src/com/android/systemui/usb/UsbStorageActivity.java b/packages/SystemUI/src/com/android/systemui/usb/UsbStorageActivity.java
index 29df28e..d024dd0 100644
--- a/packages/SystemUI/src/com/android/systemui/usb/UsbStorageActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/usb/UsbStorageActivity.java
@@ -46,6 +46,7 @@
import android.widget.TextView;
import android.view.View;
import android.view.Window;
+import android.view.WindowManager;
import android.util.Log;
import java.util.List;
@@ -102,6 +103,11 @@
requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
setProgressBarIndeterminateVisibility(true);
+ getWindow().addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
+ if (Environment.isExternalStorageRemovable()) {
+ getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
+ }
+
setTitle(getString(com.android.internal.R.string.usb_storage_activity_title));
setContentView(com.android.internal.R.layout.usb_storage_activity);
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 8527059..cd9b07e 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -1715,7 +1715,7 @@
// The first time a track is added we wait
// for all its buffers to be filled before processing it
mAudioMixer->setActiveTrack(track->name());
- if (cblk->framesReady() && (track->isReady() || track->isStopped()) &&
+ if (cblk->framesReady() && track->isReady() &&
!track->isPaused() && !track->isTerminated())
{
//LOGV("track %d u=%08x, s=%08x [OK] on thread %p", track->name(), cblk->user, cblk->server, this);
@@ -2231,7 +2231,7 @@
// The first time a track is added we wait
// for all its buffers to be filled before processing it
- if (cblk->framesReady() && (track->isReady() || track->isStopped()) &&
+ if (cblk->framesReady() && track->isReady() &&
!track->isPaused() && !track->isTerminated())
{
//LOGV("track %d u=%08x, s=%08x [OK]", track->name(), cblk->user, cblk->server);
@@ -3039,7 +3039,7 @@
}
bool AudioFlinger::PlaybackThread::Track::isReady() const {
- if (mFillingUpStatus != FS_FILLING) return true;
+ if (mFillingUpStatus != FS_FILLING || isStopped() || isPausing()) return true;
if (mCblk->framesReady() >= mCblk->frameCount ||
(mCblk->flags & CBLK_FORCEREADY_MSK)) {
diff --git a/services/java/com/android/server/AlarmManagerService.java b/services/java/com/android/server/AlarmManagerService.java
index e088417..4e2f1e3 100644
--- a/services/java/com/android/server/AlarmManagerService.java
+++ b/services/java/com/android/server/AlarmManagerService.java
@@ -38,9 +38,11 @@
import android.text.format.Time;
import android.util.EventLog;
import android.util.Slog;
+import android.util.TimeUtils;
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
@@ -456,25 +458,28 @@
synchronized (mLock) {
pw.println("Current Alarm Manager state:");
if (mRtcWakeupAlarms.size() > 0 || mRtcAlarms.size() > 0) {
+ final long now = System.currentTimeMillis();
+ SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
pw.println(" ");
pw.print(" Realtime wakeup (now=");
- pw.print(System.currentTimeMillis()); pw.println("):");
+ pw.print(sdf.format(new Date(now))); pw.println("):");
if (mRtcWakeupAlarms.size() > 0) {
- dumpAlarmList(pw, mRtcWakeupAlarms, " ", "RTC_WAKEUP");
+ dumpAlarmList(pw, mRtcWakeupAlarms, " ", "RTC_WAKEUP", now);
}
if (mRtcAlarms.size() > 0) {
- dumpAlarmList(pw, mRtcAlarms, " ", "RTC");
+ dumpAlarmList(pw, mRtcAlarms, " ", "RTC", now);
}
}
if (mElapsedRealtimeWakeupAlarms.size() > 0 || mElapsedRealtimeAlarms.size() > 0) {
+ final long now = SystemClock.elapsedRealtime();
pw.println(" ");
pw.print(" Elapsed realtime wakeup (now=");
- pw.print(SystemClock.elapsedRealtime()); pw.println("):");
+ TimeUtils.formatDuration(now, pw); pw.println("):");
if (mElapsedRealtimeWakeupAlarms.size() > 0) {
- dumpAlarmList(pw, mElapsedRealtimeWakeupAlarms, " ", "ELAPSED_WAKEUP");
+ dumpAlarmList(pw, mElapsedRealtimeWakeupAlarms, " ", "ELAPSED_WAKEUP", now);
}
if (mElapsedRealtimeAlarms.size() > 0) {
- dumpAlarmList(pw, mElapsedRealtimeAlarms, " ", "ELAPSED");
+ dumpAlarmList(pw, mElapsedRealtimeAlarms, " ", "ELAPSED", now);
}
}
@@ -499,12 +504,13 @@
}
}
- private static final void dumpAlarmList(PrintWriter pw, ArrayList<Alarm> list, String prefix, String label) {
+ private static final void dumpAlarmList(PrintWriter pw, ArrayList<Alarm> list,
+ String prefix, String label, long now) {
for (int i=list.size()-1; i>=0; i--) {
Alarm a = list.get(i);
pw.print(prefix); pw.print(label); pw.print(" #"); pw.print(i);
pw.print(": "); pw.println(a);
- a.dump(pw, prefix + " ");
+ a.dump(pw, prefix + " ", now);
}
}
@@ -619,10 +625,9 @@
return sb.toString();
}
- public void dump(PrintWriter pw, String prefix)
- {
+ public void dump(PrintWriter pw, String prefix, long now) {
pw.print(prefix); pw.print("type="); pw.print(type);
- pw.print(" when="); pw.print(when);
+ pw.print(" when="); TimeUtils.formatDuration(when, now, pw);
pw.print(" repeatInterval="); pw.print(repeatInterval);
pw.print(" count="); pw.println(count);
pw.print(prefix); pw.print("operation="); pw.println(operation);
diff --git a/services/java/com/android/server/Installer.java b/services/java/com/android/server/Installer.java
index 1f34eba..85eca60 100644
--- a/services/java/com/android/server/Installer.java
+++ b/services/java/com/android/server/Installer.java
@@ -327,4 +327,33 @@
public int moveFiles() {
return execute("movefiles");
}
+
+ public int linkNativeLibraryDirectory(String dataPath, String nativeLibPath) {
+ if (dataPath == null) {
+ Slog.e(TAG, "unlinkNativeLibraryDirectory dataPath is null");
+ return -1;
+ } else if (nativeLibPath == null) {
+ Slog.e(TAG, "unlinkNativeLibraryDirectory nativeLibPath is null");
+ return -1;
+ }
+
+ StringBuilder builder = new StringBuilder("linklib ");
+ builder.append(dataPath);
+ builder.append(' ');
+ builder.append(nativeLibPath);
+
+ return execute(builder.toString());
+ }
+
+ public int unlinkNativeLibraryDirectory(String dataPath) {
+ if (dataPath == null) {
+ Slog.e(TAG, "unlinkNativeLibraryDirectory dataPath is null");
+ return -1;
+ }
+
+ StringBuilder builder = new StringBuilder("unlinklib ");
+ builder.append(dataPath);
+
+ return execute(builder.toString());
+ }
}
diff --git a/services/java/com/android/server/MountService.java b/services/java/com/android/server/MountService.java
index 8e5cdc2..3b2d836 100644
--- a/services/java/com/android/server/MountService.java
+++ b/services/java/com/android/server/MountService.java
@@ -79,8 +79,6 @@
private static final String VOLD_TAG = "VoldConnector";
- protected static final int MAX_OBBS = 8;
-
/*
* Internal vold volume state constants
*/
@@ -159,7 +157,6 @@
* Mounted OBB tracking information. Used to track the current state of all
* OBBs.
*/
- final private Map<Integer, Integer> mObbUidUsage = new HashMap<Integer, Integer>();
final private Map<IBinder, List<ObbState>> mObbMounts = new HashMap<IBinder, List<ObbState>>();
final private Map<String, ObbState> mObbPathToStateMap = new HashMap<String, ObbState>();
@@ -170,8 +167,6 @@
this.token = token;
this.callerUid = callerUid;
mounted = false;
-
- getBinder().linkToDeath(this, 0);
}
// OBB source filename
@@ -196,7 +191,11 @@
mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_RUN_ACTION, action));
}
- public void cleanUp() {
+ public void link() throws RemoteException {
+ getBinder().linkToDeath(this, 0);
+ }
+
+ public void unlink() {
getBinder().unlinkToDeath(this, 0);
}
@@ -224,7 +223,6 @@
private static final int OBB_MCS_BOUND = 2;
private static final int OBB_MCS_UNBIND = 3;
private static final int OBB_MCS_RECONNECT = 4;
- private static final int OBB_MCS_GIVE_UP = 5;
/*
* Default Container Service information
@@ -1589,12 +1587,6 @@
}
final int callerUid = Binder.getCallingUid();
-
- final Integer uidUsage = mObbUidUsage.get(callerUid);
- if (uidUsage != null && uidUsage > MAX_OBBS) {
- throw new IllegalStateException("Maximum number of OBBs mounted!");
- }
-
obbState = new ObbState(filename, token, callerUid);
addObbState(obbState);
}
@@ -1659,56 +1651,61 @@
Slog.i(TAG, "Send to OBB handler: " + action.toString());
}
- private void addObbState(ObbState obbState) {
+ private void addObbState(ObbState obbState) throws RemoteException {
synchronized (mObbMounts) {
- List<ObbState> obbStates = mObbMounts.get(obbState.getBinder());
+ final IBinder binder = obbState.getBinder();
+ List<ObbState> obbStates = mObbMounts.get(binder);
+ final boolean unique;
+
if (obbStates == null) {
obbStates = new ArrayList<ObbState>();
- mObbMounts.put(obbState.getBinder(), obbStates);
- }
- obbStates.add(obbState);
- mObbPathToStateMap.put(obbState.filename, obbState);
-
- // Track the number of OBBs used by this UID.
- final int uid = obbState.callerUid;
- final Integer uidUsage = mObbUidUsage.get(uid);
- if (uidUsage == null) {
- mObbUidUsage.put(uid, 1);
+ mObbMounts.put(binder, obbStates);
+ unique = true;
} else {
- mObbUidUsage.put(uid, uidUsage + 1);
+ unique = obbStates.contains(obbState);
}
+
+ if (unique) {
+ obbStates.add(obbState);
+ try {
+ obbState.link();
+ } catch (RemoteException e) {
+ /*
+ * The binder died before we could link it, so clean up our
+ * state and return failure.
+ */
+ obbStates.remove(obbState);
+ if (obbStates.isEmpty()) {
+ mObbMounts.remove(binder);
+ }
+
+ // Rethrow the error so mountObb can get it
+ throw e;
+ }
+ }
+
+ mObbPathToStateMap.put(obbState.filename, obbState);
}
}
private void removeObbState(ObbState obbState) {
synchronized (mObbMounts) {
- final List<ObbState> obbStates = mObbMounts.get(obbState.getBinder());
+ final IBinder binder = obbState.getBinder();
+ final List<ObbState> obbStates = mObbMounts.get(binder);
if (obbStates != null) {
- obbStates.remove(obbState);
- }
- if (obbStates == null || obbStates.isEmpty()) {
- mObbMounts.remove(obbState.getBinder());
- obbState.cleanUp();
- }
- mObbPathToStateMap.remove(obbState.filename);
-
- // Track the number of OBBs used by this UID.
- final int uid = obbState.callerUid;
- final Integer uidUsage = mObbUidUsage.get(uid);
- if (uidUsage == null) {
- Slog.e(TAG, "Called removeObbState for UID that isn't in map: " + uid);
- } else {
- final int newUsage = uidUsage - 1;
- if (newUsage == 0) {
- mObbUidUsage.remove(uid);
- } else {
- mObbUidUsage.put(uid, newUsage);
+ if (obbStates.remove(obbState)) {
+ obbState.unlink();
+ }
+ if (obbStates.isEmpty()) {
+ mObbMounts.remove(binder);
}
}
+
+ mObbPathToStateMap.remove(obbState.filename);
}
}
- private void replaceObbState(ObbState oldObbState, ObbState newObbState) {
+ private void replaceObbState(ObbState oldObbState, ObbState newObbState) throws RemoteException {
synchronized (mObbMounts) {
removeObbState(oldObbState);
addObbState(newObbState);
@@ -1717,7 +1714,7 @@
private class ObbActionHandler extends Handler {
private boolean mBound = false;
- private List<ObbAction> mActions = new LinkedList<ObbAction>();
+ private final List<ObbAction> mActions = new LinkedList<ObbAction>();
ObbActionHandler(Looper l) {
super(l);
@@ -1727,7 +1724,7 @@
public void handleMessage(Message msg) {
switch (msg.what) {
case OBB_RUN_ACTION: {
- ObbAction action = (ObbAction) msg.obj;
+ final ObbAction action = (ObbAction) msg.obj;
if (DEBUG_OBB)
Slog.i(TAG, "OBB_RUN_ACTION: " + action.toString());
@@ -1743,15 +1740,9 @@
action.handleError();
return;
}
-
- mActions.add(action);
- break;
}
- // Once we bind to the service, the first
- // pending request will be processed.
mActions.add(action);
- mObbActionHandler.sendEmptyMessage(OBB_MCS_BOUND);
break;
}
case OBB_MCS_BOUND: {
@@ -1769,7 +1760,7 @@
}
mActions.clear();
} else if (mActions.size() > 0) {
- ObbAction action = mActions.get(0);
+ final ObbAction action = mActions.get(0);
if (action != null) {
action.execute(this);
}
@@ -1817,12 +1808,6 @@
}
break;
}
- case OBB_MCS_GIVE_UP: {
- if (DEBUG_OBB)
- Slog.i(TAG, "OBB_MCS_GIVE_UP");
- mActions.remove(0);
- break;
- }
}
}
@@ -1862,7 +1847,7 @@
mRetries++;
if (mRetries > MAX_RETRIES) {
Slog.w(TAG, "Failed to invoke remote methods on default container service. Giving up");
- mObbActionHandler.sendEmptyMessage(OBB_MCS_GIVE_UP);
+ mObbActionHandler.sendEmptyMessage(OBB_MCS_UNBIND);
handleError();
return;
} else {
@@ -1879,6 +1864,7 @@
if (DEBUG_OBB)
Slog.d(TAG, "Error handling OBB action", e);
handleError();
+ mObbActionHandler.sendEmptyMessage(OBB_MCS_UNBIND);
}
}
diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java
index dbf92ba..ce0e79f 100644
--- a/services/java/com/android/server/PackageManagerService.java
+++ b/services/java/com/android/server/PackageManagerService.java
@@ -140,7 +140,6 @@
private static final boolean DEBUG_PREFERRED = false;
private static final boolean DEBUG_UPGRADE = false;
private static final boolean DEBUG_INSTALL = false;
- private static final boolean DEBUG_NATIVE = false;
private static final boolean MULTIPLE_APPLICATION_UIDS = true;
private static final int RADIO_UID = Process.PHONE_UID;
@@ -184,6 +183,7 @@
static final int SCAN_UPDATE_SIGNATURE = 1<<3;
static final int SCAN_NEW_INSTALL = 1<<4;
static final int SCAN_NO_PATHS = 1<<5;
+ static final int SCAN_UPDATE_TIME = 1<<6;
static final int REMOVE_CHATTY = 1<<16;
@@ -922,7 +922,7 @@
mFrameworkInstallObserver.startWatching();
scanDirLI(mFrameworkDir, PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR,
- scanMode | SCAN_NO_DEX);
+ scanMode | SCAN_NO_DEX, 0);
// Collect all system packages.
mSystemAppDir = new File(Environment.getRootDirectory(), "app");
@@ -930,7 +930,7 @@
mSystemAppDir.getPath(), OBSERVER_EVENTS, true);
mSystemInstallObserver.startWatching();
scanDirLI(mSystemAppDir, PackageParser.PARSE_IS_SYSTEM
- | PackageParser.PARSE_IS_SYSTEM_DIR, scanMode);
+ | PackageParser.PARSE_IS_SYSTEM_DIR, scanMode, 0);
// Collect all vendor packages.
mVendorAppDir = new File("/vendor/app");
@@ -938,7 +938,7 @@
mVendorAppDir.getPath(), OBSERVER_EVENTS, true);
mVendorInstallObserver.startWatching();
scanDirLI(mVendorAppDir, PackageParser.PARSE_IS_SYSTEM
- | PackageParser.PARSE_IS_SYSTEM_DIR, scanMode);
+ | PackageParser.PARSE_IS_SYSTEM_DIR, scanMode, 0);
if (mInstaller != null) {
if (DEBUG_UPGRADE) Log.v(TAG, "Running installd update commands");
@@ -985,12 +985,13 @@
mAppInstallObserver = new AppDirObserver(
mAppInstallDir.getPath(), OBSERVER_EVENTS, false);
mAppInstallObserver.startWatching();
- scanDirLI(mAppInstallDir, 0, scanMode);
+ scanDirLI(mAppInstallDir, 0, scanMode, 0);
mDrmAppInstallObserver = new AppDirObserver(
mDrmAppPrivateInstallDir.getPath(), OBSERVER_EVENTS, false);
mDrmAppInstallObserver.startWatching();
- scanDirLI(mDrmAppPrivateInstallDir, PackageParser.PARSE_FORWARD_LOCK, scanMode);
+ scanDirLI(mDrmAppPrivateInstallDir, PackageParser.PARSE_FORWARD_LOCK,
+ scanMode, 0);
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SCAN_END,
SystemClock.uptimeMillis());
@@ -1318,14 +1319,15 @@
PackageInfo generatePackageInfo(PackageParser.Package p, int flags) {
if ((flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0) {
// The package has been uninstalled but has retained data and resources.
- return PackageParser.generatePackageInfo(p, null, flags);
+ return PackageParser.generatePackageInfo(p, null, flags, 0, 0);
}
final PackageSetting ps = (PackageSetting)p.mExtras;
if (ps == null) {
return null;
}
final GrantedPermissions gp = ps.sharedUser != null ? ps.sharedUser : ps;
- return PackageParser.generatePackageInfo(p, gp.gids, flags);
+ return PackageParser.generatePackageInfo(p, gp.gids, flags,
+ ps.firstInstallTime, ps.lastUpdateTime);
}
public PackageInfo getPackageInfo(String packageName, int flags) {
@@ -2484,7 +2486,7 @@
return finalList;
}
- private void scanDirLI(File dir, int flags, int scanMode) {
+ private void scanDirLI(File dir, int flags, int scanMode, long currentTime) {
String[] files = dir.list();
if (files == null) {
Log.d(TAG, "No files in app dir " + dir);
@@ -2501,7 +2503,7 @@
continue;
}
PackageParser.Package pkg = scanPackageLI(file,
- flags|PackageParser.PARSE_MUST_BE_APK, scanMode);
+ flags|PackageParser.PARSE_MUST_BE_APK, scanMode, currentTime);
// Don't mess around with apps in system partition.
if (pkg == null && (flags & PackageParser.PARSE_IS_SYSTEM) == 0 &&
mLastScanError == PackageManager.INSTALL_FAILED_INVALID_APK) {
@@ -2569,7 +2571,7 @@
* Returns null in case of errors and the error code is stored in mLastScanError
*/
private PackageParser.Package scanPackageLI(File scanFile,
- int parseFlags, int scanMode) {
+ int parseFlags, int scanMode, long currentTime) {
mLastScanError = PackageManager.INSTALL_SUCCEEDED;
String scanPath = scanFile.getPath();
parseFlags |= mDefParseFlags;
@@ -2669,7 +2671,7 @@
// Set application objects path explicitly.
setApplicationInfoPaths(pkg, codePath, resPath);
// Note that we invoke the following method only if we are about to unpack an application
- return scanPackageLI(pkg, parseFlags, scanMode | SCAN_UPDATE_SIGNATURE);
+ return scanPackageLI(pkg, parseFlags, scanMode | SCAN_UPDATE_SIGNATURE, currentTime);
}
private static void setApplicationInfoPaths(PackageParser.Package pkg, String destCodePath,
@@ -2800,7 +2802,7 @@
}
private PackageParser.Package scanPackageLI(PackageParser.Package pkg,
- int parseFlags, int scanMode) {
+ int parseFlags, int scanMode, long currentTime) {
File scanFile = new File(pkg.mScanPath);
if (scanFile == null || pkg.applicationInfo.sourceDir == null ||
pkg.applicationInfo.publicSourceDir == null) {
@@ -3133,7 +3135,7 @@
}
}
- long scanFileTime = scanFile.lastModified();
+ final long scanFileTime = scanFile.lastModified();
final boolean forceDex = (scanMode&SCAN_FORCE_DEX) != 0;
final boolean scanFileNewer = forceDex || scanFileTime != pkgSetting.timeStamp;
pkg.applicationInfo.processName = fixProcessName(
@@ -3241,8 +3243,6 @@
}
}
- pkg.applicationInfo.nativeLibraryDir = pkgSetting.nativeLibraryPathString;
-
/*
* Set the data dir to the default "/data/data/<package name>/lib"
* if we got here without anyone telling us different (e.g., apps
@@ -3252,10 +3252,14 @@
* This happens during an upgrade from a package settings file that
* doesn't have a native library path attribute at all.
*/
- if (pkgSetting.nativeLibraryPathString == null && pkg.applicationInfo.dataDir != null) {
- final String nativeLibraryPath = new File(dataPath, LIB_DIR_NAME).getPath();
- pkg.applicationInfo.nativeLibraryDir = nativeLibraryPath;
- pkgSetting.nativeLibraryPathString = nativeLibraryPath;
+ if (pkg.applicationInfo.nativeLibraryDir == null && pkg.applicationInfo.dataDir != null) {
+ if (pkgSetting.nativeLibraryPathString == null) {
+ final String nativeLibraryPath = new File(dataPath, LIB_DIR_NAME).getPath();
+ pkg.applicationInfo.nativeLibraryDir = nativeLibraryPath;
+ pkgSetting.nativeLibraryPathString = nativeLibraryPath;
+ } else {
+ pkg.applicationInfo.nativeLibraryDir = pkgSetting.nativeLibraryPathString;
+ }
}
pkgSetting.uidError = uidError;
@@ -3274,10 +3278,27 @@
* In other words, we're going to unpack the binaries
* only for non-system apps and system app upgrades.
*/
- if ((!isSystemApp(pkg) || isUpdatedSystemApp(pkg)) && !isExternal(pkg)) {
- Log.i(TAG, path + " changed; unpacking");
- File sharedLibraryDir = new File(pkg.applicationInfo.nativeLibraryDir);
- NativeLibraryHelper.copyNativeBinariesLI(scanFile, sharedLibraryDir);
+ if (pkg.applicationInfo.nativeLibraryDir != null) {
+ final File sharedLibraryDir = new File(pkg.applicationInfo.nativeLibraryDir);
+ if (isSystemApp(pkg) && !isUpdatedSystemApp(pkg)) {
+ /*
+ * Upgrading from a previous version of the OS sometimes
+ * leaves native libraries in the /data/data/<app>/lib
+ * directory for system apps even when they shouldn't be.
+ * Recent changes in the JNI library search path
+ * necessitates we remove those to match previous behavior.
+ */
+ if (NativeLibraryHelper.removeNativeBinariesFromDirLI(sharedLibraryDir)) {
+ Log.i(TAG, "removed obsolete native libraries for system package " + path);
+ }
+ } else if (!isExternal(pkg)) {
+ Log.i(TAG, path + " changed; unpacking");
+ mInstaller.unlinkNativeLibraryDirectory(dataPath.getPath());
+ NativeLibraryHelper.copyNativeBinariesLI(scanFile, sharedLibraryDir);
+ } else {
+ mInstaller.linkNativeLibraryDirectory(dataPath.getPath(),
+ pkg.applicationInfo.nativeLibraryDir);
+ }
}
pkg.mScanPath = path;
@@ -3314,6 +3335,24 @@
// Make sure we don't accidentally delete its data.
mSettings.mPackagesToBeCleaned.remove(pkgName);
+ // Take care of first install / last update times.
+ if (currentTime != 0) {
+ if (pkgSetting.firstInstallTime == 0) {
+ pkgSetting.firstInstallTime = pkgSetting.lastUpdateTime = currentTime;
+ } else if ((scanMode&SCAN_UPDATE_TIME) != 0) {
+ pkgSetting.lastUpdateTime = currentTime;
+ }
+ } else if (pkgSetting.firstInstallTime == 0) {
+ // We need *something*. Take time time stamp of the file.
+ pkgSetting.firstInstallTime = pkgSetting.lastUpdateTime = scanFileTime;
+ } else if ((parseFlags&PackageParser.PARSE_IS_SYSTEM_DIR) != 0) {
+ if (scanFileTime != pkgSetting.timeStamp) {
+ // A package on the system image has changed; consider this
+ // to be an update.
+ pkgSetting.lastUpdateTime = scanFileTime;
+ }
+ }
+
int N = pkg.providers.size();
StringBuilder r = null;
int i;
@@ -4453,7 +4492,8 @@
| PackageParser.PARSE_IS_SYSTEM_DIR: 0) |
PackageParser.PARSE_CHATTY |
PackageParser.PARSE_MUST_BE_APK,
- SCAN_MONITOR | SCAN_NO_PATHS);
+ SCAN_MONITOR | SCAN_NO_PATHS | SCAN_UPDATE_TIME,
+ System.currentTimeMillis());
if (p != null) {
synchronized (mPackages) {
updatePermissionsLP(p.packageName, p,
@@ -4996,10 +5036,6 @@
try { if (out != null) out.close(); } catch (IOException e) {}
}
- if (!temp) {
- NativeLibraryHelper.copyNativeBinariesLI(codeFile, new File(libraryPath));
- }
-
return ret;
}
@@ -5446,7 +5482,8 @@
}
}
mLastScanError = PackageManager.INSTALL_SUCCEEDED;
- PackageParser.Package newPackage = scanPackageLI(pkg, parseFlags, scanMode);
+ PackageParser.Package newPackage = scanPackageLI(pkg, parseFlags, scanMode,
+ System.currentTimeMillis());
if (newPackage == null) {
Slog.w(TAG, "Package couldn't be installed in " + pkg.mPath);
if ((res.returnCode=mLastScanError) == PackageManager.INSTALL_SUCCEEDED) {
@@ -5509,16 +5546,24 @@
oldInstallerPackageName = mSettings.getInstallerPackageName(pkgName);
}
+ long origUpdateTime;
+ if (pkg.mExtras != null) {
+ origUpdateTime = ((PackageSetting)pkg.mExtras).lastUpdateTime;
+ } else {
+ origUpdateTime = 0;
+ }
+
// First delete the existing package while retaining the data directory
if (!deletePackageLI(pkgName, true, PackageManager.DONT_DELETE_DATA,
res.removedInfo, true)) {
- // If the existing package was'nt successfully deleted
+ // If the existing package wasn't successfully deleted
res.returnCode = PackageManager.INSTALL_FAILED_REPLACE_COULDNT_DELETE;
deletedPkg = false;
} else {
// Successfully deleted the old package. Now proceed with re-installation
mLastScanError = PackageManager.INSTALL_SUCCEEDED;
- newPackage = scanPackageLI(pkg, parseFlags, scanMode);
+ newPackage = scanPackageLI(pkg, parseFlags, scanMode | SCAN_UPDATE_TIME,
+ System.currentTimeMillis());
if (newPackage == null) {
Slog.w(TAG, "Package couldn't be installed in " + pkg.mPath);
if ((res.returnCode=mLastScanError) == PackageManager.INSTALL_SUCCEEDED) {
@@ -5556,8 +5601,10 @@
int oldParseFlags = mDefParseFlags | PackageParser.PARSE_CHATTY |
(isForwardLocked(deletedPackage) ? PackageParser.PARSE_FORWARD_LOCK : 0) |
(oldOnSd ? PackageParser.PARSE_ON_SDCARD : 0);
- int oldScanMode = (oldOnSd ? 0 : SCAN_MONITOR) | SCAN_UPDATE_SIGNATURE;
- if (scanPackageLI(restoreFile, oldParseFlags, oldScanMode) == null) {
+ int oldScanMode = (oldOnSd ? 0 : SCAN_MONITOR) | SCAN_UPDATE_SIGNATURE
+ | SCAN_UPDATE_TIME;
+ if (scanPackageLI(restoreFile, oldParseFlags, oldScanMode,
+ origUpdateTime) == null) {
Slog.e(TAG, "Failed to restore package : " + pkgName + " after failed upgrade");
return;
}
@@ -5608,13 +5655,18 @@
// Successfully disabled the old package. Now proceed with re-installation
mLastScanError = PackageManager.INSTALL_SUCCEEDED;
pkg.applicationInfo.flags |= ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
- newPackage = scanPackageLI(pkg, parseFlags, scanMode);
+ newPackage = scanPackageLI(pkg, parseFlags, scanMode, 0);
if (newPackage == null) {
Slog.w(TAG, "Package couldn't be installed in " + pkg.mPath);
if ((res.returnCode=mLastScanError) == PackageManager.INSTALL_SUCCEEDED) {
res.returnCode = PackageManager.INSTALL_FAILED_INVALID_APK;
}
} else {
+ if (newPackage.mExtras != null) {
+ final PackageSetting newPkgSetting = (PackageSetting)newPackage.mExtras;
+ newPkgSetting.firstInstallTime = oldPkgSetting.firstInstallTime;
+ newPkgSetting.lastUpdateTime = System.currentTimeMillis();
+ }
updateSettingsLI(newPackage, installerPackageName, res);
updatedSettings = true;
}
@@ -5626,12 +5678,10 @@
removePackageLI(newPackage, true);
}
// Add back the old system package
- scanPackageLI(oldPkg, parseFlags,
- SCAN_MONITOR
- | SCAN_UPDATE_SIGNATURE);
+ scanPackageLI(oldPkg, parseFlags, SCAN_MONITOR | SCAN_UPDATE_SIGNATURE, 0);
// Restore the old system information in Settings
synchronized(mPackages) {
- if(updatedSettings) {
+ if (updatedSettings) {
mSettings.enableSystemPackageLP(packageName);
mSettings.setInstallerPackageName(packageName,
oldPkgSetting.installerPackageName);
@@ -5645,7 +5695,6 @@
PackageSetting ps = mSettings.getDisabledSystemPkg(packageName);
if (ps != null && ps.codePathString != null &&
!ps.codePathString.equals(oldPkgSetting.codePathString)) {
- int installFlags = 0;
res.removedInfo.args = createInstallArgs(0, oldPkgSetting.codePathString,
oldPkgSetting.resourcePathString, oldPkgSetting.nativeLibraryPathString);
}
@@ -6180,7 +6229,7 @@
// Install the system package
PackageParser.Package newPkg = scanPackageLI(ps.codePath,
PackageParser.PARSE_MUST_BE_APK | PackageParser.PARSE_IS_SYSTEM,
- SCAN_MONITOR | SCAN_NO_PATHS);
+ SCAN_MONITOR | SCAN_NO_PATHS, 0);
if (newPkg == null) {
Slog.w(TAG, "Failed to restore system package:"+p.packageName+" with error:" + mLastScanError);
@@ -7033,6 +7082,8 @@
printedSomething = false;
SharedUserSetting packageSharedUser = null;
if (dumpStar || dumpPackages) {
+ SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+ Date date = new Date();
for (PackageSetting ps : mSettings.mPackages.values()) {
if (packageName != null && !packageName.equals(ps.realName)
&& !packageName.equals(ps.name)) {
@@ -7107,7 +7158,12 @@
}
}
pw.println("]");
- pw.print(" timeStamp="); pw.println(String.valueOf(ps.timeStamp));
+ pw.print(" timeStamp=");
+ date.setTime(ps.timeStamp); pw.println(sdf.format(date));
+ pw.print(" firstInstallTime=");
+ date.setTime(ps.firstInstallTime); pw.println(sdf.format(date));
+ pw.print(" lastUpdateTime=");
+ date.setTime(ps.lastUpdateTime); pw.println(sdf.format(date));
pw.print(" signatures="); pw.println(ps.signatures);
pw.print(" permissionsFixed="); pw.print(ps.permissionsFixed);
pw.print(" haveGids="); pw.println(ps.haveGids);
@@ -7618,6 +7674,8 @@
String nativeLibraryPathString;
String obbPathString;
long timeStamp;
+ long firstInstallTime;
+ long lastUpdateTime;
int versionCode;
boolean uidError;
@@ -7682,6 +7740,8 @@
gids = base.gids;
timeStamp = base.timeStamp;
+ firstInstallTime = base.firstInstallTime;
+ lastUpdateTime = base.lastUpdateTime;
signatures = base.signatures;
permissionsFixed = base.permissionsFixed;
haveGids = base.haveGids;
@@ -8051,7 +8111,7 @@
if (p != null) {
if (!p.codePath.equals(codePath)) {
// Check to see if its a disabled system app
- if((p != null) && ((p.pkgFlags & ApplicationInfo.FLAG_SYSTEM) != 0)) {
+ if ((p.pkgFlags & ApplicationInfo.FLAG_SYSTEM) != 0) {
// This is an updated system app with versions in both system
// and data partition. Just let the most recent version
// take precedence.
@@ -8062,6 +8122,13 @@
// let's log a message about it.
Slog.i(TAG, "Package " + name + " codePath changed from " + p.codePath
+ " to " + codePath + "; Retaining data and using new");
+ /*
+ * Since we've changed paths, we need to prefer the new
+ * native library path over the one stored in the
+ * package settings since we might have moved from
+ * internal to external storage or vice versa.
+ */
+ p.nativeLibraryPathString = nativeLibraryPathString;
}
}
if (p.sharedUser != sharedUser) {
@@ -8544,7 +8611,9 @@
serializer.attribute(null, "realName", pkg.realName);
}
serializer.attribute(null, "codePath", pkg.codePathString);
- serializer.attribute(null, "ts", String.valueOf(pkg.timeStamp));
+ serializer.attribute(null, "ft", Long.toHexString(pkg.timeStamp));
+ serializer.attribute(null, "it", Long.toHexString(pkg.firstInstallTime));
+ serializer.attribute(null, "ut", Long.toHexString(pkg.lastUpdateTime));
serializer.attribute(null, "version", String.valueOf(pkg.versionCode));
if (!pkg.resourcePathString.equals(pkg.codePathString)) {
serializer.attribute(null, "resourcePath", pkg.resourcePathString);
@@ -8596,7 +8665,9 @@
}
serializer.attribute(null, "flags",
Integer.toString(pkg.pkgFlags));
- serializer.attribute(null, "ts", String.valueOf(pkg.timeStamp));
+ serializer.attribute(null, "ft", Long.toHexString(pkg.timeStamp));
+ serializer.attribute(null, "it", Long.toHexString(pkg.firstInstallTime));
+ serializer.attribute(null, "ut", Long.toHexString(pkg.lastUpdateTime));
serializer.attribute(null, "version", String.valueOf(pkg.versionCode));
if (pkg.sharedUser == null) {
serializer.attribute(null, "userId",
@@ -8952,13 +9023,36 @@
pkgFlags |= ApplicationInfo.FLAG_SYSTEM;
PackageSetting ps = new PackageSetting(name, realName, new File(codePathStr),
new File(resourcePathStr), nativeLibraryPathStr, versionCode, pkgFlags);
- String timeStampStr = parser.getAttributeValue(null, "ts");
+ String timeStampStr = parser.getAttributeValue(null, "ft");
if (timeStampStr != null) {
try {
- long timeStamp = Long.parseLong(timeStampStr);
+ long timeStamp = Long.parseLong(timeStampStr, 16);
ps.setTimeStamp(timeStamp);
} catch (NumberFormatException e) {
}
+ } else {
+ timeStampStr = parser.getAttributeValue(null, "ts");
+ if (timeStampStr != null) {
+ try {
+ long timeStamp = Long.parseLong(timeStampStr);
+ ps.setTimeStamp(timeStamp);
+ } catch (NumberFormatException e) {
+ }
+ }
+ }
+ timeStampStr = parser.getAttributeValue(null, "it");
+ if (timeStampStr != null) {
+ try {
+ ps.firstInstallTime = Long.parseLong(timeStampStr, 16);
+ } catch (NumberFormatException e) {
+ }
+ }
+ timeStampStr = parser.getAttributeValue(null, "ut");
+ if (timeStampStr != null) {
+ try {
+ ps.lastUpdateTime = Long.parseLong(timeStampStr, 16);
+ } catch (NumberFormatException e) {
+ }
}
String idStr = parser.getAttributeValue(null, "userId");
ps.userId = idStr != null ? Integer.parseInt(idStr) : 0;
@@ -9005,6 +9099,8 @@
String uidError = null;
int pkgFlags = 0;
long timeStamp = 0;
+ long firstInstallTime = 0;
+ long lastUpdateTime = 0;
PackageSettingBase packageSetting = null;
String version = null;
int versionCode = 0;
@@ -9044,10 +9140,32 @@
pkgFlags |= ApplicationInfo.FLAG_SYSTEM;
}
}
- final String timeStampStr = parser.getAttributeValue(null, "ts");
+ String timeStampStr = parser.getAttributeValue(null, "ft");
if (timeStampStr != null) {
try {
- timeStamp = Long.parseLong(timeStampStr);
+ timeStamp = Long.parseLong(timeStampStr, 16);
+ } catch (NumberFormatException e) {
+ }
+ } else {
+ timeStampStr = parser.getAttributeValue(null, "ts");
+ if (timeStampStr != null) {
+ try {
+ timeStamp = Long.parseLong(timeStampStr);
+ } catch (NumberFormatException e) {
+ }
+ }
+ }
+ timeStampStr = parser.getAttributeValue(null, "it");
+ if (timeStampStr != null) {
+ try {
+ firstInstallTime = Long.parseLong(timeStampStr, 16);
+ } catch (NumberFormatException e) {
+ }
+ }
+ timeStampStr = parser.getAttributeValue(null, "ut");
+ if (timeStampStr != null) {
+ try {
+ lastUpdateTime = Long.parseLong(timeStampStr, 16);
} catch (NumberFormatException e) {
}
}
@@ -9081,6 +9199,8 @@
+ parser.getPositionDescription());
} else {
packageSetting.setTimeStamp(timeStamp);
+ packageSetting.firstInstallTime = firstInstallTime;
+ packageSetting.lastUpdateTime = lastUpdateTime;
}
} else if (sharedIdStr != null) {
userId = sharedIdStr != null
@@ -9090,6 +9210,8 @@
new File(codePathStr), new File(resourcePathStr),
nativeLibraryPathStr, userId, versionCode, pkgFlags);
packageSetting.setTimeStamp(timeStamp);
+ packageSetting.firstInstallTime = firstInstallTime;
+ packageSetting.lastUpdateTime = lastUpdateTime;
mPendingPackages.add((PendingPackage) packageSetting);
if (DEBUG_SETTINGS) Log.i(TAG, "Reading package " + name
+ ": sharedUserId=" + userId + " pkg="
@@ -9648,7 +9770,7 @@
doGc = true;
synchronized (mInstallLock) {
final PackageParser.Package pkg = scanPackageLI(new File(codePath),
- parseFlags, 0);
+ parseFlags, 0, 0);
// Scan the package
if (pkg != null) {
synchronized (mPackages) {
@@ -9873,10 +9995,10 @@
synchronized (mPackages) {
PackageParser.Package pkg = mPackages.get(mp.packageName);
// Recheck for package again.
- if (pkg == null ) {
- Slog.w(TAG, " Package " + mp.packageName +
- " doesn't exist. Aborting move");
- returnCode = PackageManager.MOVE_FAILED_DOESNT_EXIST;
+ if (pkg == null) {
+ Slog.w(TAG, " Package " + mp.packageName
+ + " doesn't exist. Aborting move");
+ returnCode = PackageManager.MOVE_FAILED_DOESNT_EXIST;
} else if (!mp.srcArgs.getCodePath().equals(pkg.applicationInfo.sourceDir)) {
Slog.w(TAG, "Package " + mp.packageName + " code path changed from " +
mp.srcArgs.getCodePath() + " to " + pkg.applicationInfo.sourceDir +
@@ -9887,15 +10009,34 @@
final String newCodePath = mp.targetArgs.getCodePath();
final String newResPath = mp.targetArgs.getResourcePath();
final String newNativePath = mp.targetArgs.getNativeLibraryPath();
- pkg.mPath = newCodePath;
- // Move dex files around
- if (moveDexFilesLI(pkg)
- != PackageManager.INSTALL_SUCCEEDED) {
- // Moving of dex files failed. Set
- // error code and abort move.
- pkg.mPath = pkg.mScanPath;
- returnCode = PackageManager.MOVE_FAILED_INSUFFICIENT_STORAGE;
- } else {
+
+ if ((mp.flags & PackageManager.INSTALL_EXTERNAL) == 0) {
+ if (mInstaller
+ .unlinkNativeLibraryDirectory(pkg.applicationInfo.dataDir) < 0) {
+ returnCode = PackageManager.MOVE_FAILED_INSUFFICIENT_STORAGE;
+ } else {
+ NativeLibraryHelper.copyNativeBinariesLI(
+ new File(newCodePath), new File(newNativePath));
+ }
+ } else {
+ if (mInstaller.linkNativeLibraryDirectory(
+ pkg.applicationInfo.dataDir, newNativePath) < 0) {
+ returnCode = PackageManager.MOVE_FAILED_INSUFFICIENT_STORAGE;
+ }
+ }
+
+ if (returnCode == PackageManager.MOVE_SUCCEEDED) {
+ pkg.mPath = newCodePath;
+ // Move dex files around
+ if (moveDexFilesLI(pkg) != PackageManager.INSTALL_SUCCEEDED) {
+ // Moving of dex files failed. Set
+ // error code and abort move.
+ pkg.mPath = pkg.mScanPath;
+ returnCode = PackageManager.MOVE_FAILED_INSUFFICIENT_STORAGE;
+ }
+ }
+
+ if (returnCode == PackageManager.MOVE_SUCCEEDED) {
pkg.mScanPath = newCodePath;
pkg.applicationInfo.sourceDir = newCodePath;
pkg.applicationInfo.publicSourceDir = newResPath;
diff --git a/services/java/com/android/server/PowerManagerService.java b/services/java/com/android/server/PowerManagerService.java
index e77ed69..496c665 100644
--- a/services/java/com/android/server/PowerManagerService.java
+++ b/services/java/com/android/server/PowerManagerService.java
@@ -220,6 +220,7 @@
private Sensor mLightSensor;
private boolean mLightSensorEnabled;
private float mLightSensorValue = -1;
+ private boolean mProxIgnoredBecauseScreenTurnedOff = false;
private int mHighestLightSensorValue = -1;
private float mLightSensorPendingValue = -1;
private int mLightSensorScreenBrightness = -1;
@@ -252,7 +253,7 @@
// could be either static or controllable at runtime
private static final boolean mSpew = false;
- private static final boolean mDebugProximitySensor = (true || mSpew);
+ private static final boolean mDebugProximitySensor = (false || mSpew);
private static final boolean mDebugLightSensor = (false || mSpew);
private native void nativeInit();
@@ -638,7 +639,8 @@
int n = flags & LOCK_MASK;
return n == PowerManager.FULL_WAKE_LOCK
|| n == PowerManager.SCREEN_BRIGHT_WAKE_LOCK
- || n == PowerManager.SCREEN_DIM_WAKE_LOCK;
+ || n == PowerManager.SCREEN_DIM_WAKE_LOCK
+ || n == PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK;
}
void enforceWakeSourcePermission(int uid, int pid) {
@@ -778,25 +780,33 @@
// set it to whatever they want. otherwise, we modulate that
// by the current state so we never turn it more on than
// it already is.
- if ((wl.flags & PowerManager.ACQUIRE_CAUSES_WAKEUP) != 0) {
- int oldWakeLockState = mWakeLockState;
- mWakeLockState = mLocks.reactivateScreenLocksLocked();
- if (mSpew) {
- Slog.d(TAG, "wakeup here mUserState=0x" + Integer.toHexString(mUserState)
- + " mWakeLockState=0x"
- + Integer.toHexString(mWakeLockState)
- + " previous wakeLockState=0x" + Integer.toHexString(oldWakeLockState));
+ if ((flags & LOCK_MASK) == PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK) {
+ mProximityWakeLockCount++;
+ if (mProximityWakeLockCount == 1) {
+ enableProximityLockLocked();
}
} else {
- if (mSpew) {
- Slog.d(TAG, "here mUserState=0x" + Integer.toHexString(mUserState)
- + " mLocks.gatherState()=0x"
- + Integer.toHexString(mLocks.gatherState())
- + " mWakeLockState=0x" + Integer.toHexString(mWakeLockState));
+ if ((wl.flags & PowerManager.ACQUIRE_CAUSES_WAKEUP) != 0) {
+ int oldWakeLockState = mWakeLockState;
+ mWakeLockState = mLocks.reactivateScreenLocksLocked();
+ if (mSpew) {
+ Slog.d(TAG, "wakeup here mUserState=0x" + Integer.toHexString(mUserState)
+ + " mWakeLockState=0x"
+ + Integer.toHexString(mWakeLockState)
+ + " previous wakeLockState=0x"
+ + Integer.toHexString(oldWakeLockState));
+ }
+ } else {
+ if (mSpew) {
+ Slog.d(TAG, "here mUserState=0x" + Integer.toHexString(mUserState)
+ + " mLocks.gatherState()=0x"
+ + Integer.toHexString(mLocks.gatherState())
+ + " mWakeLockState=0x" + Integer.toHexString(mWakeLockState));
+ }
+ mWakeLockState = (mUserState | mWakeLockState) & mLocks.gatherState();
}
- mWakeLockState = (mUserState | mWakeLockState) & mLocks.gatherState();
+ setPowerState(mWakeLockState | mUserState);
}
- setPowerState(mWakeLockState | mUserState);
}
else if ((flags & LOCK_MASK) == PowerManager.PARTIAL_WAKE_LOCK) {
if (newlock) {
@@ -806,11 +816,6 @@
}
}
Power.acquireWakeLock(Power.PARTIAL_WAKE_LOCK,PARTIAL_NAME);
- } else if ((flags & LOCK_MASK) == PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK) {
- mProximityWakeLockCount++;
- if (mProximityWakeLockCount == 1) {
- enableProximityLockLocked();
- }
}
if (diffsource) {
@@ -868,12 +873,27 @@
}
if (isScreenLock(wl.flags)) {
- mWakeLockState = mLocks.gatherState();
- // goes in the middle to reduce flicker
- if ((wl.flags & PowerManager.ON_AFTER_RELEASE) != 0) {
- userActivity(SystemClock.uptimeMillis(), -1, false, OTHER_EVENT, false);
+ if ((wl.flags & LOCK_MASK) == PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK) {
+ mProximityWakeLockCount--;
+ if (mProximityWakeLockCount == 0) {
+ if (mProximitySensorActive &&
+ ((flags & PowerManager.WAIT_FOR_PROXIMITY_NEGATIVE) != 0)) {
+ // wait for proximity sensor to go negative before disabling sensor
+ if (mDebugProximitySensor) {
+ Slog.d(TAG, "waiting for proximity sensor to go negative");
+ }
+ } else {
+ disableProximityLockLocked();
+ }
+ }
+ } else {
+ mWakeLockState = mLocks.gatherState();
+ // goes in the middle to reduce flicker
+ if ((wl.flags & PowerManager.ON_AFTER_RELEASE) != 0) {
+ userActivity(SystemClock.uptimeMillis(), -1, false, OTHER_EVENT, false);
+ }
+ setPowerState(mWakeLockState | mUserState);
}
- setPowerState(mWakeLockState | mUserState);
}
else if ((wl.flags & LOCK_MASK) == PowerManager.PARTIAL_WAKE_LOCK) {
mPartialCount--;
@@ -881,19 +901,6 @@
if (LOG_PARTIAL_WL) EventLog.writeEvent(EventLogTags.POWER_PARTIAL_WAKE_STATE, 0, wl.tag);
Power.releaseWakeLock(PARTIAL_NAME);
}
- } else if ((wl.flags & LOCK_MASK) == PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK) {
- mProximityWakeLockCount--;
- if (mProximityWakeLockCount == 0) {
- if (mProximitySensorActive &&
- ((flags & PowerManager.WAIT_FOR_PROXIMITY_NEGATIVE) != 0)) {
- // wait for proximity sensor to go negative before disabling sensor
- if (mDebugProximitySensor) {
- Slog.d(TAG, "waiting for proximity sensor to go negative");
- }
- } else {
- disableProximityLockLocked();
- }
- }
}
// Unlink the lock from the binder.
wl.binder.unlinkToDeath(wl, 0);
@@ -2433,11 +2440,23 @@
mWakeLockState = SCREEN_OFF;
int N = mLocks.size();
int numCleared = 0;
+ boolean proxLock = false;
for (int i=0; i<N; i++) {
WakeLock wl = mLocks.get(i);
if (isScreenLock(wl.flags)) {
- mLocks.get(i).activated = false;
- numCleared++;
+ if (((wl.flags & LOCK_MASK) == PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK)
+ && reason == WindowManagerPolicy.OFF_BECAUSE_OF_PROX_SENSOR) {
+ proxLock = true;
+ } else {
+ mLocks.get(i).activated = false;
+ numCleared++;
+ }
+ }
+ }
+ if (!proxLock) {
+ mProxIgnoredBecauseScreenTurnedOff = true;
+ if (mDebugProximitySensor) {
+ Slog.d(TAG, "setting mProxIgnoredBecauseScreenTurnedOff");
}
}
EventLog.writeEvent(EventLogTags.POWER_SLEEP_REQUESTED, numCleared);
@@ -2628,6 +2647,11 @@
result |= wl.minState;
}
}
+ if (mDebugProximitySensor) {
+ Slog.d(TAG, "reactivateScreenLocksLocked mProxIgnoredBecauseScreenTurnedOff="
+ + mProxIgnoredBecauseScreenTurnedOff);
+ }
+ mProxIgnoredBecauseScreenTurnedOff = false;
return result;
}
}
@@ -2787,7 +2811,13 @@
}
if (mProximitySensorActive) {
mProximitySensorActive = false;
- forceUserActivityLocked();
+ if (mDebugProximitySensor) {
+ Slog.d(TAG, "disableProximityLockLocked mProxIgnoredBecauseScreenTurnedOff="
+ + mProxIgnoredBecauseScreenTurnedOff);
+ }
+ if (!mProxIgnoredBecauseScreenTurnedOff) {
+ forceUserActivityLocked();
+ }
}
}
}
@@ -2801,15 +2831,27 @@
return;
}
if (active) {
- goToSleepLocked(SystemClock.uptimeMillis(),
- WindowManagerPolicy.OFF_BECAUSE_OF_PROX_SENSOR);
+ if (mDebugProximitySensor) {
+ Slog.d(TAG, "b mProxIgnoredBecauseScreenTurnedOff="
+ + mProxIgnoredBecauseScreenTurnedOff);
+ }
+ if (!mProxIgnoredBecauseScreenTurnedOff) {
+ goToSleepLocked(SystemClock.uptimeMillis(),
+ WindowManagerPolicy.OFF_BECAUSE_OF_PROX_SENSOR);
+ }
mProximitySensorActive = true;
} else {
// proximity sensor negative events trigger as user activity.
// temporarily set mUserActivityAllowed to true so this will work
// even when the keyguard is on.
mProximitySensorActive = false;
- forceUserActivityLocked();
+ if (mDebugProximitySensor) {
+ Slog.d(TAG, "b mProxIgnoredBecauseScreenTurnedOff="
+ + mProxIgnoredBecauseScreenTurnedOff);
+ }
+ if (!mProxIgnoredBecauseScreenTurnedOff) {
+ forceUserActivityLocked();
+ }
if (mProximityWakeLockCount == 0) {
// disable sensor if we have no listeners left after proximity negative
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 50054bd..9c06c33 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -2993,84 +2993,6 @@
}
}
- final void decPersistentCountLocked(ProcessRecord app) {
- app.persistentActivities--;
- if (app.persistentActivities > 0) {
- // Still more of 'em...
- return;
- }
- if (app.persistent) {
- // Ah, but the application itself is persistent. Whatever!
- return;
- }
-
- // App is no longer persistent... make sure it and the ones
- // following it in the LRU list have the correc oom_adj.
- updateOomAdjLocked();
- }
-
- public void setPersistent(IBinder token, boolean isPersistent) {
- if (checkCallingPermission(android.Manifest.permission.PERSISTENT_ACTIVITY)
- != PackageManager.PERMISSION_GRANTED) {
- String msg = "Permission Denial: setPersistent() from pid="
- + Binder.getCallingPid()
- + ", uid=" + Binder.getCallingUid()
- + " requires " + android.Manifest.permission.PERSISTENT_ACTIVITY;
- Slog.w(TAG, msg);
- throw new SecurityException(msg);
- }
-
- synchronized(this) {
- int index = mMainStack.indexOfTokenLocked(token);
- if (index < 0) {
- return;
- }
- ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(index);
- ProcessRecord app = r.app;
-
- if (localLOGV) Slog.v(
- TAG, "Setting persistence " + isPersistent + ": " + r);
-
- if (isPersistent) {
- if (r.persistent) {
- // Okay okay, I heard you already!
- if (localLOGV) Slog.v(TAG, "Already persistent!");
- return;
- }
- r.persistent = true;
- app.persistentActivities++;
- if (localLOGV) Slog.v(TAG, "Num persistent now: " + app.persistentActivities);
- if (app.persistentActivities > 1) {
- // We aren't the first...
- if (localLOGV) Slog.v(TAG, "Not the first!");
- return;
- }
- if (app.persistent) {
- // This would be redundant.
- if (localLOGV) Slog.v(TAG, "App is persistent!");
- return;
- }
-
- // App is now persistent... make sure it and the ones
- // following it now have the correct oom_adj.
- final long origId = Binder.clearCallingIdentity();
- updateOomAdjLocked();
- Binder.restoreCallingIdentity(origId);
-
- } else {
- if (!r.persistent) {
- // Okay okay, I heard you already!
- return;
- }
- r.persistent = false;
- final long origId = Binder.clearCallingIdentity();
- decPersistentCountLocked(app);
- Binder.restoreCallingIdentity(origId);
-
- }
- }
- }
-
public boolean clearApplicationUserData(final String packageName,
final IPackageDataObserver observer) {
int uid = Binder.getCallingUid();
@@ -11585,11 +11507,6 @@
adj = FOREGROUND_APP_ADJ;
schedGroup = Process.THREAD_GROUP_DEFAULT;
app.adjType = "instrumentation";
- } else if (app.persistentActivities > 0) {
- // Special persistent activities... shouldn't be used these days.
- adj = FOREGROUND_APP_ADJ;
- schedGroup = Process.THREAD_GROUP_DEFAULT;
- app.adjType = "persistent";
} else if (app.curReceiver != null ||
(mPendingBroadcast != null && mPendingBroadcast.curApp == app)) {
// An app that is currently receiving a broadcast also
@@ -12313,8 +12230,7 @@
final ProcessRecord app = mLruProcesses.get(i);
if (app.persistent || app.services.size() != 0
- || app.curReceiver != null
- || app.persistentActivities > 0) {
+ || app.curReceiver != null) {
// Don't count processes holding services against our
// maximum process count.
if (localLOGV) Slog.v(
@@ -12379,8 +12295,7 @@
// Quit the application only if we have a state saved for
// all of its activities.
boolean canQuit = !app.persistent && app.curReceiver == null
- && app.services.size() == 0
- && app.persistentActivities == 0;
+ && app.services.size() == 0;
int NUMA = app.activities.size();
int j;
if (Config.LOGV) Slog.v(
@@ -12444,7 +12359,7 @@
// We can finish this one if we have its icicle saved and
// it is not persistent.
if ((r.haveState || !r.stateNotNeeded) && !r.visible
- && r.stopped && !r.persistent && !r.finishing) {
+ && r.stopped && !r.finishing) {
final int origSize = mMainStack.mLRUActivities.size();
r.stack.destroyActivityLocked(r, true);
diff --git a/services/java/com/android/server/am/ActivityRecord.java b/services/java/com/android/server/am/ActivityRecord.java
index 53b08d0..4d773e4 100644
--- a/services/java/com/android/server/am/ActivityRecord.java
+++ b/services/java/com/android/server/am/ActivityRecord.java
@@ -96,7 +96,6 @@
int configChangeFlags; // which config values have changed
boolean keysPaused; // has key dispatching been paused for it?
boolean inHistory; // are we in the history stack?
- boolean persistent; // requested to be persistent?
int launchMode; // the launch mode activity attribute.
boolean visible; // does this activity's window need to be shown?
boolean waitingVisible; // true if waiting for a new act to become vis
@@ -160,7 +159,6 @@
pw.print(" finishing="); pw.println(finishing);
pw.print(prefix); pw.print("keysPaused="); pw.print(keysPaused);
pw.print(" inHistory="); pw.print(inHistory);
- pw.print(" persistent="); pw.print(persistent);
pw.print(" launchMode="); pw.println(launchMode);
pw.print(prefix); pw.print("fullscreen="); pw.print(fullscreen);
pw.print(" visible="); pw.print(visible);
@@ -213,7 +211,6 @@
configDestroy = false;
keysPaused = false;
inHistory = false;
- persistent = false;
visible = true;
waitingVisible = false;
nowVisible = false;
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index 9ed1242..016ddcd 100644
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -3151,9 +3151,6 @@
mService.mHandler.sendEmptyMessage(
ActivityManagerService.CANCEL_HEAVY_NOTIFICATION_MSG);
}
- if (r.persistent) {
- mService.decPersistentCountLocked(r.app);
- }
if (r.app.activities.size() == 0) {
// No longer have activities, so update location in
// LRU list.
@@ -3452,54 +3449,49 @@
return true;
}
- // If the activity isn't persistent, there is a chance we will
- // need to restart it.
- if (!r.persistent) {
-
- // Figure out what has changed between the two configurations.
- int changes = oldConfig.diff(newConfig);
- if (DEBUG_SWITCH || DEBUG_CONFIGURATION) {
- Slog.v(TAG, "Checking to restart " + r.info.name + ": changed=0x"
- + Integer.toHexString(changes) + ", handles=0x"
- + Integer.toHexString(r.info.configChanges)
- + ", newConfig=" + newConfig);
+ // Figure out what has changed between the two configurations.
+ int changes = oldConfig.diff(newConfig);
+ if (DEBUG_SWITCH || DEBUG_CONFIGURATION) {
+ Slog.v(TAG, "Checking to restart " + r.info.name + ": changed=0x"
+ + Integer.toHexString(changes) + ", handles=0x"
+ + Integer.toHexString(r.info.configChanges)
+ + ", newConfig=" + newConfig);
+ }
+ if ((changes&(~r.info.configChanges)) != 0) {
+ // Aha, the activity isn't handling the change, so DIE DIE DIE.
+ r.configChangeFlags |= changes;
+ r.startFreezingScreenLocked(r.app, globalChanges);
+ if (r.app == null || r.app.thread == null) {
+ if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
+ "Switch is destroying non-running " + r);
+ destroyActivityLocked(r, true);
+ } else if (r.state == ActivityState.PAUSING) {
+ // A little annoying: we are waiting for this activity to
+ // finish pausing. Let's not do anything now, but just
+ // flag that it needs to be restarted when done pausing.
+ if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
+ "Switch is skipping already pausing " + r);
+ r.configDestroy = true;
+ return true;
+ } else if (r.state == ActivityState.RESUMED) {
+ // Try to optimize this case: the configuration is changing
+ // and we need to restart the top, resumed activity.
+ // Instead of doing the normal handshaking, just say
+ // "restart!".
+ if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
+ "Switch is restarting resumed " + r);
+ relaunchActivityLocked(r, r.configChangeFlags, true);
+ r.configChangeFlags = 0;
+ } else {
+ if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
+ "Switch is restarting non-resumed " + r);
+ relaunchActivityLocked(r, r.configChangeFlags, false);
+ r.configChangeFlags = 0;
}
- if ((changes&(~r.info.configChanges)) != 0) {
- // Aha, the activity isn't handling the change, so DIE DIE DIE.
- r.configChangeFlags |= changes;
- r.startFreezingScreenLocked(r.app, globalChanges);
- if (r.app == null || r.app.thread == null) {
- if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
- "Switch is destroying non-running " + r);
- destroyActivityLocked(r, true);
- } else if (r.state == ActivityState.PAUSING) {
- // A little annoying: we are waiting for this activity to
- // finish pausing. Let's not do anything now, but just
- // flag that it needs to be restarted when done pausing.
- if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
- "Switch is skipping already pausing " + r);
- r.configDestroy = true;
- return true;
- } else if (r.state == ActivityState.RESUMED) {
- // Try to optimize this case: the configuration is changing
- // and we need to restart the top, resumed activity.
- // Instead of doing the normal handshaking, just say
- // "restart!".
- if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
- "Switch is restarting resumed " + r);
- relaunchActivityLocked(r, r.configChangeFlags, true);
- r.configChangeFlags = 0;
- } else {
- if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
- "Switch is restarting non-resumed " + r);
- relaunchActivityLocked(r, r.configChangeFlags, false);
- r.configChangeFlags = 0;
- }
-
- // All done... tell the caller we weren't able to keep this
- // activity around.
- return false;
- }
+
+ // All done... tell the caller we weren't able to keep this
+ // activity around.
+ return false;
}
// Default case: the activity can handle this new configuration, so
diff --git a/services/java/com/android/server/am/BroadcastRecord.java b/services/java/com/android/server/am/BroadcastRecord.java
index bac21b1..b268efa 100644
--- a/services/java/com/android/server/am/BroadcastRecord.java
+++ b/services/java/com/android/server/am/BroadcastRecord.java
@@ -84,8 +84,8 @@
pw.print(prefix); pw.print("extras: "); pw.println(bundle.toString());
}
}
- pw.print(prefix); pw.print("caller="); pw.print(callerPackage); pw.println(" ");
- pw.println(callerApp != null ? callerApp.toShortString() : "null");
+ pw.print(prefix); pw.print("caller="); pw.print(callerPackage); pw.print(" ");
+ pw.print(callerApp != null ? callerApp.toShortString() : "null");
pw.print(" pid="); pw.print(callingPid);
pw.print(" uid="); pw.println(callingUid);
if (requiredPermission != null) {
diff --git a/services/java/com/android/server/am/ProcessRecord.java b/services/java/com/android/server/am/ProcessRecord.java
index 404c6be..353ff6d 100644
--- a/services/java/com/android/server/am/ProcessRecord.java
+++ b/services/java/com/android/server/am/ProcessRecord.java
@@ -115,7 +115,6 @@
Dialog anrDialog; // dialog being displayed due to app not resp.
boolean removed; // has app package been removed from device?
boolean debugging; // was app launched for debugging?
- int persistentActivities; // number of activities that are persistent
boolean waitedForDebugger; // has process show wait for debugger dialog?
Dialog waitDialog; // current wait for debugger dialog
@@ -181,8 +180,7 @@
pw.print(" foregroundServices="); pw.print(foregroundServices);
pw.print(" forcingToForeground="); pw.println(forcingToForeground);
pw.print(prefix); pw.print("persistent="); pw.print(persistent);
- pw.print(" removed="); pw.print(removed);
- pw.print(" persistentActivities="); pw.println(persistentActivities);
+ pw.print(" removed="); pw.println(removed);
pw.print(prefix); pw.print("adjSeq="); pw.print(adjSeq);
pw.print(" lruSeq="); pw.println(lruSeq);
if (!keeping) {
@@ -259,7 +257,6 @@
curAdj = setAdj = -100;
persistent = false;
removed = false;
- persistentActivities = 0;
}
public void setPid(int _pid) {
diff --git a/services/java/com/android/server/location/GpsLocationProvider.java b/services/java/com/android/server/location/GpsLocationProvider.java
index 39ce0b6..e9eb4f0 100755
--- a/services/java/com/android/server/location/GpsLocationProvider.java
+++ b/services/java/com/android/server/location/GpsLocationProvider.java
@@ -46,6 +46,10 @@
import android.os.SystemClock;
import android.os.WorkSource;
import android.provider.Settings;
+import android.provider.Telephony.Sms.Intents;
+import android.telephony.TelephonyManager;
+import android.telephony.gsm.GsmCellLocation;
+import android.telephony.SmsMessage;
import android.util.Log;
import android.util.SparseIntArray;
@@ -53,6 +57,9 @@
import com.android.internal.telephony.Phone;
import com.android.internal.location.GpsNetInitiatedHandler;
import com.android.internal.location.GpsNetInitiatedHandler.GpsNiNotification;
+import com.android.internal.telephony.GsmAlphabet;
+import com.android.internal.telephony.SmsHeader;
+import com.android.internal.util.HexDump;
import java.io.File;
import java.io.FileInputStream;
@@ -153,6 +160,24 @@
private static final int REMOVE_LISTENER = 9;
private static final int REQUEST_SINGLE_SHOT = 10;
+ // Request setid
+ private static final int AGPS_RIL_REQUEST_SETID_IMSI = 1;
+ private static final int AGPS_RIL_REQUEST_SETID_MSISDN = 2;
+
+ // Request ref location
+ private static final int AGPS_RIL_REQUEST_REFLOC_CELLID = 1;
+ private static final int AGPS_RIL_REQUEST_REFLOC_MAC = 2;
+
+ // ref. location info
+ private static final int AGPS_REF_LOCATION_TYPE_GSM_CELLID = 1;
+ private static final int AGPS_REF_LOCATION_TYPE_UMTS_CELLID = 2;
+ private static final int AGPS_REG_LOCATION_TYPE_MAC = 3;
+
+ // set id info
+ private static final int AGPS_SETID_TYPE_NONE = 0;
+ private static final int AGPS_SETID_TYPE_IMSI = 1;
+ private static final int AGPS_SETID_TYPE_MSISDN = 2;
+
private static final String PROPERTIES_FILE = "/etc/gps.conf";
private int mLocationFlags = LOCATION_INVALID;
@@ -328,10 +353,27 @@
} else if (action.equals(ALARM_TIMEOUT)) {
if (DEBUG) Log.d(TAG, "ALARM_TIMEOUT");
hibernate();
- }
+ } else if (action.equals(Intents.DATA_SMS_RECEIVED_ACTION)) {
+ checkSmsSuplInit(intent);
+ } else if (action.equals(Intents.WAP_PUSH_RECEIVED_ACTION)) {
+ checkWapSuplInit(intent);
+ }
}
};
+ private void checkSmsSuplInit(Intent intent) {
+ SmsMessage[] messages = Intents.getMessagesFromIntent(intent);
+ for (int i=0; i <messages.length; i++) {
+ byte[] supl_init = messages[i].getUserData();
+ native_agps_ni_message(supl_init,supl_init.length);
+ }
+ }
+
+ private void checkWapSuplInit(Intent intent) {
+ byte[] supl_init = (byte[]) intent.getExtra("data");
+ native_agps_ni_message(supl_init,supl_init.length);
+ }
+
public static boolean isSupported() {
return native_is_supported();
}
@@ -352,6 +394,21 @@
mWakeupIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(ALARM_WAKEUP), 0);
mTimeoutIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(ALARM_TIMEOUT), 0);
+ IntentFilter intentFilter = new IntentFilter();
+ intentFilter.addAction(Intents.DATA_SMS_RECEIVED_ACTION);
+ intentFilter.addDataScheme("sms");
+ intentFilter.addDataAuthority("localhost","7275");
+ context.registerReceiver(mBroadcastReciever, intentFilter);
+
+ intentFilter = new IntentFilter();
+ intentFilter.addAction(Intents.WAP_PUSH_RECEIVED_ACTION);
+ try {
+ intentFilter.addDataType("application/vnd.omaloc-supl-init");
+ } catch (IntentFilter.MalformedMimeTypeException e) {
+ Log.w(TAG, "Malformed SUPL init mime type");
+ }
+ context.registerReceiver(mBroadcastReciever, intentFilter);
+
mConnMgr = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
// Battery statistics service to be notified when GPS turns on or off
@@ -1255,22 +1312,20 @@
//=============================================================
// NI Client support
- //=============================================================
+ //=============================================================
private final INetInitiatedListener mNetInitiatedListener = new INetInitiatedListener.Stub() {
- // Sends a response for an NI reqeust to HAL.
- public boolean sendNiResponse(int notificationId, int userResponse)
- {
- // TODO Add Permission check
-
- StringBuilder extrasBuf = new StringBuilder();
+ // Sends a response for an NI reqeust to HAL.
+ public boolean sendNiResponse(int notificationId, int userResponse)
+ {
+ // TODO Add Permission check
- if (DEBUG) Log.d(TAG, "sendNiResponse, notifId: " + notificationId +
- ", response: " + userResponse);
-
- native_send_ni_response(notificationId, userResponse);
-
- return true;
- }
+ StringBuilder extrasBuf = new StringBuilder();
+
+ if (DEBUG) Log.d(TAG, "sendNiResponse, notifId: " + notificationId +
+ ", response: " + userResponse);
+ native_send_ni_response(notificationId, userResponse);
+ return true;
+ }
};
public INetInitiatedListener getNetInitiatedListener() {
@@ -1278,70 +1333,132 @@
}
// Called by JNI function to report an NI request.
- @SuppressWarnings("deprecation")
- public void reportNiNotification(
- int notificationId,
- int niType,
- int notifyFlags,
- int timeout,
- int defaultResponse,
- String requestorId,
- String text,
- int requestorIdEncoding,
- int textEncoding,
- String extras // Encoded extra data
+ public void reportNiNotification(
+ int notificationId,
+ int niType,
+ int notifyFlags,
+ int timeout,
+ int defaultResponse,
+ String requestorId,
+ String text,
+ int requestorIdEncoding,
+ int textEncoding,
+ String extras // Encoded extra data
)
- {
- Log.i(TAG, "reportNiNotification: entered");
- Log.i(TAG, "notificationId: " + notificationId +
- ", niType: " + niType +
- ", notifyFlags: " + notifyFlags +
- ", timeout: " + timeout +
- ", defaultResponse: " + defaultResponse);
-
- Log.i(TAG, "requestorId: " + requestorId +
- ", text: " + text +
- ", requestorIdEncoding: " + requestorIdEncoding +
- ", textEncoding: " + textEncoding);
-
- GpsNiNotification notification = new GpsNiNotification();
-
- notification.notificationId = notificationId;
- notification.niType = niType;
- notification.needNotify = (notifyFlags & GpsNetInitiatedHandler.GPS_NI_NEED_NOTIFY) != 0;
- notification.needVerify = (notifyFlags & GpsNetInitiatedHandler.GPS_NI_NEED_VERIFY) != 0;
- notification.privacyOverride = (notifyFlags & GpsNetInitiatedHandler.GPS_NI_PRIVACY_OVERRIDE) != 0;
- notification.timeout = timeout;
- notification.defaultResponse = defaultResponse;
- notification.requestorId = requestorId;
- notification.text = text;
- notification.requestorIdEncoding = requestorIdEncoding;
- notification.textEncoding = textEncoding;
-
- // Process extras, assuming the format is
- // one of more lines of "key = value"
- Bundle bundle = new Bundle();
-
- if (extras == null) extras = "";
- Properties extraProp = new Properties();
-
- try {
- extraProp.load(new StringBufferInputStream(extras));
- }
- catch (IOException e)
- {
- Log.e(TAG, "reportNiNotification cannot parse extras data: " + extras);
- }
-
- for (Entry<Object, Object> ent : extraProp.entrySet())
- {
- bundle.putString((String) ent.getKey(), (String) ent.getValue());
- }
-
- notification.extras = bundle;
-
- mNIHandler.handleNiNotification(notification);
- }
+ {
+ Log.i(TAG, "reportNiNotification: entered");
+ Log.i(TAG, "notificationId: " + notificationId +
+ ", niType: " + niType +
+ ", notifyFlags: " + notifyFlags +
+ ", timeout: " + timeout +
+ ", defaultResponse: " + defaultResponse);
+
+ Log.i(TAG, "requestorId: " + requestorId +
+ ", text: " + text +
+ ", requestorIdEncoding: " + requestorIdEncoding +
+ ", textEncoding: " + textEncoding);
+
+ GpsNiNotification notification = new GpsNiNotification();
+
+ notification.notificationId = notificationId;
+ notification.niType = niType;
+ notification.needNotify = (notifyFlags & GpsNetInitiatedHandler.GPS_NI_NEED_NOTIFY) != 0;
+ notification.needVerify = (notifyFlags & GpsNetInitiatedHandler.GPS_NI_NEED_VERIFY) != 0;
+ notification.privacyOverride = (notifyFlags & GpsNetInitiatedHandler.GPS_NI_PRIVACY_OVERRIDE) != 0;
+ notification.timeout = timeout;
+ notification.defaultResponse = defaultResponse;
+ notification.requestorId = requestorId;
+ notification.text = text;
+ notification.requestorIdEncoding = requestorIdEncoding;
+ notification.textEncoding = textEncoding;
+
+ // Process extras, assuming the format is
+ // one of more lines of "key = value"
+ Bundle bundle = new Bundle();
+
+ if (extras == null) extras = "";
+ Properties extraProp = new Properties();
+
+ try {
+ extraProp.load(new StringBufferInputStream(extras));
+ }
+ catch (IOException e)
+ {
+ Log.e(TAG, "reportNiNotification cannot parse extras data: " + extras);
+ }
+
+ for (Entry<Object, Object> ent : extraProp.entrySet())
+ {
+ bundle.putString((String) ent.getKey(), (String) ent.getValue());
+ }
+
+ notification.extras = bundle;
+
+ mNIHandler.handleNiNotification(notification);
+ }
+
+ /**
+ * Called from native code to request set id info.
+ * We should be careful about receiving null string from the TelephonyManager,
+ * because sending null String to JNI function would cause a crash.
+ */
+
+ private void requestSetID(int flags) {
+ TelephonyManager phone = (TelephonyManager)
+ mContext.getSystemService(Context.TELEPHONY_SERVICE);
+ int type = AGPS_SETID_TYPE_NONE;
+ String data = "";
+
+ if ((flags & AGPS_RIL_REQUEST_SETID_IMSI) == AGPS_RIL_REQUEST_SETID_IMSI) {
+ String data_temp = phone.getSubscriberId();
+ if (data_temp == null) {
+ // This means the framework does not have the SIM card ready.
+ } else {
+ // This means the framework has the SIM card.
+ data = data_temp;
+ type = AGPS_SETID_TYPE_IMSI;
+ }
+ }
+ else if ((flags & AGPS_RIL_REQUEST_SETID_MSISDN) == AGPS_RIL_REQUEST_SETID_MSISDN) {
+ String data_temp = phone.getLine1Number();
+ if (data_temp == null) {
+ // This means the framework does not have the SIM card ready.
+ } else {
+ // This means the framework has the SIM card.
+ data = data_temp;
+ type = AGPS_SETID_TYPE_MSISDN;
+ }
+ }
+ native_agps_set_id(type, data);
+ }
+
+ /**
+ * Called from native code to request reference location info
+ */
+
+ private void requestRefLocation(int flags) {
+ TelephonyManager phone = (TelephonyManager)
+ mContext.getSystemService(Context.TELEPHONY_SERVICE);
+ if (phone.getPhoneType() == TelephonyManager.PHONE_TYPE_GSM) {
+ GsmCellLocation gsm_cell = (GsmCellLocation) phone.getCellLocation();
+ if ((gsm_cell != null) && (phone.getPhoneType() == TelephonyManager.PHONE_TYPE_GSM)
+ && (phone.getNetworkOperator().length() > 3)) {
+ int type;
+ int mcc = Integer.parseInt(phone.getNetworkOperator().substring(0,3));
+ int mnc = Integer.parseInt(phone.getNetworkOperator().substring(3));
+ if (phone.getNetworkType() == TelephonyManager.NETWORK_TYPE_UMTS)
+ type = AGPS_REF_LOCATION_TYPE_UMTS_CELLID;
+ else
+ type = AGPS_REF_LOCATION_TYPE_GSM_CELLID;
+ native_agps_set_ref_location_cellid(type, mcc, mnc,
+ gsm_cell.getLac(), gsm_cell.getCid());
+ }
+ else
+ Log.e(TAG,"Error getting cell location info.");
+ }
+ else
+ Log.e(TAG,"CDMA not supported.");
+ }
private void sendMessage(int message, int arg, Object obj) {
// hold a wake lock while messages are pending
@@ -1472,8 +1589,14 @@
private native void native_agps_data_conn_open(String apn);
private native void native_agps_data_conn_closed();
private native void native_agps_data_conn_failed();
+ private native void native_agps_ni_message(byte [] msg, int length);
private native void native_set_agps_server(int type, String hostname, int port);
// Network-initiated (NI) Support
private native void native_send_ni_response(int notificationId, int userResponse);
+
+ // AGPS ril suport
+ private native void native_agps_set_ref_location_cellid(int type, int mcc, int mnc,
+ int lac, int cid);
+ private native void native_agps_set_id(int type, String setid);
}
diff --git a/services/jni/com_android_server_location_GpsLocationProvider.cpp b/services/jni/com_android_server_location_GpsLocationProvider.cpp
index 59d7cde..71c7aba 100755
--- a/services/jni/com_android_server_location_GpsLocationProvider.cpp
+++ b/services/jni/com_android_server_location_GpsLocationProvider.cpp
@@ -40,12 +40,15 @@
static jmethodID method_setEngineCapabilities;
static jmethodID method_xtraDownloadRequest;
static jmethodID method_reportNiNotification;
+static jmethodID method_requestRefLocation;
+static jmethodID method_requestSetID;
static const GpsInterface* sGpsInterface = NULL;
static const GpsXtraInterface* sGpsXtraInterface = NULL;
static const AGpsInterface* sAGpsInterface = NULL;
static const GpsNiInterface* sGpsNiInterface = NULL;
static const GpsDebugInterface* sGpsDebugInterface = NULL;
+static const AGpsRilInterface* sAGpsRilInterface = NULL;
// temporary storage for GPS callbacks
static GpsSvStatus sGpsSvStatus;
@@ -193,17 +196,30 @@
create_thread_callback,
};
-static void android_location_GpsLocationProvider_class_init_native(JNIEnv* env, jclass clazz) {
- method_reportLocation = env->GetMethodID(clazz, "reportLocation", "(IDDDFFFJ)V");
- method_reportStatus = env->GetMethodID(clazz, "reportStatus", "(I)V");
- method_reportSvStatus = env->GetMethodID(clazz, "reportSvStatus", "()V");
- method_reportAGpsStatus = env->GetMethodID(clazz, "reportAGpsStatus", "(II)V");
- method_reportNmea = env->GetMethodID(clazz, "reportNmea", "(J)V");
- method_setEngineCapabilities = env->GetMethodID(clazz, "setEngineCapabilities", "(I)V");
- method_xtraDownloadRequest = env->GetMethodID(clazz, "xtraDownloadRequest", "()V");
- method_reportNiNotification = env->GetMethodID(clazz, "reportNiNotification", "(IIIIILjava/lang/String;Ljava/lang/String;IILjava/lang/String;)V");
+static void agps_request_set_id(uint32_t flags)
+{
+ LOGD("agps_request_set_id: flags (%d)", flags);
+
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
+ env->CallVoidMethod(mCallbacksObj, method_requestSetID, flags);
+ checkAndClearExceptionFromCallback(env, __FUNCTION__);
}
+static void agps_request_ref_location(uint32_t flags)
+{
+ LOGD("agps_ref_location: flags (%d)", flags);
+
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
+ env->CallVoidMethod(mCallbacksObj, method_requestRefLocation, flags);
+ checkAndClearExceptionFromCallback(env, __FUNCTION__);
+}
+
+AGpsRilCallbacks sAGpsRilCallbacks = {
+ agps_request_set_id,
+ agps_request_ref_location,
+ create_thread_callback,
+};
+
static const GpsInterface* get_gps_interface() {
int err;
hw_module_t* module;
@@ -222,6 +238,64 @@
return interface;
}
+static const AGpsInterface* GetAGpsInterface()
+{
+ if (!sGpsInterface)
+ sGpsInterface = get_gps_interface();
+ if (!sGpsInterface || sGpsInterface->init(&sGpsCallbacks) != 0)
+ return NULL;
+
+ if (!sAGpsInterface) {
+ sAGpsInterface = (const AGpsInterface*)sGpsInterface->get_extension(AGPS_INTERFACE);
+ if (sAGpsInterface)
+ sAGpsInterface->init(&sAGpsCallbacks);
+ }
+ return sAGpsInterface;
+}
+
+static const GpsNiInterface* GetNiInterface()
+{
+ if (!sGpsInterface)
+ sGpsInterface = get_gps_interface();
+ if (!sGpsInterface || sGpsInterface->init(&sGpsCallbacks) != 0)
+ return NULL;
+
+ if (!sGpsNiInterface) {
+ sGpsNiInterface = (const GpsNiInterface*)sGpsInterface->get_extension(GPS_NI_INTERFACE);
+ if (sGpsNiInterface)
+ sGpsNiInterface->init(&sGpsNiCallbacks);
+ }
+ return sGpsNiInterface;
+}
+
+static const AGpsRilInterface* GetAGpsRilInterface()
+{
+ if (!sGpsInterface)
+ sGpsInterface = get_gps_interface();
+ if (!sGpsInterface || sGpsInterface->init(&sGpsCallbacks) != 0)
+ return NULL;
+
+ if (!sAGpsRilInterface) {
+ sAGpsRilInterface = (const AGpsRilInterface*)sGpsInterface->get_extension(AGPS_RIL_INTERFACE);
+ if (sAGpsRilInterface)
+ sAGpsRilInterface->init(&sAGpsRilCallbacks);
+ }
+ return sAGpsRilInterface;
+}
+
+static void android_location_GpsLocationProvider_class_init_native(JNIEnv* env, jclass clazz) {
+ method_reportLocation = env->GetMethodID(clazz, "reportLocation", "(IDDDFFFJ)V");
+ method_reportStatus = env->GetMethodID(clazz, "reportStatus", "(I)V");
+ method_reportSvStatus = env->GetMethodID(clazz, "reportSvStatus", "()V");
+ method_reportAGpsStatus = env->GetMethodID(clazz, "reportAGpsStatus", "(II)V");
+ method_reportNmea = env->GetMethodID(clazz, "reportNmea", "(J)V");
+ method_setEngineCapabilities = env->GetMethodID(clazz, "setEngineCapabilities", "(I)V");
+ method_xtraDownloadRequest = env->GetMethodID(clazz, "xtraDownloadRequest", "()V");
+ method_reportNiNotification = env->GetMethodID(clazz, "reportNiNotification", "(IIIIILjava/lang/String;Ljava/lang/String;IILjava/lang/String;)V");
+ method_requestRefLocation = env->GetMethodID(clazz,"requestRefLocation","(I)V");
+ method_requestSetID = env->GetMethodID(clazz,"requestSetID","(I)V");
+}
+
static jboolean android_location_GpsLocationProvider_is_supported(JNIEnv* env, jclass clazz) {
if (!sGpsInterface)
sGpsInterface = get_gps_interface();
@@ -239,16 +313,6 @@
if (!sGpsInterface || sGpsInterface->init(&sGpsCallbacks) != 0)
return false;
- if (!sAGpsInterface)
- sAGpsInterface = (const AGpsInterface*)sGpsInterface->get_extension(AGPS_INTERFACE);
- if (sAGpsInterface)
- sAGpsInterface->init(&sAGpsCallbacks);
-
- if (!sGpsNiInterface)
- sGpsNiInterface = (const GpsNiInterface*)sGpsInterface->get_extension(GPS_NI_INTERFACE);
- if (sGpsNiInterface)
- sGpsNiInterface->init(&sGpsNiCallbacks);
-
if (!sGpsDebugInterface)
sGpsDebugInterface = (const GpsDebugInterface*)sGpsInterface->get_extension(GPS_DEBUG_INTERFACE);
@@ -313,6 +377,64 @@
return num_svs;
}
+static void android_location_GpsLocationProvider_agps_set_reference_location_cellid(JNIEnv* env,
+ jobject obj, jint type, jint mcc, jint mnc, jint lac, jint cid)
+{
+ AGpsRefLocation location;
+ const AGpsRilInterface* interface = GetAGpsRilInterface();
+ if (!interface) {
+ LOGE("no AGPS RIL interface in agps_set_reference_location_cellid");
+ return;
+ }
+
+ switch(type) {
+ case AGPS_REF_LOCATION_TYPE_GSM_CELLID:
+ case AGPS_REF_LOCATION_TYPE_UMTS_CELLID:
+ location.type = type;
+ location.u.cellID.mcc = mcc;
+ location.u.cellID.mnc = mnc;
+ location.u.cellID.lac = lac;
+ location.u.cellID.cid = cid;
+ break;
+ default:
+ LOGE("Neither a GSM nor a UMTS cellid (%s:%d).",__FUNCTION__,__LINE__);
+ return;
+ break;
+ }
+ interface->set_ref_location(&location, sizeof(location));
+}
+
+static void android_location_GpsLocationProvider_agps_send_ni_message(JNIEnv* env,
+ jobject obj, jbyteArray ni_msg, jint size)
+{
+ size_t sz;
+ const AGpsRilInterface* interface = GetAGpsRilInterface();
+ if (!interface) {
+ LOGE("no AGPS RIL interface in send_ni_message");
+ return;
+ }
+ if (size < 0)
+ return;
+ sz = (size_t)size;
+ jbyte* b = env->GetByteArrayElements(ni_msg, 0);
+ interface->ni_message((uint8_t *)b,sz);
+ env->ReleaseByteArrayElements(ni_msg,b,0);
+}
+
+static void android_location_GpsLocationProvider_agps_set_id(JNIEnv *env,
+ jobject obj, jint type, jstring setid_string)
+{
+ const AGpsRilInterface* interface = GetAGpsRilInterface();
+ if (!interface) {
+ LOGE("no AGPS RIL interface in agps_set_id");
+ return;
+ }
+
+ const char *setid = env->GetStringUTFChars(setid_string, NULL);
+ interface->set_set_id(type, setid);
+ env->ReleaseStringUTFChars(setid_string, setid);
+}
+
static jint android_location_GpsLocationProvider_read_nmea(JNIEnv* env, jobject obj,
jbyteArray nmeaArray, jint buffer_size)
{
@@ -363,62 +485,63 @@
static void android_location_GpsLocationProvider_agps_data_conn_open(JNIEnv* env, jobject obj, jstring apn)
{
- if (!sAGpsInterface) {
- sAGpsInterface = (const AGpsInterface*)sGpsInterface->get_extension(AGPS_INTERFACE);
+ const AGpsInterface* interface = GetAGpsInterface();
+ if (!interface) {
+ LOGE("no AGPS interface in agps_data_conn_open");
+ return;
}
- if (sAGpsInterface) {
- if (apn == NULL) {
- jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
- return;
- }
- const char *apnStr = env->GetStringUTFChars(apn, NULL);
- sAGpsInterface->data_conn_open(apnStr);
- env->ReleaseStringUTFChars(apn, apnStr);
+ if (apn == NULL) {
+ jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+ return;
}
+ const char *apnStr = env->GetStringUTFChars(apn, NULL);
+ interface->data_conn_open(apnStr);
+ env->ReleaseStringUTFChars(apn, apnStr);
}
static void android_location_GpsLocationProvider_agps_data_conn_closed(JNIEnv* env, jobject obj)
{
- if (!sAGpsInterface) {
- sAGpsInterface = (const AGpsInterface*)sGpsInterface->get_extension(AGPS_INTERFACE);
+ const AGpsInterface* interface = GetAGpsInterface();
+ if (!interface) {
+ LOGE("no AGPS interface in agps_data_conn_open");
+ return;
}
- if (sAGpsInterface) {
- sAGpsInterface->data_conn_closed();
- }
+ interface->data_conn_closed();
}
static void android_location_GpsLocationProvider_agps_data_conn_failed(JNIEnv* env, jobject obj)
{
- if (!sAGpsInterface) {
- sAGpsInterface = (const AGpsInterface*)sGpsInterface->get_extension(AGPS_INTERFACE);
+ const AGpsInterface* interface = GetAGpsInterface();
+ if (!interface) {
+ LOGE("no AGPS interface in agps_data_conn_open");
+ return;
}
- if (sAGpsInterface) {
- sAGpsInterface->data_conn_failed();
- }
+ interface->data_conn_failed();
}
static void android_location_GpsLocationProvider_set_agps_server(JNIEnv* env, jobject obj,
jint type, jstring hostname, jint port)
{
- if (!sAGpsInterface) {
- sAGpsInterface = (const AGpsInterface*)sGpsInterface->get_extension(AGPS_INTERFACE);
+ const AGpsInterface* interface = GetAGpsInterface();
+ if (!interface) {
+ LOGE("no AGPS interface in agps_data_conn_open");
+ return;
}
- if (sAGpsInterface) {
- const char *c_hostname = env->GetStringUTFChars(hostname, NULL);
- sAGpsInterface->set_server(type, c_hostname, port);
- env->ReleaseStringUTFChars(hostname, c_hostname);
- }
+ const char *c_hostname = env->GetStringUTFChars(hostname, NULL);
+ interface->set_server(type, c_hostname, port);
+ env->ReleaseStringUTFChars(hostname, c_hostname);
}
static void android_location_GpsLocationProvider_send_ni_response(JNIEnv* env, jobject obj,
jint notifId, jint response)
{
- if (!sGpsNiInterface) {
- sGpsNiInterface = (const GpsNiInterface*)sGpsInterface->get_extension(GPS_NI_INTERFACE);
+ const GpsNiInterface* interface = GetNiInterface();
+ if (!interface) {
+ LOGE("no NI interface in send_ni_response");
+ return;
}
- if (sGpsNiInterface) {
- sGpsNiInterface->respond(notifId, response);
- }
+
+ interface->respond(notifId, response);
}
static jstring android_location_GpsLocationProvider_get_internal_state(JNIEnv* env, jobject obj)
@@ -454,8 +577,11 @@
{"native_agps_data_conn_open", "(Ljava/lang/String;)V", (void*)android_location_GpsLocationProvider_agps_data_conn_open},
{"native_agps_data_conn_closed", "()V", (void*)android_location_GpsLocationProvider_agps_data_conn_closed},
{"native_agps_data_conn_failed", "()V", (void*)android_location_GpsLocationProvider_agps_data_conn_failed},
+ {"native_agps_set_id","(ILjava/lang/String;)V",(void*)android_location_GpsLocationProvider_agps_set_id},
+ {"native_agps_set_ref_location_cellid","(IIIII)V",(void*)android_location_GpsLocationProvider_agps_set_reference_location_cellid},
{"native_set_agps_server", "(ILjava/lang/String;I)V", (void*)android_location_GpsLocationProvider_set_agps_server},
{"native_send_ni_response", "(II)V", (void*)android_location_GpsLocationProvider_send_ni_response},
+ {"native_agps_ni_message", "([BI)V", (void *)android_location_GpsLocationProvider_agps_send_ni_message},
{"native_get_internal_state", "()Ljava/lang/String;", (void*)android_location_GpsLocationProvider_get_internal_state},
};
diff --git a/telephony/java/com/android/internal/telephony/CallManager.java b/telephony/java/com/android/internal/telephony/CallManager.java
index 09b7d05..7a026fa 100644
--- a/telephony/java/com/android/internal/telephony/CallManager.java
+++ b/telephony/java/com/android/internal/telephony/CallManager.java
@@ -1468,13 +1468,27 @@
*
*/
public Call getActiveFgCall() {
- for (Call call : mForegroundCalls) {
- if (call.getState() != Call.State.IDLE) {
+ Call call = getFirstNonIdleCall(mForegroundCalls);
+ if (call == null) {
+ call = (mDefaultPhone == null)
+ ? null
+ : mDefaultPhone.getForegroundCall();
+ }
+ return call;
+ }
+
+ // Returns the first call that is not in IDLE state. If both active calls
+ // and disconnecting/disconnected calls exist, return the first active call.
+ private Call getFirstNonIdleCall(List<Call> calls) {
+ Call result = null;
+ for (Call call : calls) {
+ if (!call.isIdle()) {
return call;
+ } else if (call.getState() != Call.State.IDLE) {
+ if (result == null) result = call;
}
}
- return (mDefaultPhone == null) ?
- null : mDefaultPhone.getForegroundCall();
+ return result;
}
/**
@@ -1491,13 +1505,13 @@
* Complete background calls list can be get by getBackgroundCalls()
*/
public Call getFirstActiveBgCall() {
- for (Call call : mBackgroundCalls) {
- if (call.getState() != Call.State.IDLE) {
- return call;
- }
+ Call call = getFirstNonIdleCall(mBackgroundCalls);
+ if (call == null) {
+ call = (mDefaultPhone == null)
+ ? null
+ : mDefaultPhone.getBackgroundCall();
}
- return (mDefaultPhone == null) ?
- null : mDefaultPhone.getBackgroundCall();
+ return call;
}
/**
@@ -1514,13 +1528,13 @@
* Complete ringing calls list can be get by getRingingCalls()
*/
public Call getFirstActiveRingingCall() {
- for (Call call : mRingingCalls) {
- if (!call.isIdle()) {
- return call;
- }
+ Call call = getFirstNonIdleCall(mRingingCalls);
+ if (call == null) {
+ call = (mDefaultPhone == null)
+ ? null
+ : mDefaultPhone.getRingingCall();
}
- return (mDefaultPhone == null) ?
- null : mDefaultPhone.getRingingCall();
+ return call;
}
/**
diff --git a/telephony/java/com/android/internal/telephony/CallerInfo.java b/telephony/java/com/android/internal/telephony/CallerInfo.java
index cf89848..360d35e 100644
--- a/telephony/java/com/android/internal/telephony/CallerInfo.java
+++ b/telephony/java/com/android/internal/telephony/CallerInfo.java
@@ -26,9 +26,9 @@
import android.text.TextUtils;
import android.telephony.TelephonyManager;
import android.telephony.PhoneNumberUtils;
-import android.util.Config;
import android.util.Log;
+
/**
* Looks up caller information for the given phone number.
*
@@ -36,6 +36,7 @@
*/
public class CallerInfo {
private static final String TAG = "CallerInfo";
+ private static final boolean VDBG = Log.isLoggable(TAG, Log.VERBOSE);
public static final String UNKNOWN_NUMBER = "-1";
public static final String PRIVATE_NUMBER = "-2";
@@ -128,7 +129,7 @@
info.isCachedPhotoCurrent = false;
info.contactExists = false;
- if (Config.LOGV) Log.v(TAG, "construct callerInfo from cursor");
+ if (VDBG) Log.v(TAG, "construct callerInfo from cursor");
if (cursor != null) {
if (cursor.moveToFirst()) {
@@ -166,31 +167,30 @@
// Look for the person ID.
// TODO: This is pretty ugly now, see bug 2269240 for
- // more details. With tel: URI the contact id is in
- // col "_id" while when we use a
- // content://contacts/data/phones URI, the contact id
- // is col "contact_id". As a work around we use the
- // type of the contact url to figure out which column
- // we should look at to get the contact_id.
-
- final String mimeType = context.getContentResolver().getType(contactRef);
+ // more details. The column to use depends upon the type of URL,
+ // for content://com.android.contacts/data/phones the "contact_id"
+ // column is used. For content/com.andriod.contacts/phone_lookup"
+ // the "_ID" column is used. If it is neither we leave columnIndex
+ // at -1 and no person ID will be available.
columnIndex = -1;
- if (Phone.CONTENT_ITEM_TYPE.equals(mimeType)) {
- // content://com.android.contacts/data/phones URL
+ String url = contactRef.toString();
+ if (url.startsWith("content://com.android.contacts/data/phones")) {
+ if (VDBG) Log.v(TAG,
+ "URL path starts with 'data/phones' using RawContacts.CONTACT_ID");
columnIndex = cursor.getColumnIndex(RawContacts.CONTACT_ID);
- } else {
- // content://com.android.contacts/phone_lookup URL
- // TODO: mime type is null here so we cannot test
- // if we have the right url type. phone_lookup URL
- // should resolve to a mime type.
+ } else if (url.startsWith("content://com.android.contacts/phone_lookup")) {
+ if (VDBG) Log.v(TAG,
+ "URL path starts with 'phone_lookup' using PhoneLookup._ID");
columnIndex = cursor.getColumnIndex(PhoneLookup._ID);
+ } else {
+ Log.e(TAG, "Bad contact URL '" + url + "'");
}
if (columnIndex != -1) {
info.person_id = cursor.getLong(columnIndex);
} else {
- Log.e(TAG, "Column missing for " + contactRef);
+ Log.e(TAG, "person_id column missing for " + contactRef);
}
// look for the custom ringtone, create from the string stored
diff --git a/telephony/java/com/android/internal/telephony/MccTable.java b/telephony/java/com/android/internal/telephony/MccTable.java
index b73c2f7..5539057 100644
--- a/telephony/java/com/android/internal/telephony/MccTable.java
+++ b/telephony/java/com/android/internal/telephony/MccTable.java
@@ -174,7 +174,7 @@
(438, 'tm', 2, 'Turkmenistan'),
(440, 'jp', 2, 'Asia/Tokyo', 'ja', 14, 'Japan'),
(441, 'jp', 2, 'Asia/Tokyo', 'ja', 14, 'Japan'),
- (450, 'kr', 2, 'Korea (Republic of)'),
+ (450, 'kr', 2, 'Asia/Seoul', 'ko', 13, 'Korea (Republic of)'),
(452, 'vn', 2, 'Viet Nam (Socialist Republic of)'),
(454, 'hk', 2, '"Hong Kong, China"'),
(455, 'mo', 2, '"Macao, China"'),
@@ -378,6 +378,7 @@
"",
"Africa/Johannesburg",
"Asia/Beijing",
+ "Asia/Seoul",
"Asia/Singapore",
"Asia/Tokyo",
"Australia/Sydney",
@@ -399,7 +400,8 @@
* AUTO GENERATED (by the Python code above)
*/
private static final String[] LANG_STRINGS = {
- "", "cs", "de", "en", "es", "fr", "it", "ja", "nl", "zh"
+ "", "cs", "de", "en", "es", "fr", "it", "ja", "ko", "nl",
+ "zh"
};
/**
@@ -446,13 +448,13 @@
* default language 4 bits
*/
private static final int[] IND_CODES = {
- 0x67720400, 0x6e6c6c68, 0x62650400, 0x667204b5, 0x6d630400, 0x61640400,
- 0x657304a4, 0x68750400, 0x62610400, 0x68720400, 0x72730400, 0x697404d6,
- 0x766104d6, 0x726f0400, 0x63680502, 0x637a6cc1, 0x736b0400, 0x61746ce2,
- 0x67626c93, 0x67626c93, 0x646b0400, 0x73650400, 0x6e6f0400, 0x66690400,
+ 0x67720400, 0x6e6c6c79, 0x62650400, 0x667204c5, 0x6d630400, 0x61640400,
+ 0x657304b4, 0x68750400, 0x62610400, 0x68720400, 0x72730400, 0x697404e6,
+ 0x766104e6, 0x726f0400, 0x63680512, 0x637a6cd1, 0x736b0400, 0x61746cf2,
+ 0x67626ca3, 0x67626ca3, 0x646b0400, 0x73650400, 0x6e6f0400, 0x66690400,
0x6c740400, 0x6c760400, 0x65650400, 0x72750400, 0x75610400, 0x62790400,
- 0x6d640400, 0x706c04f0, 0x64656c72, 0x67690400, 0x70740400, 0x6c750400,
- 0x69650483, 0x69730400, 0x616c0400, 0x6d740400, 0x63790400, 0x67650400,
+ 0x6d640400, 0x706c0500, 0x64656c82, 0x67690400, 0x70740400, 0x6c750400,
+ 0x69650493, 0x69730400, 0x616c0400, 0x6d740400, 0x63790400, 0x67650400,
0x616d0400, 0x62670400, 0x74720400, 0x666f0400, 0x67650400, 0x676c0400,
0x736d0400, 0x736c0400, 0x6d6b0400, 0x6c690400, 0x6d650400, 0x63615e00,
0x706d0400, 0x75735e03, 0x75735e03, 0x75735e03, 0x75735e03, 0x75735e03,
@@ -465,11 +467,11 @@
0x6c620400, 0x6a6f0400, 0x73790400, 0x69710400, 0x6b770400, 0x73610400,
0x79650400, 0x6f6d0400, 0x70730400, 0x61650400, 0x696c0400, 0x62680400,
0x71610400, 0x6d6e0400, 0x6e700400, 0x61650400, 0x61650400, 0x69720400,
- 0x757a0400, 0x746a0400, 0x6b670400, 0x746d0400, 0x6a707447, 0x6a707447,
- 0x6b720400, 0x766e0400, 0x686b0400, 0x6d6f0400, 0x6b680400, 0x6c610400,
- 0x636e6c29, 0x636e6c29, 0x74770400, 0x6b700400, 0x62640400, 0x6d760400,
- 0x6d790400, 0x61755c53, 0x69640400, 0x746c0400, 0x70680400, 0x74680400,
- 0x73675c33, 0x626e0400, 0x6e7a0513, 0x6d700400, 0x67750400, 0x6e720400,
+ 0x757a0400, 0x746a0400, 0x6b670400, 0x746d0400, 0x6a707457, 0x6a707457,
+ 0x6b726c38, 0x766e0400, 0x686b0400, 0x6d6f0400, 0x6b680400, 0x6c610400,
+ 0x636e6c2a, 0x636e6c2a, 0x74770400, 0x6b700400, 0x62640400, 0x6d760400,
+ 0x6d790400, 0x61755c63, 0x69640400, 0x746c0400, 0x70680400, 0x74680400,
+ 0x73675c43, 0x626e0400, 0x6e7a0523, 0x6d700400, 0x67750400, 0x6e720400,
0x70670400, 0x746f0400, 0x73620400, 0x76750400, 0x666a0400, 0x77660400,
0x61730400, 0x6b690400, 0x6e630400, 0x70660400, 0x636b0400, 0x77730400,
0x666d0400, 0x6d680400, 0x70770400, 0x65670400, 0x647a0400, 0x6d610400,
diff --git a/telephony/java/com/android/internal/telephony/WapPushOverSms.java b/telephony/java/com/android/internal/telephony/WapPushOverSms.java
index a636a4b..168b63b 100644
--- a/telephony/java/com/android/internal/telephony/WapPushOverSms.java
+++ b/telephony/java/com/android/internal/telephony/WapPushOverSms.java
@@ -132,6 +132,9 @@
case WspTypeDecoder.CONTENT_TYPE_B_VND_DOCOMO_PF:
mimeType = WspTypeDecoder.CONTENT_MIME_TYPE_B_VND_DOCOMO_PF;
break;
+ case WspTypeDecoder.CONTENT_TYPE_B_SUPL_INIT:
+ mimeType = WspTypeDecoder.CONTENT_MIME_TYPE_B_SUPL_INIT;
+ break;
default:
if (Config.LOGD) {
Log.w(LOG_TAG,
@@ -154,6 +157,8 @@
binaryContentType = WspTypeDecoder.CONTENT_TYPE_B_MMS;
} else if (mimeType.equals(WspTypeDecoder.CONTENT_MIME_TYPE_B_VND_DOCOMO_PF)) {
binaryContentType = WspTypeDecoder.CONTENT_TYPE_B_VND_DOCOMO_PF;
+ } else if (mimeType.equals(WspTypeDecoder.CONTENT_MIME_TYPE_B_SUPL_INIT)) {
+ binaryContentType = WspTypeDecoder.CONTENT_TYPE_B_SUPL_INIT;
} else {
if (Config.LOGD) Log.w(LOG_TAG, "Received PDU. Unknown Content-Type = " + mimeType);
return Intents.RESULT_SMS_HANDLED;
diff --git a/telephony/java/com/android/internal/telephony/WspTypeDecoder.java b/telephony/java/com/android/internal/telephony/WspTypeDecoder.java
index 336bc82..5dc89f0 100644
--- a/telephony/java/com/android/internal/telephony/WspTypeDecoder.java
+++ b/telephony/java/com/android/internal/telephony/WspTypeDecoder.java
@@ -40,6 +40,7 @@
public static final int CONTENT_TYPE_B_PUSH_CO = 0x32;
public static final int CONTENT_TYPE_B_MMS = 0x3e;
public static final int CONTENT_TYPE_B_VND_DOCOMO_PF = 0x0310;
+ public static final int CONTENT_TYPE_B_SUPL_INIT = 0x312;
public static final String CONTENT_MIME_TYPE_B_DRM_RIGHTS_XML =
"application/vnd.oma.drm.rights+xml";
@@ -50,6 +51,7 @@
public static final String CONTENT_MIME_TYPE_B_PUSH_CO = "application/vnd.wap.coc";
public static final String CONTENT_MIME_TYPE_B_MMS = "application/vnd.wap.mms-message";
public static final String CONTENT_MIME_TYPE_B_VND_DOCOMO_PF = "application/vnd.docomo.pf";
+ public static final String CONTENT_MIME_TYPE_B_SUPL_INIT = "application/vnd.omaloc-supl-init";
public static final int PARAMETER_ID_X_WAP_APPLICATION_ID = 0x2f;
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
index 90ecbd7..6ddb312 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
@@ -358,8 +358,14 @@
EVENT_SIM_RECORDS_LOADED, null);
mNeedToRegForSimLoaded = false;
}
- // restore the previous network selection.
- phone.restoreSavedNetworkSelection(null);
+
+ boolean skipRestoringSelection = phone.getContext().getResources().getBoolean(
+ com.android.internal.R.bool.skip_restoring_network_selection);
+
+ if (!skipRestoringSelection) {
+ // restore the previous network selection.
+ phone.restoreSavedNetworkSelection(null);
+ }
pollState();
// Signal strength polling stops when radio is off
queueNextSignalStrengthPoll();
diff --git a/telephony/java/com/android/internal/telephony/sip/SipPhone.java b/telephony/java/com/android/internal/telephony/sip/SipPhone.java
index 4fd4cdd..02af0ed 100755
--- a/telephony/java/com/android/internal/telephony/sip/SipPhone.java
+++ b/telephony/java/com/android/internal/telephony/sip/SipPhone.java
@@ -807,7 +807,10 @@
} catch (SipException e) {
throw new CallStateException("hangup(): " + e);
} finally {
- mAdapter.onCallEnded(DisconnectCause.LOCAL);
+ mAdapter.onCallEnded(((mState == Call.State.INCOMING)
+ || (mState == Call.State.WAITING))
+ ? DisconnectCause.INCOMING_REJECTED
+ : DisconnectCause.LOCAL);
}
}
}
diff --git a/telephony/mockril/Android.mk b/telephony/mockril/Android.mk
new file mode 100644
index 0000000..7c39cb1
--- /dev/null
+++ b/telephony/mockril/Android.mk
@@ -0,0 +1,31 @@
+#
+# 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.
+#
+#
+
+LOCAL_PATH:=$(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_JAVA_LIBRARIES := core framework
+
+LOCAL_STATIC_JAVA_LIBRARIES := librilproto-java
+
+LOCAL_MODULE_TAGS := debug
+LOCAL_MODULE := mockrilcontroller
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/telephony/mockril/src/com/android/internal/telephony/mockril/MockRilController.java b/telephony/mockril/src/com/android/internal/telephony/mockril/MockRilController.java
new file mode 100644
index 0000000..9b6a850
--- /dev/null
+++ b/telephony/mockril/src/com/android/internal/telephony/mockril/MockRilController.java
@@ -0,0 +1,156 @@
+/*
+ * 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.telephony.mockril;
+
+import android.os.Bundle;
+import android.util.Log;
+import android.telephony.PhoneNumberUtils;
+
+import com.android.internal.communication.MsgHeader;
+import com.android.internal.communication.Msg;
+import com.android.internal.telephony.RilChannel;
+import com.android.internal.telephony.ril_proto.RilCtrlCmds;
+import com.android.internal.telephony.ril_proto.RilCmds;
+import com.google.protobuf.micro.MessageMicro;
+
+import java.io.IOException;
+
+/**
+ * Contain a list of commands to control Mock RIL. Before using these commands the devices
+ * needs to be set with Mock RIL. Refer to hardware/ril/mockril/README.txt for details.
+ *
+ */
+public class MockRilController {
+ private static final String TAG = "MockRILController";
+ private RilChannel mRilChannel = null;
+ private Msg mMessage = null;
+
+ public MockRilController() throws IOException {
+ mRilChannel = RilChannel.makeRilChannel();
+ }
+
+ /**
+ * Close the channel after the communication is done.
+ * This method has to be called after the test is finished.
+ */
+ public void closeChannel() {
+ mRilChannel.close();
+ }
+
+ /**
+ * Send commands and return true on success
+ * @param cmd for MsgHeader
+ * @param token for MsgHeader
+ * @param status for MsgHeader
+ * @param pbData for Msg data
+ * @return true if command is sent successfully, false if it fails
+ */
+ private boolean sendCtrlCommand(int cmd, long token, int status, MessageMicro pbData) {
+ try {
+ Msg.send(mRilChannel, cmd, token, status, pbData);
+ } catch (IOException e) {
+ Log.v(TAG, "send command : %d failed: " + e.getStackTrace());
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Get control response
+ * @return Msg if response is received, else return null.
+ */
+ private Msg getCtrlResponse() {
+ Msg response = null;
+ try {
+ response = Msg.recv(mRilChannel);
+ } catch (IOException e) {
+ Log.v(TAG, "receive response for getRadioState() error: " + e.getStackTrace());
+ return null;
+ }
+ return response;
+ }
+
+ /**
+ * @return the radio state if it is valid, otherwise return -1
+ */
+ public int getRadioState() {
+ if (!sendCtrlCommand(RilCtrlCmds.CTRL_CMD_GET_RADIO_STATE, 0, 0, null)) {
+ return -1;
+ }
+ Msg response = getCtrlResponse();
+ if (response == null) {
+ Log.v(TAG, "failed to get response");
+ return -1;
+ }
+ response.printHeader(TAG);
+ RilCtrlCmds.CtrlRspRadioState resp =
+ response.getDataAs(RilCtrlCmds.CtrlRspRadioState.class);
+ int state = resp.getState();
+ if ((state >= RilCmds.RADIOSTATE_OFF) && (state <= RilCmds.RADIOSTATE_NV_READY))
+ return state;
+ else
+ return -1;
+ }
+
+ /**
+ * Set the radio state of mock ril to the given state
+ * @param state for given radio state
+ * @return true if the state is set successful, false if it fails
+ */
+ public boolean setRadioState(int state) {
+ RilCtrlCmds.CtrlReqRadioState req = new RilCtrlCmds.CtrlReqRadioState();
+ if (state < 0 || state > RilCmds.RADIOSTATE_NV_READY) {
+ Log.v(TAG, "the give radio state is not valid.");
+ return false;
+ }
+ req.setState(state);
+ if (!sendCtrlCommand(RilCtrlCmds.CTRL_CMD_SET_RADIO_STATE, 0, 0, req)) {
+ Log.v(TAG, "send set radio state request failed.");
+ return false;
+ }
+ Msg response = getCtrlResponse();
+ if (response == null) {
+ Log.v(TAG, "failed to get response for setRadioState");
+ return false;
+ }
+ response.printHeader(TAG);
+ RilCtrlCmds.CtrlRspRadioState resp =
+ response.getDataAs(RilCtrlCmds.CtrlRspRadioState.class);
+ int curstate = resp.getState();
+ return curstate == state;
+ }
+
+
+
+ /**
+ * Set an MT call
+ *
+ * @param phoneNumber for the number shown
+ */
+ public boolean setMTCall(String phoneNumber) {
+ RilCtrlCmds.CtrlReqSetMTCall req = new RilCtrlCmds.CtrlReqSetMTCall();
+
+ // Check whether it is a valid number
+ req.setPhoneNumber(phoneNumber);
+ if (!sendCtrlCommand(RilCtrlCmds.CTRL_CMD_SET_MT_CALL, 0, 0, req)) {
+ Log.v(TAG, "send CMD_SET_MT_CALL request failed");
+ return false;
+ }
+ return true;
+ }
+
+}
diff --git a/telephony/tests/telephonytests/Android.mk b/telephony/tests/telephonytests/Android.mk
index 45e265a..98e4403 100644
--- a/telephony/tests/telephonytests/Android.mk
+++ b/telephony/tests/telephonytests/Android.mk
@@ -5,6 +5,8 @@
LOCAL_SRC_FILES := $(call all-subdir-java-files)
+LOCAL_STATIC_JAVA_LIBRARIES := librilproto-java
+
LOCAL_JAVA_LIBRARIES := android.test.runner
LOCAL_PACKAGE_NAME := FrameworksTelephonyTests
diff --git a/telephony/tests/telephonytests/AndroidManifest.xml b/telephony/tests/telephonytests/AndroidManifest.xml
index 6a97423..ba1d957 100644
--- a/telephony/tests/telephonytests/AndroidManifest.xml
+++ b/telephony/tests/telephonytests/AndroidManifest.xml
@@ -32,6 +32,13 @@
android:targetPackage="com.android.frameworks.telephonytests"
android:label="Frameworks Telephony Tests">
</instrumentation>
+
+ <instrumentation android:name=".TelephonyMockRilTestRunner"
+ android:targetPackage="com.android.frameworks.telephonytests"
+ android:label="Test Runner for Mock Ril Tests"
+ />
+
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
+ <uses-permission android:name="android.permission.INTERNET" />
</manifest>
diff --git a/telephony/tests/telephonytests/src/com/android/frameworks/telephonytests/TelephonyMockRilTestRunner.java b/telephony/tests/telephonytests/src/com/android/frameworks/telephonytests/TelephonyMockRilTestRunner.java
new file mode 100644
index 0000000..9192f57
--- /dev/null
+++ b/telephony/tests/telephonytests/src/com/android/frameworks/telephonytests/TelephonyMockRilTestRunner.java
@@ -0,0 +1,93 @@
+/*
+ * 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.frameworks.telephonytests;
+
+import android.os.Bundle;
+
+import android.test.InstrumentationTestRunner;
+import android.test.InstrumentationTestSuite;
+import android.util.Log;
+
+import java.io.IOException;
+
+import com.android.internal.telephony.RilChannel;
+import com.android.internal.telephony.mockril.MockRilTest;
+
+import junit.framework.TestSuite;
+
+public class TelephonyMockRilTestRunner extends InstrumentationTestRunner {
+
+ public RilChannel mMockRilChannel;
+
+ @Override
+ public TestSuite getAllTests() {
+ log("getAllTests E");
+ TestSuite suite = new InstrumentationTestSuite(this);
+ suite.addTestSuite(MockRilTest.class);
+ log("getAllTests X");
+ return suite;
+ }
+
+ @Override
+ public ClassLoader getLoader() {
+ log("getLoader EX");
+ return TelephonyMockRilTestRunner.class.getClassLoader();
+ }
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ log("onCreate E");
+ try {
+ mMockRilChannel = RilChannel.makeRilChannel();
+ } catch (IOException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ log("onCreate X");
+
+ super.onCreate(icicle);
+ }
+
+ @Override
+ public void onDestroy() {
+ // I've not seen this called
+ log("onDestroy EX");
+ super.onDestroy();
+ }
+
+ @Override
+ public void onStart() {
+ // Called when the instrumentation thread is started.
+ // At the moment we don't need the thread so return
+ // which will shut down this unused thread.
+ log("onStart EX");
+ super.onStart();
+ }
+
+ @Override
+ public void finish(int resultCode, Bundle results) {
+ // Called when complete so I ask the mMockRilChannel to quit.
+ log("finish E");
+ mMockRilChannel.close();
+ log("finish X");
+ super.finish(resultCode, results);
+ }
+
+ private void log(String s) {
+ Log.e("TelephonyMockRilTestRunner", s);
+ }
+}
diff --git a/telephony/tests/telephonytests/src/com/android/internal/telephony/mockril/MockRilTest.java b/telephony/tests/telephonytests/src/com/android/internal/telephony/mockril/MockRilTest.java
new file mode 100644
index 0000000..f0d5b31
--- /dev/null
+++ b/telephony/tests/telephonytests/src/com/android/internal/telephony/mockril/MockRilTest.java
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony.mockril;
+
+import android.util.Log;
+import android.test.InstrumentationTestCase;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+import com.android.internal.communication.MsgHeader;
+import com.android.internal.communication.Msg;
+import com.android.internal.telephony.RilChannel;
+import com.android.internal.telephony.ril_proto.RilCtrlCmds;
+import com.android.internal.telephony.ril_proto.RilCmds;
+
+import com.android.frameworks.telephonytests.TelephonyMockRilTestRunner;
+import com.google.protobuf.micro.InvalidProtocolBufferMicroException;
+
+// Test suite for test ril
+public class MockRilTest extends InstrumentationTestCase {
+ private static final String TAG = "MockRilTest";
+
+ RilChannel mMockRilChannel;
+ TelephonyMockRilTestRunner mRunner;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mRunner = (TelephonyMockRilTestRunner)getInstrumentation();
+ mMockRilChannel = mRunner.mMockRilChannel;
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ }
+
+ static void log(String s) {
+ Log.v(TAG, s);
+ }
+
+ /**
+ * Test protobuf serialization and deserialization
+ * @throws InvalidProtocolBufferMicroException
+ */
+ public void testProtobufSerDes() throws InvalidProtocolBufferMicroException {
+ log("testProtobufSerdes E");
+
+ RilCtrlCmds.CtrlRspRadioState rs = new RilCtrlCmds.CtrlRspRadioState();
+ assertTrue(String.format("expected rs.state == 0 was %d", rs.getState()),
+ rs.getState() == 0);
+ rs.setState(1);
+ assertTrue(String.format("expected rs.state == 1 was %d", rs.getState()),
+ rs.getState() == 1);
+
+ byte[] rs_ser = rs.toByteArray();
+ RilCtrlCmds.CtrlRspRadioState rsNew = RilCtrlCmds.CtrlRspRadioState.parseFrom(rs_ser);
+ assertTrue(String.format("expected rsNew.state == 1 was %d", rs.getState()),
+ rs.getState() == 1);
+
+ log("testProtobufSerdes X");
+ }
+
+ /**
+ * Test echo command works using writeMsg & readMsg
+ */
+ public void testEchoMsg() throws IOException {
+ log("testEchoMsg E");
+
+ MsgHeader mh = new MsgHeader();
+ mh.setCmd(0);
+ mh.setToken(1);
+ mh.setStatus(2);
+ ByteBuffer data = ByteBuffer.allocate(3);
+ data.put((byte)3);
+ data.put((byte)4);
+ data.put((byte)5);
+ Msg.send(mMockRilChannel, mh, data);
+
+ Msg respMsg = Msg.recv(mMockRilChannel);
+ assertTrue(String.format("expected mhd.header.cmd == 0 was %d",respMsg.getCmd()),
+ respMsg.getCmd() == 0);
+ assertTrue(String.format("expected mhd.header.token == 1 was %d",respMsg.getToken()),
+ respMsg.getToken() == 1);
+ assertTrue(String.format("expected mhd.header.status == 2 was %d", respMsg.getStatus()),
+ respMsg.getStatus() == 2);
+ assertTrue(String.format("expected mhd.data[0] == 3 was %d", respMsg.getData(0)),
+ respMsg.getData(0) == 3);
+ assertTrue(String.format("expected mhd.data[1] == 4 was %d", respMsg.getData(1)),
+ respMsg.getData(1) == 4);
+ assertTrue(String.format("expected mhd.data[2] == 5 was %d", respMsg.getData(2)),
+ respMsg.getData(2) == 5);
+
+ log("testEchoMsg X");
+ }
+
+ /**
+ * Test get as
+ */
+ public void testGetAs() {
+ log("testGetAs E");
+
+ // Use a message header as the protobuf data content
+ MsgHeader mh = new MsgHeader();
+ mh.setCmd(12345);
+ mh.setToken(9876);
+ mh.setStatus(7654);
+ mh.setLengthData(4321);
+ byte[] data = mh.toByteArray();
+ MsgHeader mhResult = Msg.getAs(MsgHeader.class, data);
+
+ assertTrue(String.format("expected cmd == 12345 was %d", mhResult.getCmd()),
+ mhResult.getCmd() == 12345);
+ assertTrue(String.format("expected token == 9876 was %d", mhResult.getToken()),
+ mhResult.getToken() == 9876);
+ assertTrue(String.format("expected status == 7654 was %d", mhResult.getStatus()),
+ mhResult.getStatus() == 7654);
+ assertTrue(String.format("expected lengthData == 4321 was %d", mhResult.getLengthData()),
+ mhResult.getLengthData() == 4321);
+
+ Msg msg = Msg.obtain();
+ msg.setData(ByteBuffer.wrap(data));
+
+ mhResult = msg.getDataAs(MsgHeader.class);
+
+ assertTrue(String.format("expected cmd == 12345 was %d", mhResult.getCmd()),
+ mhResult.getCmd() == 12345);
+ assertTrue(String.format("expected token == 9876 was %d", mhResult.getToken()),
+ mhResult.getToken() == 9876);
+ assertTrue(String.format("expected status == 7654 was %d", mhResult.getStatus()),
+ mhResult.getStatus() == 7654);
+ assertTrue(String.format("expected lengthData == 4321 was %d", mhResult.getLengthData()),
+ mhResult.getLengthData() == 4321);
+
+ log("testGetAs X");
+ }
+
+ public void testGetRadioState() throws IOException {
+ log("testGetRadioState E");
+
+ Msg.send(mMockRilChannel, 1, 9876, 0, null);
+
+ Msg resp = Msg.recv(mMockRilChannel);
+ //resp.printHeader("testGetRadioState");
+
+ assertTrue(String.format("expected cmd == 1 was %d", resp.getCmd()),
+ resp.getCmd() == 1);
+ assertTrue(String.format("expected token == 9876 was %d", resp.getToken()),
+ resp.getToken() == 9876);
+ assertTrue(String.format("expected status == 0 was %d", resp.getStatus()),
+ resp.getStatus() == 0);
+
+ RilCtrlCmds.CtrlRspRadioState rsp = resp.getDataAs(RilCtrlCmds.CtrlRspRadioState.class);
+
+ int state = rsp.getState();
+ log("testGetRadioState state=" + state);
+ assertTrue(String.format("expected RadioState >= 0 && RadioState <= 9 was %d", state),
+ ((state >= 0) && (state <= 9)));
+
+ log("testGetRadioState X");
+ }
+
+ public void testSetRadioState() throws IOException {
+ log("testSetRadioState E");
+
+ RilCtrlCmds.CtrlReqRadioState cmdrs = new RilCtrlCmds.CtrlReqRadioState();
+ assertEquals(0, cmdrs.getState());
+
+ cmdrs.setState(RilCmds.RADIOSTATE_SIM_NOT_READY);
+ assertEquals(2, cmdrs.getState());
+
+ Msg.send(mMockRilChannel, RilCtrlCmds.CTRL_CMD_SET_RADIO_STATE, 0, 0, cmdrs);
+
+ Msg resp = Msg.recv(mMockRilChannel);
+
+ RilCtrlCmds.CtrlRspRadioState rsp = resp.getDataAs(RilCtrlCmds.CtrlRspRadioState.class);
+
+ int state = rsp.getState();
+ log("get response for testSetRadioState: " + state);
+ assertTrue(RilCmds.RADIOSTATE_SIM_NOT_READY == state);
+ }
+}
diff --git a/tests/StatusBar/src/com/android/statusbartest/PowerTest.java b/tests/StatusBar/src/com/android/statusbartest/PowerTest.java
index f778cab..178fa92 100644
--- a/tests/StatusBar/src/com/android/statusbartest/PowerTest.java
+++ b/tests/StatusBar/src/com/android/statusbartest/PowerTest.java
@@ -49,6 +49,8 @@
int mPokeState = 0;
IBinder mPokeToken = new Binder();
Handler mHandler = new Handler();
+ PowerManager mPm;
+ PowerManager.WakeLock mProx;
@Override
protected String tag() {
@@ -58,10 +60,27 @@
@Override
protected Test[] tests() {
mPowerManager = IPowerManager.Stub.asInterface(ServiceManager.getService("power"));
+ mPm = (PowerManager)getSystemService("power");
+ mProx = mPm.newWakeLock(PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK, "PowerTest-prox");
return mTests;
}
private Test[] mTests = new Test[] {
+ new Test("Enable proximity") {
+ public void run() {
+ mProx.acquire();
+ }
+ },
+ new Test("Disable proximity") {
+ public void run() {
+ mProx.release();
+ }
+ },
+ new Test("Disable proximity (WAIT_FOR_PROXIMITY_NEGATIVE)") {
+ public void run() {
+ mProx.release(PowerManager.WAIT_FOR_PROXIMITY_NEGATIVE);
+ }
+ },
new Test("Cheek events don't poke") {
public void run() {
mPokeState |= LocalPowerManager.POKE_LOCK_IGNORE_CHEEK_EVENTS;
@@ -72,6 +91,7 @@
}
}
},
+
new Test("Cheek events poke") {
public void run() {
mPokeState &= ~LocalPowerManager.POKE_LOCK_IGNORE_CHEEK_EVENTS;
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeContext.java
index 744bfbe..d5a90e6 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeContext.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeContext.java
@@ -245,8 +245,8 @@
BridgeXmlBlockParser parser = null;
if (set instanceof BridgeXmlBlockParser) {
parser = (BridgeXmlBlockParser)set;
- } else {
- // reall this should not be happening since its instantiated in Bridge
+ } else if (set != null) { // null parser is ok
+ // really this should not be happening since its instantiated in Bridge
mLogger.error("Parser is not a BridgeXmlBlockParser!");
return null;
}
@@ -255,13 +255,16 @@
TreeMap<Integer, String> styleNameMap = searchAttrs(attrs, frameworkAttributes);
BridgeTypedArray ta = ((BridgeResources) mResources).newTypeArray(attrs.length,
- parser.isPlatformFile());
+ parser != null ? parser.isPlatformFile() : true);
// resolve the defStyleAttr value into a IStyleResourceValue
IStyleResourceValue defStyleValues = null;
// look for a custom style.
- String customStyle = parser.getAttributeValue(null /* namespace*/, "style");
+ String customStyle = null;
+ if (parser != null) {
+ customStyle = parser.getAttributeValue(null /* namespace*/, "style");
+ }
if (customStyle != null) {
IResourceValue item = findResValue(customStyle);
@@ -308,7 +311,10 @@
int index = styleAttribute.getKey().intValue();
String name = styleAttribute.getValue();
- String value = parser.getAttributeValue(namespace, name);
+ String value = null;
+ if (parser != null) {
+ value = parser.getAttributeValue(namespace, name);
+ }
// if there's no direct value for this attribute in the XML, we look for default
// values in the widget defStyle, and then in the theme.
diff --git a/voip/java/android/net/sip/SipAudioCall.java b/voip/java/android/net/sip/SipAudioCall.java
index c23da20..f55bade 100644
--- a/voip/java/android/net/sip/SipAudioCall.java
+++ b/voip/java/android/net/sip/SipAudioCall.java
@@ -43,9 +43,11 @@
import java.util.Map;
/**
- * Class that handles an audio call over SIP.
+ * Class that handles an Internet audio call over SIP. {@link SipManager}
+ * facilitates instantiating a {@code SipAudioCall} object for making/receiving
+ * calls. See {@link SipManager#makeAudioCall} and
+ * {@link SipManager#takeAudioCall}.
*/
-/** @hide */
public class SipAudioCall {
private static final String TAG = SipAudioCall.class.getSimpleName();
private static final boolean RELEASE_SOCKET = true;
@@ -56,7 +58,7 @@
public static class Listener {
/**
* Called when the call object is ready to make another call.
- * The default implementation calls {@link #onChange}.
+ * The default implementation calls {@link #onChanged}.
*
* @param call the call object that is ready to make another call
*/
@@ -66,7 +68,7 @@
/**
* Called when a request is sent out to initiate a new call.
- * The default implementation calls {@link #onChange}.
+ * The default implementation calls {@link #onChanged}.
*
* @param call the call object that carries out the audio call
*/
@@ -76,7 +78,7 @@
/**
* Called when a new call comes in.
- * The default implementation calls {@link #onChange}.
+ * The default implementation calls {@link #onChanged}.
*
* @param call the call object that carries out the audio call
* @param caller the SIP profile of the caller
@@ -87,7 +89,7 @@
/**
* Called when a RINGING response is received for the INVITE request
- * sent. The default implementation calls {@link #onChange}.
+ * sent. The default implementation calls {@link #onChanged}.
*
* @param call the call object that carries out the audio call
*/
@@ -97,7 +99,7 @@
/**
* Called when the session is established.
- * The default implementation calls {@link #onChange}.
+ * The default implementation calls {@link #onChanged}.
*
* @param call the call object that carries out the audio call
*/
@@ -107,7 +109,7 @@
/**
* Called when the session is terminated.
- * The default implementation calls {@link #onChange}.
+ * The default implementation calls {@link #onChanged}.
*
* @param call the call object that carries out the audio call
*/
@@ -117,7 +119,7 @@
/**
* Called when the peer is busy during session initialization.
- * The default implementation calls {@link #onChange}.
+ * The default implementation calls {@link #onChanged}.
*
* @param call the call object that carries out the audio call
*/
@@ -127,7 +129,7 @@
/**
* Called when the call is on hold.
- * The default implementation calls {@link #onChange}.
+ * The default implementation calls {@link #onChanged}.
*
* @param call the call object that carries out the audio call
*/
@@ -257,8 +259,10 @@
*
* @return true if the call is established
*/
- public synchronized boolean isInCall() {
- return mInCall;
+ public boolean isInCall() {
+ synchronized (this) {
+ return mInCall;
+ }
}
/**
@@ -266,8 +270,10 @@
*
* @return true if the call is on hold
*/
- public synchronized boolean isOnHold() {
- return mHold;
+ public boolean isOnHold() {
+ synchronized (this) {
+ return mHold;
+ }
}
/**
@@ -299,8 +305,10 @@
*
* @return the local SIP profile
*/
- public synchronized SipProfile getLocalProfile() {
- return mLocalProfile;
+ public SipProfile getLocalProfile() {
+ synchronized (this) {
+ return mLocalProfile;
+ }
}
/**
@@ -308,8 +316,10 @@
*
* @return the peer's SIP profile
*/
- public synchronized SipProfile getPeerProfile() {
- return (mSipSession == null) ? null : mSipSession.getPeerProfile();
+ public SipProfile getPeerProfile() {
+ synchronized (this) {
+ return (mSipSession == null) ? null : mSipSession.getPeerProfile();
+ }
}
/**
@@ -318,9 +328,11 @@
*
* @return the session state
*/
- public synchronized int getState() {
- if (mSipSession == null) return SipSession.State.READY_TO_CALL;
- return mSipSession.getState();
+ public int getState() {
+ synchronized (this) {
+ if (mSipSession == null) return SipSession.State.READY_TO_CALL;
+ return mSipSession.getState();
+ }
}
@@ -330,8 +342,10 @@
* @return the session object that carries this call
* @hide
*/
- public synchronized SipSession getSipSession() {
- return mSipSession;
+ public SipSession getSipSession() {
+ synchronized (this) {
+ return mSipSession;
+ }
}
private SipSession.Listener createListener() {
@@ -364,22 +378,25 @@
}
@Override
- public synchronized void onRinging(SipSession session,
+ public void onRinging(SipSession session,
SipProfile peerProfile, String sessionDescription) {
- if ((mSipSession == null) || !mInCall
- || !session.getCallId().equals(mSipSession.getCallId())) {
- // should not happen
- session.endCall();
- return;
- }
+ synchronized (SipAudioCall.this) {
+ 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();
+ // session changing request
+ try {
+ String answer = createAnswer(sessionDescription).encode();
+ mSipSession.answerCall(answer, SESSION_TIMEOUT);
+ } catch (Throwable e) {
+ Log.e(TAG, "onRinging()", e);
+ session.endCall();
+ }
}
}
@@ -508,18 +525,22 @@
* @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());
+ public void attachCall(SipSession session, String sessionDescription)
+ throws SipException {
+ synchronized (this) {
+ 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);
+ if (getState() == SipSession.State.INCOMING_CALL) {
+ startRinging();
+ }
+ } catch (Throwable e) {
+ Log.e(TAG, "attachCall()", e);
+ throwSipException(e);
+ }
}
}
@@ -529,7 +550,7 @@
* and {@code Listener.onError(SipAudioCall, SipErrorCode.TIME_OUT, String)}
* will be called.
*
- * @param callee the SIP profile to make the call to
+ * @param peerProfile the SIP profile to make the call to
* @param sipSession the {@link SipSession} for carrying out the call
* @param timeout the timeout value in seconds. Default value (defined by
* SIP protocol) is used if {@code timeout} is zero or negative.
@@ -537,15 +558,19 @@
* @throws SipException if the SIP service fails to create a session for the
* call
*/
- public synchronized void makeCall(SipProfile peerProfile,
- SipSession sipSession, int timeout) throws SipException {
- mSipSession = sipSession;
- try {
- mAudioStream = new AudioStream(InetAddress.getByName(getLocalIp()));
- sipSession.setListener(createListener());
- sipSession.makeCall(peerProfile, createOffer().encode(), timeout);
- } catch (IOException e) {
- throw new SipException("makeCall()", e);
+ public void makeCall(SipProfile peerProfile, SipSession sipSession,
+ int timeout) throws SipException {
+ synchronized (this) {
+ mSipSession = sipSession;
+ try {
+ mAudioStream = new AudioStream(InetAddress.getByName(
+ getLocalIp()));
+ sipSession.setListener(createListener());
+ sipSession.makeCall(peerProfile, createOffer().encode(),
+ timeout);
+ } catch (IOException e) {
+ throw new SipException("makeCall()", e);
+ }
}
}
@@ -553,13 +578,15 @@
* 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;
+ public void endCall() throws SipException {
+ synchronized (this) {
+ stopRinging();
+ stopCall(RELEASE_SOCKET);
+ mInCall = false;
- // perform the above local ops first and then network op
- if (mSipSession != null) mSipSession.endCall();
+ // perform the above local ops first and then network op
+ if (mSipSession != null) mSipSession.endCall();
+ }
}
/**
@@ -574,13 +601,15 @@
* @see Listener.onError
* @throws SipException if the SIP service fails to hold the call
*/
- public synchronized void holdCall(int timeout) throws SipException {
+ public void holdCall(int timeout) throws SipException {
+ synchronized (this) {
if (mHold) return;
- mSipSession.changeCall(createHoldOffer().encode(), timeout);
- mHold = true;
+ mSipSession.changeCall(createHoldOffer().encode(), timeout);
+ mHold = true;
- AudioGroup audioGroup = getAudioGroup();
- if (audioGroup != null) audioGroup.setMode(AudioGroup.MODE_ON_HOLD);
+ AudioGroup audioGroup = getAudioGroup();
+ if (audioGroup != null) audioGroup.setMode(AudioGroup.MODE_ON_HOLD);
+ }
}
/**
@@ -594,13 +623,16 @@
* @see Listener.onError
* @throws SipException if the SIP service fails to answer the call
*/
- 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);
+ public void answerCall(int timeout) throws SipException {
+ synchronized (this) {
+ stopRinging();
+ try {
+ mAudioStream = new AudioStream(InetAddress.getByName(
+ getLocalIp()));
+ mSipSession.answerCall(createAnswer(mPeerSd).encode(), timeout);
+ } catch (IOException e) {
+ throw new SipException("answerCall()", e);
+ }
}
}
@@ -616,12 +648,14 @@
* @see Listener.onError
* @throws SipException if the SIP service fails to unhold the call
*/
- 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);
+ public void continueCall(int timeout) throws SipException {
+ synchronized (this) {
+ if (!mHold) return;
+ mSipSession.changeCall(createContinueOffer().encode(), timeout);
+ mHold = false;
+ AudioGroup audioGroup = getAudioGroup();
+ if (audioGroup != null) audioGroup.setMode(AudioGroup.MODE_NORMAL);
+ }
}
private SimpleSessionDescription createOffer() {
@@ -739,12 +773,15 @@
}
/** Toggles mute. */
- public synchronized void toggleMute() {
- AudioGroup audioGroup = getAudioGroup();
- if (audioGroup != null) {
- audioGroup.setMode(
- mMuted ? AudioGroup.MODE_NORMAL : AudioGroup.MODE_MUTED);
- mMuted = !mMuted;
+ public void toggleMute() {
+ synchronized (this) {
+ AudioGroup audioGroup = getAudioGroup();
+ if (audioGroup != null) {
+ audioGroup.setMode(mMuted
+ ? AudioGroup.MODE_NORMAL
+ : AudioGroup.MODE_MUTED);
+ mMuted = !mMuted;
+ }
}
}
@@ -753,14 +790,18 @@
*
* @return true if the call is muted
*/
- public synchronized boolean isMuted() {
- return mMuted;
+ public boolean isMuted() {
+ synchronized (this) {
+ return mMuted;
+ }
}
/** Puts the device to speaker mode. */
- public synchronized void setSpeakerMode(boolean speakerMode) {
- ((AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE))
- .setSpeakerphoneOn(speakerMode);
+ public void setSpeakerMode(boolean speakerMode) {
+ synchronized (this) {
+ ((AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE))
+ .setSpeakerphoneOn(speakerMode);
+ }
}
/**
@@ -785,14 +826,16 @@
* inputs.
* @param result the result message to send when done
*/
- 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);
+ public void sendDtmf(int code, Message result) {
+ synchronized (this) {
+ 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();
}
- if (result != null) result.sendToTarget();
}
/**
@@ -806,8 +849,10 @@
* yet been set up
* @hide
*/
- public synchronized AudioStream getAudioStream() {
- return mAudioStream;
+ public AudioStream getAudioStream() {
+ synchronized (this) {
+ return mAudioStream;
+ }
}
/**
@@ -824,9 +869,11 @@
* @see #getAudioStream
* @hide
*/
- public synchronized AudioGroup getAudioGroup() {
- if (mAudioGroup != null) return mAudioGroup;
- return ((mAudioStream == null) ? null : mAudioStream.getGroup());
+ public AudioGroup getAudioGroup() {
+ synchronized (this) {
+ if (mAudioGroup != null) return mAudioGroup;
+ return ((mAudioStream == null) ? null : mAudioStream.getGroup());
+ }
}
/**
@@ -837,11 +884,13 @@
* @see #getAudioStream
* @hide
*/
- public synchronized void setAudioGroup(AudioGroup group) {
- if ((mAudioStream != null) && (mAudioStream.getGroup() != null)) {
- mAudioStream.join(group);
+ public void setAudioGroup(AudioGroup group) {
+ synchronized (this) {
+ if ((mAudioStream != null) && (mAudioStream.getGroup() != null)) {
+ mAudioStream.join(group);
+ }
+ mAudioGroup = group;
}
- mAudioGroup = group;
}
/**
@@ -981,8 +1030,10 @@
*
* @param enabled true to enable; false to disable
*/
- public synchronized void setRingbackToneEnabled(boolean enabled) {
- mRingbackToneEnabled = enabled;
+ public void setRingbackToneEnabled(boolean enabled) {
+ synchronized (this) {
+ mRingbackToneEnabled = enabled;
+ }
}
/**
@@ -990,8 +1041,10 @@
*
* @param enabled true to enable; false to disable
*/
- public synchronized void setRingtoneEnabled(boolean enabled) {
- mRingtoneEnabled = enabled;
+ public void setRingtoneEnabled(boolean enabled) {
+ synchronized (this) {
+ mRingtoneEnabled = enabled;
+ }
}
private void startRingbackTone() {
diff --git a/voip/java/android/net/sip/SipErrorCode.java b/voip/java/android/net/sip/SipErrorCode.java
index a55ab25..6aee5f1 100644
--- a/voip/java/android/net/sip/SipErrorCode.java
+++ b/voip/java/android/net/sip/SipErrorCode.java
@@ -19,10 +19,9 @@
/**
* Defines error code returned in
* {@link SipRegistrationListener#onRegistrationFailed},
- * {@link ISipSessionListener#onError},
- * {@link ISipSessionListener#onCallChangeFailed} and
- * {@link ISipSessionListener#onRegistrationFailed}.
- * @hide
+ * {@link SipSession.Listener#onError},
+ * {@link SipSession.Listener#onCallChangeFailed} and
+ * {@link SipSession.Listener#onRegistrationFailed}.
*/
public class SipErrorCode {
/** Not an error. */
diff --git a/voip/java/android/net/sip/SipException.java b/voip/java/android/net/sip/SipException.java
index f0d846b..225b94f 100644
--- a/voip/java/android/net/sip/SipException.java
+++ b/voip/java/android/net/sip/SipException.java
@@ -18,7 +18,6 @@
/**
* General SIP-related exception class.
- * @hide
*/
public class SipException extends Exception {
public SipException() {
diff --git a/voip/java/android/net/sip/SipManager.java b/voip/java/android/net/sip/SipManager.java
index 80c35fb..ee0e3cd 100644
--- a/voip/java/android/net/sip/SipManager.java
+++ b/voip/java/android/net/sip/SipManager.java
@@ -48,7 +48,8 @@
* <li>process SIP events directly with a {@link SipSession} created by
* {@link #createSipSession}.</li>
* </ul>
- * @hide
+ * {@code SipManager} can only be instantiated if SIP API is supported by the
+ * device. (See {@link #isApiSupported}).
*/
public class SipManager {
/**
@@ -58,13 +59,27 @@
*/
public static final int INCOMING_CALL_RESULT_CODE = 101;
- /** Part of the incoming call intent. */
+ /**
+ * Key to retrieve the call ID from an incoming call intent.
+ * @see #open(SipProfile, PendingIntent, SipRegistrationListener)
+ */
public static final String EXTRA_CALL_ID = "android:sipCallID";
- /** Part of the incoming call intent. */
+ /**
+ * Key to retrieve the offered session description from an incoming call
+ * intent.
+ * @see #open(SipProfile, PendingIntent, SipRegistrationListener)
+ */
public static final String EXTRA_OFFER_SD = "android:sipOfferSD";
/**
+ * Action to broadcast when SipService is up.
+ * Internal use only.
+ * @hide
+ */
+ public static final String ACTION_SIP_SERVICE_UP =
+ "android.net.sip.SIP_SERVICE_UP";
+ /**
* Action string for the incoming call intent for the Phone app.
* Internal use only.
* @hide
@@ -171,7 +186,11 @@
* 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.
+ * in order to receive calls from the provider. When the SIP service
+ * receives a new call, it will send out an intent with the provided action
+ * string. The intent contains a call ID extra and an offer session
+ * description string extra. Use {@link #getCallId} and
+ * {@link #getOfferSessionDescription} to retrieve those extras.
*
* @param localProfile the SIP profile to receive incoming calls for
* @param incomingCallPendingIntent When an incoming call is received, the
@@ -187,6 +206,9 @@
* @throws NullPointerException if {@code incomingCallPendingIntent} is null
* @throws SipException if the profile contains incorrect settings or
* calling the SIP service results in an error
+ * @see #isIncomingCallIntent
+ * @see #getCallId
+ * @see #getOfferSessionDescription
*/
public void open(SipProfile localProfile,
PendingIntent incomingCallPendingIntent,
@@ -284,7 +306,8 @@
* @param peerProfile the SIP profile to make the call to
* @param listener to listen to the call events from {@link SipAudioCall};
* can be null
- * @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.
* @return a {@link SipAudioCall} object
* @throws SipException if calling the SIP service results in an error
* @see SipAudioCall.Listener.onError
@@ -314,7 +337,8 @@
* @param peerProfileUri URI of the SIP profile to make the call to
* @param listener to listen to the call events from {@link SipAudioCall};
* can be null
- * @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.
* @return a {@link SipAudioCall} object
* @throws SipException if calling the SIP service results in an error
* @see SipAudioCall.Listener.onError
@@ -482,7 +506,7 @@
}
/**
- * Gets the {@link ISipSession} that handles the incoming call. For audio
+ * Gets the {@link SipSession} that handles the incoming call. For audio
* calls, consider to use {@link SipAudioCall} to handle the incoming call.
* See {@link #takeAudioCall}. Note that the method may be called only once
* for the same intent. For subsequent calls on the same intent, the method
@@ -491,11 +515,12 @@
* @param incomingCallIntent the incoming call broadcast intent
* @return the session object that handles the incoming call
*/
- public ISipSession getSessionFor(Intent incomingCallIntent)
+ public SipSession getSessionFor(Intent incomingCallIntent)
throws SipException {
try {
String callId = getCallId(incomingCallIntent);
- return mSipService.getPendingSession(callId);
+ ISipSession s = mSipService.getPendingSession(callId);
+ return new SipSession(s);
} catch (RemoteException e) {
throw new SipException("getSessionFor()", e);
}
@@ -507,8 +532,8 @@
}
/**
- * Creates a {@link ISipSession} with the specified profile. Use other
- * methods, if applicable, instead of interacting with {@link ISipSession}
+ * Creates a {@link SipSession} with the specified profile. Use other
+ * methods, if applicable, instead of interacting with {@link SipSession}
* directly.
*
* @param localProfile the SIP profile the session is associated with
diff --git a/voip/java/android/net/sip/SipProfile.java b/voip/java/android/net/sip/SipProfile.java
index 6d5cb3c..dddb07d 100644
--- a/voip/java/android/net/sip/SipProfile.java
+++ b/voip/java/android/net/sip/SipProfile.java
@@ -33,7 +33,6 @@
/**
* Class containing a SIP account, domain and server information.
- * @hide
*/
public class SipProfile implements Parcelable, Serializable, Cloneable {
private static final long serialVersionUID = 1L;
diff --git a/voip/java/android/net/sip/SipRegistrationListener.java b/voip/java/android/net/sip/SipRegistrationListener.java
index 37c9ce2..e1f35ad 100644
--- a/voip/java/android/net/sip/SipRegistrationListener.java
+++ b/voip/java/android/net/sip/SipRegistrationListener.java
@@ -18,7 +18,6 @@
/**
* Listener class to listen to SIP registration events.
- * @hide
*/
public interface SipRegistrationListener {
/**
diff --git a/voip/java/android/net/sip/SipSession.java b/voip/java/android/net/sip/SipSession.java
index 0cc7206..9c08e46 100644
--- a/voip/java/android/net/sip/SipSession.java
+++ b/voip/java/android/net/sip/SipSession.java
@@ -22,14 +22,12 @@
/**
* 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. */
@@ -101,7 +99,6 @@
/**
* Listener class that listens to {@link SipSession} events.
- * @hide
*/
public static class Listener {
/**
@@ -281,7 +278,7 @@
/**
* Gets the session state. The value returned must be one of the states in
- * {@link SipSessionState}.
+ * {@link State}.
*
* @return the session state
*/
@@ -339,7 +336,7 @@
* 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}.
+ * in {@link State#READY_TO_CALL}.
*
* @param duration duration in second before the registration expires
* @see Listener
@@ -357,7 +354,7 @@
* 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}.
+ * session state is in {@link State#READY_TO_CALL}.
*
* @see Listener
*/
@@ -372,7 +369,7 @@
/**
* 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}.
+ * the session state is in {@link State#READY_TO_CALL}.
*
* @param callee the SIP profile to make the call to
* @param sessionDescription the session description of this call
@@ -393,7 +390,7 @@
/**
* 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}.
+ * {@link State#INCOMING_CALL}.
*
* @param sessionDescription the session description to answer this call
* @param timeout the session will be timed out if the call is not
@@ -411,10 +408,10 @@
/**
* 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}.
+ * in {@link State#IN_CALL},
+ * {@link State#INCOMING_CALL},
+ * {@link State#OUTGOING_CALL} or
+ * {@link State#OUTGOING_CALL_RING_BACK}.
*/
public void endCall() {
try {
@@ -426,7 +423,7 @@
/**
* Changes the session description during a call. The method is only valid
- * to call when the session state is in {@link SipSessionState#IN_CALL}.
+ * to call when the session state is in {@link State#IN_CALL}.
*
* @param sessionDescription the new session description
* @param timeout the session will be timed out if the call is not
diff --git a/voip/java/com/android/server/sip/SipService.java b/voip/java/com/android/server/sip/SipService.java
index a7c61e5..db1931b 100644
--- a/voip/java/com/android/server/sip/SipService.java
+++ b/voip/java/com/android/server/sip/SipService.java
@@ -100,6 +100,7 @@
public static void start(Context context) {
if (SipManager.isApiSupported(context)) {
ServiceManager.addService("sip", new SipService(context));
+ context.sendBroadcast(new Intent(SipManager.ACTION_SIP_SERVICE_UP));
Log.i(TAG, "SIP service started");
}
}
@@ -122,6 +123,8 @@
}
public synchronized SipProfile[] getListOfProfiles() {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.USE_SIP, null);
boolean isCallerRadio = isCallerRadio();
ArrayList<SipProfile> profiles = new ArrayList<SipProfile>();
for (SipSessionGroupExt group : mSipGroups.values()) {
@@ -133,6 +136,8 @@
}
public void open(SipProfile localProfile) {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.USE_SIP, null);
localProfile.setCallingUid(Binder.getCallingUid());
try {
createGroup(localProfile);
@@ -145,6 +150,8 @@
public synchronized void open3(SipProfile localProfile,
PendingIntent incomingCallPendingIntent,
ISipSessionListener listener) {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.USE_SIP, null);
localProfile.setCallingUid(Binder.getCallingUid());
if (incomingCallPendingIntent == null) {
Log.w(TAG, "incomingCallPendingIntent cannot be null; "
@@ -158,7 +165,7 @@
incomingCallPendingIntent, listener);
if (localProfile.getAutoRegistration()) {
group.openToReceiveCalls();
- if (isWifiOn()) grabWifiLock();
+ if (isWifiActive()) grabWifiLock();
}
} catch (SipException e) {
Log.e(TAG, "openToReceiveCalls()", e);
@@ -180,6 +187,8 @@
}
public synchronized void close(String localProfileUri) {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.USE_SIP, null);
SipSessionGroupExt group = mSipGroups.get(localProfileUri);
if (group == null) return;
if (!isCallerCreatorOrRadio(group)) {
@@ -190,10 +199,12 @@
group = mSipGroups.remove(localProfileUri);
notifyProfileRemoved(group.getLocalProfile());
group.close();
- if (isWifiOn() && !anyOpened()) releaseWifiLock();
+ if (isWifiActive() && !anyOpened()) releaseWifiLock();
}
public synchronized boolean isOpened(String localProfileUri) {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.USE_SIP, null);
SipSessionGroupExt group = mSipGroups.get(localProfileUri);
if (group == null) return false;
if (isCallerCreatorOrRadio(group)) {
@@ -205,6 +216,8 @@
}
public synchronized boolean isRegistered(String localProfileUri) {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.USE_SIP, null);
SipSessionGroupExt group = mSipGroups.get(localProfileUri);
if (group == null) return false;
if (isCallerCreatorOrRadio(group)) {
@@ -217,6 +230,8 @@
public synchronized void setRegistrationListener(String localProfileUri,
ISipSessionListener listener) {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.USE_SIP, null);
SipSessionGroupExt group = mSipGroups.get(localProfileUri);
if (group == null) return;
if (isCallerCreator(group)) {
@@ -228,6 +243,8 @@
public synchronized ISipSession createSession(SipProfile localProfile,
ISipSessionListener listener) {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.USE_SIP, null);
localProfile.setCallingUid(Binder.getCallingUid());
if (!mConnected) return null;
try {
@@ -240,6 +257,8 @@
}
public synchronized ISipSession getPendingSession(String callId) {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.USE_SIP, null);
if (callId == null) return null;
return mPendingSessions.get(callId);
}
@@ -329,9 +348,8 @@
}
}
- private boolean isWifiOn() {
+ private boolean isWifiActive() {
return "WIFI".equalsIgnoreCase(mNetworkType);
- //return (mConnected && "WIFI".equalsIgnoreCase(mNetworkType));
}
private synchronized void onConnectivityChanged(
@@ -825,11 +843,13 @@
synchronized (SipService.this) {
if (notCurrentSession(session)) return;
- if (errorCode == SipErrorCode.INVALID_CREDENTIALS) {
- if (DEBUG) Log.d(TAG, " pause auto-registration");
- stop();
- } else {
- onError();
+ switch (errorCode) {
+ case SipErrorCode.INVALID_CREDENTIALS:
+ case SipErrorCode.SERVER_UNREACHABLE:
+ if (DEBUG) Log.d(TAG, " pause auto-registration");
+ stop();
+ default:
+ restartLater();
}
mErrorCode = errorCode;
@@ -846,11 +866,11 @@
mErrorCode = SipErrorCode.TIME_OUT;
mProxy.onRegistrationTimeout(session);
- onError();
+ restartLater();
}
}
- private void onError() {
+ private void restartLater() {
mRegistered = false;
restart(backoffDuration());
if (mKeepAliveProcess != null) {
diff --git a/voip/java/com/android/server/sip/SipSessionGroup.java b/voip/java/com/android/server/sip/SipSessionGroup.java
index 37fffa8..57b3710 100644
--- a/voip/java/com/android/server/sip/SipSessionGroup.java
+++ b/voip/java/com/android/server/sip/SipSessionGroup.java
@@ -96,8 +96,6 @@
private SipStack mSipStack;
private SipHelper mSipHelper;
- private String mLastNonce;
- private int mRPort;
// session that processes INVITE requests
private SipSessionImpl mCallReceiverSession;
@@ -150,7 +148,6 @@
Log.d(TAG, " start stack for " + myself.getUriString());
stack.start();
- mLastNonce = null;
mCallReceiverSession = null;
mSessionMap.clear();
}
@@ -366,8 +363,12 @@
ClientTransaction mClientTransaction;
String mPeerSessionDescription;
boolean mInCall;
- boolean mReRegisterFlag = false;
SessionTimer mTimer;
+ int mAuthenticationRetryCount;
+
+ // for registration
+ boolean mReRegisterFlag = false;
+ int mRPort;
// lightweight timer
class SessionTimer {
@@ -417,6 +418,8 @@
mState = SipSession.State.READY_TO_CALL;
mInviteReceived = null;
mPeerSessionDescription = null;
+ mRPort = 0;
+ mAuthenticationRetryCount = 0;
if (mDialog != null) mDialog.delete();
mDialog = null;
@@ -799,22 +802,10 @@
onRegistrationDone((state == SipSession.State.REGISTERING)
? getExpiryTime(((ResponseEvent) evt).getResponse())
: -1);
- mLastNonce = null;
- mRPort = 0;
return true;
case Response.UNAUTHORIZED:
case Response.PROXY_AUTHENTICATION_REQUIRED:
- if (!handleAuthentication(event)) {
- if (mLastNonce == null) {
- onRegistrationFailed(SipErrorCode.SERVER_ERROR,
- "server does not provide challenge");
- } else {
- Log.v(TAG, "Incorrect username/password");
- onRegistrationFailed(
- SipErrorCode.INVALID_CREDENTIALS,
- "incorrect username or password");
- }
- }
+ handleAuthentication(event);
return true;
default:
if (statusCode >= 500) {
@@ -830,16 +821,24 @@
throws SipException {
Response response = event.getResponse();
String nonce = getNonceFromResponse(response);
- if (((nonce != null) && nonce.equals(mLastNonce)) ||
- (nonce == null)) {
- mLastNonce = nonce;
+ if (nonce == null) {
+ onError(SipErrorCode.SERVER_ERROR,
+ "server does not provide challenge");
return false;
- } else {
+ } else if (mAuthenticationRetryCount < 2) {
mClientTransaction = mSipHelper.handleChallenge(
event, getAccountManager());
mDialog = mClientTransaction.getDialog();
- mLastNonce = nonce;
+ mAuthenticationRetryCount++;
+ if (isLoggable(this, event)) {
+ Log.d(TAG, " authentication retry count="
+ + mAuthenticationRetryCount);
+ }
return true;
+ } else {
+ onError(SipErrorCode.INVALID_CREDENTIALS,
+ "incorrect username or password");
+ return false;
}
}
@@ -995,12 +994,6 @@
getRealmFromResponse(response));
} else if (handleAuthentication(event)) {
addSipSession(this);
- } else if (mLastNonce == null) {
- onError(SipErrorCode.SERVER_ERROR,
- "server does not provide challenge");
- } else {
- onError(SipErrorCode.INVALID_CREDENTIALS,
- "incorrect username or password");
}
return true;
case Response.REQUEST_PENDING:
diff --git a/voip/jni/rtp/AmrCodec.cpp b/voip/jni/rtp/AmrCodec.cpp
index f3ecac2..72ee44e 100644
--- a/voip/jni/rtp/AmrCodec.cpp
+++ b/voip/jni/rtp/AmrCodec.cpp
@@ -73,7 +73,7 @@
}
// Handle mode-set and octet-align.
- char *modes = strcasestr(fmtp, "mode-set=");
+ char *modes = (char*)strcasestr(fmtp, "mode-set=");
if (modes) {
mMode = 0;
mModeSet = 0;
diff --git a/voip/jni/rtp/EchoSuppressor.cpp b/voip/jni/rtp/EchoSuppressor.cpp
index 92015a9..ad63cd6 100644
--- a/voip/jni/rtp/EchoSuppressor.cpp
+++ b/voip/jni/rtp/EchoSuppressor.cpp
@@ -15,6 +15,7 @@
*/
#include <stdio.h>
+#include <string.h>
#include <stdint.h>
#include <math.h>
@@ -156,11 +157,12 @@
if (correlation > 0.3f) {
float factor = 1.0f - correlation;
factor *= factor;
+ factor /= 2.0; // suppress harder
for (int i = 0; i < mSampleCount; ++i) {
recorded[i] *= factor;
}
}
-// LOGI("latency %5d, correlation %.10f", latency, correlation);
+ //LOGI("latency %5d, correlation %.10f", latency, correlation);
// Increase RecordOffset.