Merge "Never drag scroll views with no children." into honeycomb
diff --git a/Android.mk b/Android.mk
index f581515..5d989d1 100644
--- a/Android.mk
+++ b/Android.mk
@@ -167,6 +167,7 @@
core/java/com/android/internal/view/IInputMethodManager.aidl \
core/java/com/android/internal/view/IInputMethodSession.aidl \
core/java/com/android/internal/widget/IRemoteViewsFactory.aidl \
+ core/java/com/android/internal/widget/IRemoteViewsAdapterConnection.aidl \
location/java/android/location/ICountryDetector.aidl \
location/java/android/location/ICountryListener.aidl \
location/java/android/location/IGeocodeProvider.aidl \
diff --git a/CleanSpec.mk b/CleanSpec.mk
index 1acb620..337b30f 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -89,6 +89,7 @@
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/core/java/android/nfc/INdefTag.java)
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libstagefright_aacdec_intermediates)
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libstagefright_mp3dec_intermediates)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/build.prop)
# ************************************************
# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
diff --git a/api/11.xml b/api/11.xml
index 5087eca..31cfc85 100644
--- a/api/11.xml
+++ b/api/11.xml
@@ -188,6 +188,17 @@
visibility="public"
>
</field>
+<field name="BIND_REMOTEVIEWS"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""android.permission.BIND_REMOTEVIEWS""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="BIND_WALLPAPER"
type="java.lang.String"
transient="false"
@@ -2710,6 +2721,17 @@
visibility="public"
>
</field>
+<field name="calendarViewStyle"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843613"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="candidatesTextStyleSpans"
type="int"
transient="false"
@@ -3271,6 +3293,17 @@
visibility="public"
>
</field>
+<field name="datePickerStyle"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843612"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="dateTextAppearance"
type="int"
transient="false"
@@ -8716,17 +8749,6 @@
visibility="public"
>
</field>
-<field name="solidColor"
- type="int"
- transient="false"
- volatile="false"
- value="16843594"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
<field name="soundEffectsEnabled"
type="int"
transient="false"
@@ -10894,6 +10916,17 @@
visibility="public"
>
</field>
+<field name="windowCloseOnTouchOutside"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843611"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="windowContentOverlay"
type="int"
transient="false"
@@ -15971,7 +16004,7 @@
type="int"
transient="false"
volatile="false"
- value="16974069"
+ value="16974060"
static="true"
final="true"
deprecated="not deprecated"
@@ -16022,6 +16055,17 @@
visibility="public"
>
</field>
+<field name="Widget_DatePicker"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16974063"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="Widget_DropDownItem"
type="int"
transient="false"
@@ -16055,17 +16099,6 @@
visibility="public"
>
</field>
-<field name="Widget_EditText_NumberPickerInputText"
- type="int"
- transient="false"
- volatile="false"
- value="16974061"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
<field name="Widget_ExpandableListView"
type="int"
transient="false"
@@ -16257,7 +16290,7 @@
type="int"
transient="false"
volatile="false"
- value="16974070"
+ value="16974061"
static="true"
final="true"
deprecated="not deprecated"
@@ -16297,6 +16330,17 @@
visibility="public"
>
</field>
+<field name="Widget_Holo_DatePicker"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16974064"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="Widget_Holo_DropDownItem"
type="int"
transient="false"
@@ -16330,17 +16374,6 @@
visibility="public"
>
</field>
-<field name="Widget_Holo_EditText_NumberPickerInputText"
- type="int"
- transient="false"
- volatile="false"
- value="16974064"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
<field name="Widget_Holo_ExpandableListView"
type="int"
transient="false"
@@ -16385,28 +16418,6 @@
visibility="public"
>
</field>
-<field name="Widget_Holo_ImageButton_NumberPickerDownButton"
- type="int"
- transient="false"
- volatile="false"
- value="16974065"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="Widget_Holo_ImageButton_NumberPickerUpButton"
- type="int"
- transient="false"
- volatile="false"
- value="16974063"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
<field name="Widget_Holo_Light"
type="int"
transient="false"
@@ -16532,7 +16543,7 @@
type="int"
transient="false"
volatile="false"
- value="16974071"
+ value="16974062"
static="true"
final="true"
deprecated="not deprecated"
@@ -16605,17 +16616,6 @@
visibility="public"
>
</field>
-<field name="Widget_Holo_Light_EditText_NumberPickerInputText"
- type="int"
- transient="false"
- volatile="false"
- value="16974067"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
<field name="Widget_Holo_Light_ExpandableListView"
type="int"
transient="false"
@@ -16660,28 +16660,6 @@
visibility="public"
>
</field>
-<field name="Widget_Holo_Light_ImageButton_NumberPickerDownButton"
- type="int"
- transient="false"
- volatile="false"
- value="16974068"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="Widget_Holo_Light_ImageButton_NumberPickerUpButton"
- type="int"
- transient="false"
- volatile="false"
- value="16974066"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
<field name="Widget_Holo_Light_ListPopupWindow"
type="int"
transient="false"
@@ -17210,28 +17188,6 @@
visibility="public"
>
</field>
-<field name="Widget_ImageButton_NumberPickerDownButton"
- type="int"
- transient="false"
- volatile="false"
- value="16974062"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="Widget_ImageButton_NumberPickerUpButton"
- type="int"
- transient="false"
- volatile="false"
- value="16974060"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
<field name="Widget_ImageWell"
type="int"
transient="false"
@@ -24300,6 +24256,19 @@
<parameter name="uri" type="android.net.Uri">
</parameter>
</method>
+<method name="setFinishOnTouchOutside"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="finish" type="boolean">
+</parameter>
+</method>
<method name="setIntent"
return="void"
abstract="false"
@@ -136088,6 +136057,17 @@
visibility="public"
>
</method>
+<method name="getPreserveEGLContextOnPause"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="getRenderMode"
return="int"
abstract="false"
@@ -136259,6 +136239,19 @@
<parameter name="glWrapper" type="android.opengl.GLSurfaceView.GLWrapper">
</parameter>
</method>
+<method name="setPreserveEGLContextOnPause"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="preserveOnPause" type="boolean">
+</parameter>
+</method>
<method name="setRenderMode"
return="void"
abstract="false"
@@ -146691,6 +146684,16 @@
visibility="public"
>
</constructor>
+<constructor name="StrictMode.VmPolicy.Builder"
+ type="android.os.StrictMode.VmPolicy.Builder"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="base" type="android.os.StrictMode.VmPolicy">
+</parameter>
+</constructor>
<method name="build"
return="android.os.StrictMode.VmPolicy"
abstract="false"
@@ -146768,6 +146771,21 @@
visibility="public"
>
</method>
+<method name="setClassInstanceLimit"
+ return="android.os.StrictMode.VmPolicy.Builder"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="klass" type="java.lang.Class">
+</parameter>
+<parameter name="instanceLimit" type="int">
+</parameter>
+</method>
</class>
<class name="SystemClock"
extends="java.lang.Object"
@@ -160195,17 +160213,6 @@
visibility="public"
>
</field>
-<field name="ACTION_MTP_SESSION_END"
- type="java.lang.String"
- transient="false"
- volatile="false"
- value=""android.provider.action.MTP_SESSION_END""
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
<field name="ACTION_VIDEO_CAPTURE"
type="java.lang.String"
transient="false"
@@ -166475,6 +166482,74 @@
<parameter name="d" type="float[]">
</parameter>
</method>
+<method name="copy1DRangeFromUnchecked"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="off" type="int">
+</parameter>
+<parameter name="count" type="int">
+</parameter>
+<parameter name="d" type="int[]">
+</parameter>
+</method>
+<method name="copy1DRangeFromUnchecked"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="off" type="int">
+</parameter>
+<parameter name="count" type="int">
+</parameter>
+<parameter name="d" type="short[]">
+</parameter>
+</method>
+<method name="copy1DRangeFromUnchecked"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="off" type="int">
+</parameter>
+<parameter name="count" type="int">
+</parameter>
+<parameter name="d" type="byte[]">
+</parameter>
+</method>
+<method name="copy1DRangeFromUnchecked"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="off" type="int">
+</parameter>
+<parameter name="count" type="int">
+</parameter>
+<parameter name="d" type="float[]">
+</parameter>
+</method>
<method name="copy2DRangeFrom"
return="void"
abstract="false"
@@ -166654,6 +166729,58 @@
<parameter name="b" type="android.graphics.Bitmap">
</parameter>
</method>
+<method name="copyFromUnchecked"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="d" type="int[]">
+</parameter>
+</method>
+<method name="copyFromUnchecked"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="d" type="short[]">
+</parameter>
+</method>
+<method name="copyFromUnchecked"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="d" type="byte[]">
+</parameter>
+</method>
+<method name="copyFromUnchecked"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="d" type="float[]">
+</parameter>
+</method>
<method name="copyTo"
return="void"
abstract="false"
@@ -175623,6 +175750,17 @@
visibility="public"
>
</field>
+<field name="KEY_PARAM_PAN"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""pan""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="KEY_PARAM_STREAM"
type="java.lang.String"
transient="false"
@@ -175645,6 +175783,17 @@
visibility="public"
>
</field>
+<field name="KEY_PARAM_VOLUME"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""volume""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
</class>
<interface name="TextToSpeech.OnInitListener"
abstract="true"
@@ -219385,6 +219534,14 @@
<parameter name="view" type="android.view.View">
</parameter>
</constructor>
+<constructor name="View.DragShadowBuilder"
+ type="android.view.View.DragShadowBuilder"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
<method name="getView"
return="android.view.View"
abstract="false"
@@ -236035,6 +236192,48 @@
</parameter>
</method>
</class>
+<class name="WebStorage.Origin"
+ extends="java.lang.Object"
+ abstract="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="getOrigin"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getQuota"
+ return="long"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getUsage"
+ return="long"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
<interface name="WebStorage.QuotaUpdater"
abstract="true"
static="true"
@@ -252327,6 +252526,8 @@
deprecated="not deprecated"
visibility="public"
>
+<parameter name="appWidgetId" type="int">
+</parameter>
<parameter name="viewId" type="int">
</parameter>
<parameter name="intent" type="android.content.Intent">
diff --git a/api/current.xml b/api/current.xml
index 76be208..83bfedb 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -188,6 +188,17 @@
visibility="public"
>
</field>
+<field name="BIND_REMOTEVIEWS"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""android.permission.BIND_REMOTEVIEWS""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="BIND_WALLPAPER"
type="java.lang.String"
transient="false"
@@ -2710,6 +2721,17 @@
visibility="public"
>
</field>
+<field name="calendarViewStyle"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843613"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="candidatesTextStyleSpans"
type="int"
transient="false"
@@ -3271,6 +3293,17 @@
visibility="public"
>
</field>
+<field name="datePickerStyle"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843612"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="dateTextAppearance"
type="int"
transient="false"
@@ -8716,17 +8749,6 @@
visibility="public"
>
</field>
-<field name="solidColor"
- type="int"
- transient="false"
- volatile="false"
- value="16843594"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
<field name="soundEffectsEnabled"
type="int"
transient="false"
@@ -15982,7 +16004,7 @@
type="int"
transient="false"
volatile="false"
- value="16974069"
+ value="16974060"
static="true"
final="true"
deprecated="not deprecated"
@@ -16033,6 +16055,17 @@
visibility="public"
>
</field>
+<field name="Widget_DatePicker"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16974063"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="Widget_DropDownItem"
type="int"
transient="false"
@@ -16066,17 +16099,6 @@
visibility="public"
>
</field>
-<field name="Widget_EditText_NumberPickerInputText"
- type="int"
- transient="false"
- volatile="false"
- value="16974061"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
<field name="Widget_ExpandableListView"
type="int"
transient="false"
@@ -16268,7 +16290,7 @@
type="int"
transient="false"
volatile="false"
- value="16974070"
+ value="16974061"
static="true"
final="true"
deprecated="not deprecated"
@@ -16308,6 +16330,17 @@
visibility="public"
>
</field>
+<field name="Widget_Holo_DatePicker"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16974064"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="Widget_Holo_DropDownItem"
type="int"
transient="false"
@@ -16341,17 +16374,6 @@
visibility="public"
>
</field>
-<field name="Widget_Holo_EditText_NumberPickerInputText"
- type="int"
- transient="false"
- volatile="false"
- value="16974064"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
<field name="Widget_Holo_ExpandableListView"
type="int"
transient="false"
@@ -16396,28 +16418,6 @@
visibility="public"
>
</field>
-<field name="Widget_Holo_ImageButton_NumberPickerDownButton"
- type="int"
- transient="false"
- volatile="false"
- value="16974065"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="Widget_Holo_ImageButton_NumberPickerUpButton"
- type="int"
- transient="false"
- volatile="false"
- value="16974063"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
<field name="Widget_Holo_Light"
type="int"
transient="false"
@@ -16543,7 +16543,7 @@
type="int"
transient="false"
volatile="false"
- value="16974071"
+ value="16974062"
static="true"
final="true"
deprecated="not deprecated"
@@ -16616,17 +16616,6 @@
visibility="public"
>
</field>
-<field name="Widget_Holo_Light_EditText_NumberPickerInputText"
- type="int"
- transient="false"
- volatile="false"
- value="16974067"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
<field name="Widget_Holo_Light_ExpandableListView"
type="int"
transient="false"
@@ -16671,28 +16660,6 @@
visibility="public"
>
</field>
-<field name="Widget_Holo_Light_ImageButton_NumberPickerDownButton"
- type="int"
- transient="false"
- volatile="false"
- value="16974068"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="Widget_Holo_Light_ImageButton_NumberPickerUpButton"
- type="int"
- transient="false"
- volatile="false"
- value="16974066"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
<field name="Widget_Holo_Light_ListPopupWindow"
type="int"
transient="false"
@@ -17221,28 +17188,6 @@
visibility="public"
>
</field>
-<field name="Widget_ImageButton_NumberPickerDownButton"
- type="int"
- transient="false"
- volatile="false"
- value="16974062"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="Widget_ImageButton_NumberPickerUpButton"
- type="int"
- transient="false"
- volatile="false"
- value="16974060"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
<field name="Widget_ImageWell"
type="int"
transient="false"
@@ -136112,6 +136057,17 @@
visibility="public"
>
</method>
+<method name="getPreserveEGLContextOnPause"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="getRenderMode"
return="int"
abstract="false"
@@ -136283,6 +136239,19 @@
<parameter name="glWrapper" type="android.opengl.GLSurfaceView.GLWrapper">
</parameter>
</method>
+<method name="setPreserveEGLContextOnPause"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="preserveOnPause" type="boolean">
+</parameter>
+</method>
<method name="setRenderMode"
return="void"
abstract="false"
@@ -146736,6 +146705,17 @@
visibility="public"
>
</method>
+<method name="detectActivityLeaks"
+ return="android.os.StrictMode.VmPolicy.Builder"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="detectAll"
return="android.os.StrictMode.VmPolicy.Builder"
abstract="false"
@@ -160244,17 +160224,6 @@
visibility="public"
>
</field>
-<field name="ACTION_MTP_SESSION_END"
- type="java.lang.String"
- transient="false"
- volatile="false"
- value=""android.provider.action.MTP_SESSION_END""
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
<field name="ACTION_VIDEO_CAPTURE"
type="java.lang.String"
transient="false"
@@ -166524,6 +166493,74 @@
<parameter name="d" type="float[]">
</parameter>
</method>
+<method name="copy1DRangeFromUnchecked"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="off" type="int">
+</parameter>
+<parameter name="count" type="int">
+</parameter>
+<parameter name="d" type="int[]">
+</parameter>
+</method>
+<method name="copy1DRangeFromUnchecked"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="off" type="int">
+</parameter>
+<parameter name="count" type="int">
+</parameter>
+<parameter name="d" type="short[]">
+</parameter>
+</method>
+<method name="copy1DRangeFromUnchecked"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="off" type="int">
+</parameter>
+<parameter name="count" type="int">
+</parameter>
+<parameter name="d" type="byte[]">
+</parameter>
+</method>
+<method name="copy1DRangeFromUnchecked"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="off" type="int">
+</parameter>
+<parameter name="count" type="int">
+</parameter>
+<parameter name="d" type="float[]">
+</parameter>
+</method>
<method name="copy2DRangeFrom"
return="void"
abstract="false"
@@ -166703,6 +166740,58 @@
<parameter name="b" type="android.graphics.Bitmap">
</parameter>
</method>
+<method name="copyFromUnchecked"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="d" type="int[]">
+</parameter>
+</method>
+<method name="copyFromUnchecked"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="d" type="short[]">
+</parameter>
+</method>
+<method name="copyFromUnchecked"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="d" type="byte[]">
+</parameter>
+</method>
+<method name="copyFromUnchecked"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="d" type="float[]">
+</parameter>
+</method>
<method name="copyTo"
return="void"
abstract="false"
@@ -175672,6 +175761,17 @@
visibility="public"
>
</field>
+<field name="KEY_PARAM_PAN"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""pan""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="KEY_PARAM_STREAM"
type="java.lang.String"
transient="false"
@@ -175694,6 +175794,17 @@
visibility="public"
>
</field>
+<field name="KEY_PARAM_VOLUME"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""volume""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
</class>
<interface name="TextToSpeech.OnInitListener"
abstract="true"
@@ -219434,6 +219545,14 @@
<parameter name="view" type="android.view.View">
</parameter>
</constructor>
+<constructor name="View.DragShadowBuilder"
+ type="android.view.View.DragShadowBuilder"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
<method name="getView"
return="android.view.View"
abstract="false"
@@ -252418,6 +252537,8 @@
deprecated="not deprecated"
visibility="public"
>
+<parameter name="appWidgetId" type="int">
+</parameter>
<parameter name="viewId" type="int">
</parameter>
<parameter name="intent" type="android.content.Intent">
diff --git a/build/phone-hdpi-512-dalvik-heap.mk b/build/phone-hdpi-512-dalvik-heap.mk
index afc45ee..630cf03 100644
--- a/build/phone-hdpi-512-dalvik-heap.mk
+++ b/build/phone-hdpi-512-dalvik-heap.mk
@@ -19,5 +19,5 @@
PRODUCT_PROPERTY_OVERRIDES += \
dalvik.vm.heapstartsize=5m \
- dalvik.vm.smallheapsize=32m \
- dalvik.vm.heapsize=32m
+ dalvik.vm.growthlimit=32m \
+ dalvik.vm.heapsize=128m
diff --git a/build/phone-hdpi-dalvik-heap.mk b/build/phone-hdpi-dalvik-heap.mk
index ee30b92..ab33b96 100644
--- a/build/phone-hdpi-dalvik-heap.mk
+++ b/build/phone-hdpi-dalvik-heap.mk
@@ -18,5 +18,4 @@
PRODUCT_PROPERTY_OVERRIDES += \
dalvik.vm.heapstartsize=5m \
- dalvik.vm.smallheapsize=32m \
dalvik.vm.heapsize=32m
diff --git a/build/tablet-dalvik-heap.mk b/build/tablet-dalvik-heap.mk
index 9cb2f6b..37c3ec5 100644
--- a/build/tablet-dalvik-heap.mk
+++ b/build/tablet-dalvik-heap.mk
@@ -18,5 +18,5 @@
PRODUCT_PROPERTY_OVERRIDES += \
dalvik.vm.heapstartsize=5m \
- dalvik.vm.smallheapsize=48m \
- dalvik.vm.heapsize=48m
+ dalvik.vm.growthlimit=48m \
+ dalvik.vm.heapsize=256m
diff --git a/core/java/android/accounts/AccountManagerService.java b/core/java/android/accounts/AccountManagerService.java
index e6eaf71..2c99f14 100644
--- a/core/java/android/accounts/AccountManagerService.java
+++ b/core/java/android/accounts/AccountManagerService.java
@@ -722,6 +722,9 @@
final String[] argsAccountId = {String.valueOf(accountId)};
db.update(TABLE_ACCOUNTS, values, ACCOUNTS_ID + "=?", argsAccountId);
db.delete(TABLE_AUTHTOKENS, AUTHTOKENS_ACCOUNTS_ID + "=?", argsAccountId);
+ synchronized (mCacheLock) {
+ mAuthTokenCache.remove(account);
+ }
db.setTransactionSuccessful();
}
} finally {
@@ -1812,6 +1815,11 @@
try {
db.execSQL("DELETE from " + TABLE_AUTHTOKENS);
db.execSQL("UPDATE " + TABLE_ACCOUNTS + " SET " + ACCOUNTS_PASSWORD + " = ''");
+
+ synchronized (mCacheLock) {
+ mAuthTokenCache = new HashMap<Account, HashMap<String, String>>();
+ }
+
db.setTransactionSuccessful();
} finally {
db.endTransaction();
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 0a64070..ec6eaaa 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -4433,6 +4433,9 @@
mStopped = true;
}
mResumed = false;
+
+ // Check for Activity leaks, if enabled.
+ StrictMode.conditionallyCheckInstanceCounts();
}
final void performDestroy() {
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index d5aa961..133a7d0 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -64,8 +64,11 @@
static public int staticGetMemoryClass() {
// Really brain dead right now -- just take this from the configured
// vm heap size, and assume it is in megabytes and thus ends with "m".
- String vmHeapSize = SystemProperties.get("dalvik.vm.smallheapsize", "16m");
- return Integer.parseInt(vmHeapSize.substring(0, vmHeapSize.length()-1));
+ String vmHeapSize = SystemProperties.get("dalvik.vm.growthlimit", "");
+ if (vmHeapSize != null && !"".equals(vmHeapSize)) {
+ return Integer.parseInt(vmHeapSize.substring(0, vmHeapSize.length()-1));
+ }
+ return staticGetLargeMemoryClass();
}
/**
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index db046ef..7cf60f9 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -3463,7 +3463,7 @@
}
if ((data.appInfo.flags&ApplicationInfo.FLAG_LARGE_HEAP) != 0) {
- // XXX bump up Dalvik's heap.
+ dalvik.system.VMRuntime.getRuntime().clearGrowthLimit();
}
// If the app is being launched for full backup or restore, bring it up in
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 0243b02..de84c56 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -34,6 +34,9 @@
* A class that represents how a persistent notification is to be presented to
* the user using the {@link android.app.NotificationManager}.
*
+ * <p>The {@link Notification.Builder Notification.Builder} has been added to make it
+ * easier to construct Notifications.</p>
+ *
* <p>For a guide to creating notifications, see the
* <a href="{@docRoot}guide/topics/ui/notifiers/notifications.html">Creating Status
* Bar Notifications</a> document in the Dev Guide.</p>
@@ -119,15 +122,8 @@
/**
* An intent to launch instead of posting the notification to the status bar.
- * Only for use with extremely high-priority notifications demanding the user's
- * <strong>immediate</strong> attention, such as an incoming phone call or
- * alarm clock that the user has explicitly set to a particular time.
- * If this facility is used for something else, please give the user an option
- * to turn it off and use a normal notification, as this can be extremely
- * disruptive.
- *
- * <p>Use with {@link #FLAG_HIGH_PRIORITY} to ensure that this notification
- * will reach the user even when other notifications are suppressed.
+ *
+ * @see Notification.Builder#setFullScreenIntent
*/
public PendingIntent fullScreenIntent;
@@ -278,7 +274,7 @@
/**
* Bit to be bitwise-ored into the {@link #flags} field that should be
* set if the notification should be canceled when it is clicked by the
- * user.
+ * user. On tablets, the
*/
public static final int FLAG_AUTO_CANCEL = 0x00000010;
@@ -618,6 +614,10 @@
return sb.toString();
}
+ /**
+ * Builder class for {@link Notification} objects. Allows easier control over
+ * all the flags, as well as help constructing the typical notification layouts.
+ */
public static class Builder {
private Context mContext;
@@ -644,6 +644,16 @@
private int mDefaults;
private int mFlags;
+ /**
+ * Constructor.
+ *
+ * Automatically sets the when field to {@link System#currentTimeMillis()
+ * System.currentTimeMllis()} and the audio stream to the {@link #STREAM_DEFAULT}.
+ *
+ * @param context A {@link Context} that will be used to construct the
+ * RemoteViews. The Context will not be held past the lifetime of this
+ * Builder object.
+ */
public Builder(Context context) {
mContext = context;
@@ -652,96 +662,192 @@
mAudioStreamType = STREAM_DEFAULT;
}
+ /**
+ * Set the time that the event occurred. Notifications in the panel are
+ * sorted by this time.
+ */
public Builder setWhen(long when) {
mWhen = when;
return this;
}
+ /**
+ * Set the small icon to use in the notification layouts. Different classes of devices
+ * may return different sizes. See the UX guidelines for more information on how to
+ * design these icons.
+ *
+ * @param icon A resource ID in the application's package of the drawble to use.
+ */
public Builder setSmallIcon(int icon) {
mSmallIcon = icon;
return this;
}
+ /**
+ * A variant of {@link #setSmallIcon(int) setSmallIcon(int)} that takes an additional
+ * level parameter for when the icon is a {@link android.graphics.drawable.LevelListDrawable
+ * LevelListDrawable}.
+ *
+ * @param icon A resource ID in the application's package of the drawble to use.
+ * @param level The level to use for the icon.
+ *
+ * @see android.graphics.drawable.LevelListDrawable
+ */
public Builder setSmallIcon(int icon, int level) {
mSmallIcon = icon;
mSmallIconLevel = level;
return this;
}
+ /**
+ * Set the title (first row) of the notification, in a standard notification.
+ */
public Builder setContentTitle(CharSequence title) {
mContentTitle = title;
return this;
}
+ /**
+ * Set the text (second row) of the notification, in a standard notification.
+ */
public Builder setContentText(CharSequence text) {
mContentText = text;
return this;
}
+ /**
+ * Set the large number at the right-hand side of the notification. This is
+ * equivalent to setContentInfo, although it might show the number in a different
+ * font size for readability.
+ */
public Builder setNumber(int number) {
mNumber = number;
return this;
}
+ /**
+ * Set the large text at the right-hand side of the notification.
+ */
public Builder setContentInfo(CharSequence info) {
mContentInfo = info;
return this;
}
+ /**
+ * Supply a custom RemoteViews to use instead of the standard one.
+ */
public Builder setContent(RemoteViews views) {
mContentView = views;
return this;
}
+ /**
+ * Supply a {@link PendingIntent} to send when the notification is clicked.
+ * If you do not supply an intent, you can now add PendingIntents to individual
+ * views to be launched when clicked by calling {@link RemoteViews#setOnClickPendingIntent
+ * RemoteViews.setOnClickPendingIntent(int,PendingIntent)}.
+ */
public Builder setContentIntent(PendingIntent intent) {
mContentIntent = intent;
return this;
}
+ /**
+ * Supply a {@link PendingIntent} to send when the notification is cleared by the user
+ * directly from the notification panel. For example, this intent is sent when the user
+ * clicks the "Clear all" button, or the individual "X" buttons on notifications. This
+ * intent is not sent when the application calls {@link NotificationManager#cancel
+ * NotificationManager.cancel(int)}.
+ */
public Builder setDeleteIntent(PendingIntent intent) {
mDeleteIntent = intent;
return this;
}
+ /**
+ * An intent to launch instead of posting the notification to the status bar.
+ * Only for use with extremely high-priority notifications demanding the user's
+ * <strong>immediate</strong> attention, such as an incoming phone call or
+ * alarm clock that the user has explicitly set to a particular time.
+ * If this facility is used for something else, please give the user an option
+ * to turn it off and use a normal notification, as this can be extremely
+ * disruptive.
+ *
+ * @param intent The pending intent to launch.
+ * @param highPriority Passing true will cause this notification to be sent
+ * even if other notifications are suppressed.
+ */
public Builder setFullScreenIntent(PendingIntent intent, boolean highPriority) {
mFullScreenIntent = intent;
setFlag(FLAG_HIGH_PRIORITY, highPriority);
return this;
}
+ /**
+ * Set the text that is displayed in the status bar when the notification first
+ * arrives.
+ */
public Builder setTicker(CharSequence tickerText) {
mTickerText = tickerText;
return this;
}
+ /**
+ * Set the text that is displayed in the status bar when the notification first
+ * arrives, and also a RemoteViews object that may be displayed instead on some
+ * devices.
+ */
public Builder setTicker(CharSequence tickerText, RemoteViews views) {
mTickerText = tickerText;
mTickerView = views;
return this;
}
+ /**
+ * Set the large icon that is shown in the ticker and notification.
+ */
public Builder setLargeIcon(Bitmap icon) {
mLargeIcon = icon;
return this;
}
+ /**
+ * Set the sound to play. It will play on the default stream.
+ */
public Builder setSound(Uri sound) {
mSound = sound;
mAudioStreamType = STREAM_DEFAULT;
return this;
}
+ /**
+ * Set the sound to play. It will play on the stream you supply.
+ *
+ * @see #STREAM_DEFAULT
+ * @see AudioManager for the <code>STREAM_</code> constants.
+ */
public Builder setSound(Uri sound, int streamType) {
mSound = sound;
mAudioStreamType = streamType;
return this;
}
+ /**
+ * Set the vibration pattern to use.
+ *
+ * @see android.os.Vibrator for a discussion of the <code>pattern</code>
+ * parameter.
+ */
public Builder setVibrate(long[] pattern) {
mVibrate = pattern;
return this;
}
+ /**
+ * Set the argb value that you would like the LED on the device to blnk, as well as the
+ * rate. The rate is specified in terms of the number of milliseconds to be on
+ * and then the number of milliseconds to be off.
+ */
public Builder setLights(int argb, int onMs, int offMs) {
mLedArgb = argb;
mLedOnMs = onMs;
@@ -749,21 +855,51 @@
return this;
}
+ /**
+ * Set whether this is an ongoing notification.
+ *
+ * <p>Ongoing notifications differ from regular notifications in the following ways:
+ * <ul>
+ * <li>Ongoing notifications are sorted above the regular notifications in the
+ * notification panel.</li>
+ * <li>Ongoing notifications do not have an 'X' close button, and are not affected
+ * by the "Clear all" button.
+ * </ul>
+ */
public Builder setOngoing(boolean ongoing) {
setFlag(FLAG_ONGOING_EVENT, ongoing);
return this;
}
+ /**
+ * Set this flag if you would only like the sound, vibrate
+ * and ticker to be played if the notification is not already showing.
+ */
public Builder setOnlyAlertOnce(boolean onlyAlertOnce) {
setFlag(FLAG_ONLY_ALERT_ONCE, onlyAlertOnce);
return this;
}
+ /**
+ * Setting this flag will make it so the notification is automatically
+ * canceled when the user clicks it in the panel. The PendingIntent
+ * set with {@link #setDeleteIntent} will be broadcast when the notification
+ * is canceled.
+ */
public Builder setAutoCancel(boolean autoCancel) {
setFlag(FLAG_AUTO_CANCEL, autoCancel);
return this;
}
+ /**
+ * Set the default notification options that will be used.
+ * <p>
+ * The value should be one or more of the following fields combined with
+ * bitwise-or:
+ * {@link #DEFAULT_SOUND}, {@link #DEFAULT_VIBRATE}, {@link #DEFAULT_LIGHTS}.
+ * <p>
+ * For all default values, use {@link #DEFAULT_ALL}.
+ */
public Builder setDefaults(int defaults) {
mDefaults = defaults;
return this;
@@ -834,6 +970,10 @@
}
}
+ /**
+ * Combine all of the options that have been set and return a new {@link Notification}
+ * object.
+ */
public Notification getNotification() {
Notification n = new Notification();
n.when = mWhen;
diff --git a/core/java/android/appwidget/AppWidgetManager.java b/core/java/android/appwidget/AppWidgetManager.java
index 2a583c1..019652c 100644
--- a/core/java/android/appwidget/AppWidgetManager.java
+++ b/core/java/android/appwidget/AppWidgetManager.java
@@ -18,6 +18,7 @@
import android.content.ComponentName;
import android.content.Context;
+import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.ServiceManager;
@@ -438,6 +439,47 @@
}
/**
+ * Binds the RemoteViewsService for a given appWidgetId and intent.
+ *
+ * The appWidgetId specified must already be bound to the calling AppWidgetHost via
+ * {@link android.appwidget.AppWidgetManager#bindAppWidgetId AppWidgetManager.bindAppWidgetId()}.
+ *
+ * @param appWidgetId The AppWidget instance for which to bind the RemoteViewsService.
+ * @param intent The intent of the service which will be providing the data to the
+ * RemoteViewsAdapter.
+ * @param connection The callback interface to be notified when a connection is made or lost.
+ * @hide
+ */
+ public void bindRemoteViewsService(int appWidgetId, Intent intent, IBinder connection) {
+ try {
+ sService.bindRemoteViewsService(appWidgetId, intent, connection);
+ }
+ catch (RemoteException e) {
+ throw new RuntimeException("system server dead?", e);
+ }
+ }
+
+ /**
+ * Unbinds the RemoteViewsService for a given appWidgetId and intent.
+ *
+ * The appWidgetId specified muse already be bound to the calling AppWidgetHost via
+ * {@link android.appwidget.AppWidgetManager#bindAppWidgetId AppWidgetManager.bindAppWidgetId()}.
+ *
+ * @param appWidgetId The AppWidget instance for which to bind the RemoteViewsService.
+ * @param intent The intent of the service which will be providing the data to the
+ * RemoteViewsAdapter.
+ * @hide
+ */
+ public void unbindRemoteViewsService(int appWidgetId, Intent intent) {
+ try {
+ sService.unbindRemoteViewsService(appWidgetId, intent);
+ }
+ catch (RemoteException e) {
+ throw new RuntimeException("system server dead?", e);
+ }
+ }
+
+ /**
* Get the list of appWidgetIds that have been bound to the given AppWidget
* provider.
*
diff --git a/core/java/android/bluetooth/BluetoothInputDevice.java b/core/java/android/bluetooth/BluetoothInputDevice.java
index bc8a836..a70de59 100644
--- a/core/java/android/bluetooth/BluetoothInputDevice.java
+++ b/core/java/android/bluetooth/BluetoothInputDevice.java
@@ -85,6 +85,19 @@
*/
public static final int PRIORITY_UNDEFINED = -1;
+ /**
+ * Return codes for the connect and disconnect Bluez / Dbus calls.
+ */
+ public static final int INPUT_DISCONNECT_FAILED_NOT_CONNECTED = 5000;
+
+ public static final int INPUT_CONNECT_FAILED_ALREADY_CONNECTED = 5001;
+
+ public static final int INPUT_CONNECT_FAILED_ATTEMPT_FAILED = 5002;
+
+ public static final int INPUT_OPERATION_GENERIC_FAILURE = 5003;
+
+ public static final int INPUT_OPERATION_SUCCESS = 5004;
+
private final IBluetooth mService;
private final Context mContext;
diff --git a/core/java/android/bluetooth/BluetoothPan.java b/core/java/android/bluetooth/BluetoothPan.java
index 7dee25e..1f07349 100644
--- a/core/java/android/bluetooth/BluetoothPan.java
+++ b/core/java/android/bluetooth/BluetoothPan.java
@@ -70,6 +70,19 @@
public static final int STATE_CONNECTED = 2;
public static final int STATE_DISCONNECTING = 3;
+ /**
+ * Return codes for the connect and disconnect Bluez / Dbus calls.
+ */
+ public static final int PAN_DISCONNECT_FAILED_NOT_CONNECTED = 1000;
+
+ public static final int PAN_CONNECT_FAILED_ALREADY_CONNECTED = 1001;
+
+ public static final int PAN_CONNECT_FAILED_ATTEMPT_FAILED = 1002;
+
+ public static final int PAN_OPERATION_GENERIC_FAILURE = 1003;
+
+ public static final int PAN_OPERATION_SUCCESS = 1004;
+
private final IBluetooth mService;
private final Context mContext;
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index af7b28b..35f1c58 100644
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -211,6 +211,12 @@
* {@link android.R.style#Theme_Holo}.
* <li> The activity lifecycle has changed slightly as per
* {@link android.app.Activity}.
+ * <li> When an application requires a permission to access on of
+ * its components (activity, receiver, service, provider), this
+ * permission is no longer enforced when the application wants to
+ * access its own component. This means it can require a permission
+ * on a component that it does not itself hold and still access that
+ * component.
* </ul>
*/
public static final int HONEYCOMB = CUR_DEVELOPMENT;
diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java
index 904b2e9..ec5030c 100644
--- a/core/java/android/os/Environment.java
+++ b/core/java/android/os/Environment.java
@@ -416,6 +416,7 @@
* <p>See {@link #getExternalStorageDirectory()} for more information.
*/
public static boolean isExternalStorageRemovable() {
+ if (isExternalStorageEmulated()) return false;
return Resources.getSystem().getBoolean(
com.android.internal.R.bool.config_externalStorageRemovable);
}
diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java
index 997ea53..ae92b09 100644
--- a/core/java/android/os/StrictMode.java
+++ b/core/java/android/os/StrictMode.java
@@ -30,6 +30,7 @@
import dalvik.system.BlockGuard;
import dalvik.system.CloseGuard;
+import dalvik.system.VMDebug;
import java.io.PrintWriter;
import java.io.StringWriter;
@@ -184,6 +185,15 @@
/**
* @hide
*/
+ private static final int DETECT_VM_INSTANCE_LEAKS = 0x1000; // for VmPolicy
+
+ private static final int ALL_VM_DETECT_BITS =
+ DETECT_VM_CURSOR_LEAKS | DETECT_VM_CLOSABLE_LEAKS |
+ DETECT_VM_ACTIVITY_LEAKS | DETECT_VM_INSTANCE_LEAKS;
+
+ /**
+ * @hide
+ */
public static final int PENALTY_LOG = 0x10; // normal android.util.Log
// Used for both process and thread policy:
@@ -573,11 +583,15 @@
} else if (mClassInstanceLimit == null) {
mClassInstanceLimit = new HashMap<Class, Integer>();
}
+ mMask |= DETECT_VM_INSTANCE_LEAKS;
mClassInstanceLimit.put(klass, instanceLimit);
return this;
}
- private Builder detectActivityLeaks() {
+ /**
+ * Detect leaks of {@link android.app.Activity} subclasses.
+ */
+ public Builder detectActivityLeaks() {
return enable(DETECT_VM_ACTIVITY_LEAKS);
}
@@ -585,8 +599,8 @@
* Detect everything that's potentially suspect.
*
* <p>In the Honeycomb release this includes leaks of
- * SQLite cursors and other closable objects but will
- * likely expand in future releases.
+ * SQLite cursors, Activities, and other closable objects
+ * but will likely expand in future releases.
*/
public Builder detectAll() {
return enable(DETECT_VM_ACTIVITY_LEAKS |
@@ -1347,6 +1361,41 @@
}
/**
+ * @hide
+ */
+ public static void conditionallyCheckInstanceCounts() {
+ VmPolicy policy = getVmPolicy();
+ if (policy.classInstanceLimit.size() == 0) {
+ return;
+ }
+ Runtime.getRuntime().gc();
+ // Note: classInstanceLimit is immutable, so this is lock-free
+ for (Class klass : policy.classInstanceLimit.keySet()) {
+ int limit = policy.classInstanceLimit.get(klass);
+ long instances = VMDebug.countInstancesOfClass(klass, false);
+ if (instances <= limit) {
+ continue;
+ }
+ Throwable tr = new InstanceCountViolation(klass, instances, limit);
+ onVmPolicyViolation(tr.getMessage(), tr);
+ }
+ }
+
+ private static long sLastInstanceCountCheckMillis = 0;
+ private static boolean sIsIdlerRegistered = false; // guarded by sProcessIdleHandler
+ private static final MessageQueue.IdleHandler sProcessIdleHandler =
+ new MessageQueue.IdleHandler() {
+ public boolean queueIdle() {
+ long now = SystemClock.uptimeMillis();
+ if (now - sLastInstanceCountCheckMillis > 30 * 1000) {
+ sLastInstanceCountCheckMillis = now;
+ conditionallyCheckInstanceCounts();
+ }
+ return true;
+ }
+ };
+
+ /**
* Sets the policy for what actions in the VM process (on any
* thread) should be detected, as well as the penalty if such
* actions occur.
@@ -1357,6 +1406,19 @@
sVmPolicy = policy;
sVmPolicyMask = policy.mask;
setCloseGuardEnabled(vmClosableObjectLeaksEnabled());
+
+ Looper looper = Looper.getMainLooper();
+ if (looper != null) {
+ MessageQueue mq = looper.mQueue;
+ synchronized (sProcessIdleHandler) {
+ if (policy.classInstanceLimit.size() == 0) {
+ mq.removeIdleHandler(sProcessIdleHandler);
+ } else if (!sIsIdlerRegistered) {
+ mq.addIdleHandler(sProcessIdleHandler);
+ sIsIdlerRegistered = true;
+ }
+ }
+ }
}
/**
@@ -1406,19 +1468,39 @@
onVmPolicyViolation(message, originStack);
}
+ // Map from VM violation fingerprint to uptime millis.
+ private static final HashMap<Integer, Long> sLastVmViolationTime = new HashMap<Integer, Long>();
+
/**
* @hide
*/
public static void onVmPolicyViolation(String message, Throwable originStack) {
- if ((sVmPolicyMask & PENALTY_LOG) != 0) {
+ final boolean penaltyDropbox = (sVmPolicyMask & PENALTY_DROPBOX) != 0;
+ final boolean penaltyDeath = (sVmPolicyMask & PENALTY_DEATH) != 0;
+ final boolean penaltyLog = (sVmPolicyMask & PENALTY_LOG) != 0;
+ final ViolationInfo info = new ViolationInfo(originStack, sVmPolicyMask);
+
+ final Integer fingerprint = info.hashCode();
+ final long now = SystemClock.uptimeMillis();
+ long lastViolationTime = 0;
+ long timeSinceLastViolationMillis = Long.MAX_VALUE;
+ synchronized (sLastVmViolationTime) {
+ if (sLastVmViolationTime.containsKey(fingerprint)) {
+ lastViolationTime = sLastVmViolationTime.get(fingerprint);
+ timeSinceLastViolationMillis = now - lastViolationTime;
+ }
+ if (timeSinceLastViolationMillis > MIN_LOG_INTERVAL_MS) {
+ sLastVmViolationTime.put(fingerprint, now);
+ }
+ }
+
+ Log.d(TAG, "Time since last vm violation: " + timeSinceLastViolationMillis);
+
+ if (penaltyLog && timeSinceLastViolationMillis > MIN_LOG_INTERVAL_MS) {
Log.e(TAG, message, originStack);
}
- boolean penaltyDropbox = (sVmPolicyMask & PENALTY_DROPBOX) != 0;
- boolean penaltyDeath = (sVmPolicyMask & PENALTY_DEATH) != 0;
-
- int violationMaskSubset = PENALTY_DROPBOX | DETECT_VM_CURSOR_LEAKS;
- ViolationInfo info = new ViolationInfo(originStack, sVmPolicyMask);
+ int violationMaskSubset = PENALTY_DROPBOX | (ALL_VM_DETECT_BITS & sVmPolicyMask);
if (penaltyDropbox && !penaltyDeath) {
// Common case for userdebug/eng builds. If no death and
@@ -1428,7 +1510,7 @@
return;
}
- if (penaltyDropbox) {
+ if (penaltyDropbox && lastViolationTime == 0) {
// The violationMask, passed to ActivityManager, is a
// subset of the original StrictMode policy bitmask, with
// only the bit violated and penalty bits to be executed
@@ -1786,6 +1868,12 @@
public String broadcastIntentAction;
/**
+ * If this is a instance count violation, the number of instances in memory,
+ * else -1.
+ */
+ public long numInstances = -1;
+
+ /**
* Create an uninitialized instance of ViolationInfo
*/
public ViolationInfo() {
@@ -1806,6 +1894,9 @@
broadcastIntentAction = broadcastIntent.getAction();
}
ThreadSpanState state = sThisThreadSpanState.get();
+ if (tr instanceof InstanceCountViolation) {
+ this.numInstances = ((InstanceCountViolation) tr).mInstances;
+ }
synchronized (state) {
int spanActiveCount = state.mActiveSize;
if (spanActiveCount > MAX_SPAN_TAGS) {
@@ -1867,6 +1958,7 @@
violationNumThisLoop = in.readInt();
numAnimationsRunning = in.readInt();
violationUptimeMillis = in.readLong();
+ numInstances = in.readLong();
broadcastIntentAction = in.readString();
tags = in.readStringArray();
}
@@ -1881,6 +1973,7 @@
dest.writeInt(violationNumThisLoop);
dest.writeInt(numAnimationsRunning);
dest.writeLong(violationUptimeMillis);
+ dest.writeLong(numInstances);
dest.writeString(broadcastIntentAction);
dest.writeStringArray(tags);
}
@@ -1895,6 +1988,9 @@
if (durationMillis != -1) {
pw.println(prefix + "durationMillis: " + durationMillis);
}
+ if (numInstances != -1) {
+ pw.println(prefix + "numInstances: " + numInstances);
+ }
if (violationNumThisLoop != 0) {
pw.println(prefix + "violationNumThisLoop: " + violationNumThisLoop);
}
@@ -1914,4 +2010,29 @@
}
}
+
+ // Dummy throwable, for now, since we don't know when or where the
+ // leaked instances came from. We might in the future, but for
+ // now we suppress the stack trace because it's useless and/or
+ // misleading.
+ private static class InstanceCountViolation extends Throwable {
+ final Class mClass;
+ final long mInstances;
+ final int mLimit;
+
+ private static final StackTraceElement[] FAKE_STACK = new StackTraceElement[1];
+ static {
+ FAKE_STACK[0] = new StackTraceElement("android.os.StrictMode", "setClassInstanceLimit",
+ "StrictMode.java", 1);
+ }
+
+ public InstanceCountViolation(Class klass, long instances, int limit) {
+ // Note: now including instances here, otherwise signatures would all be different.
+ super(klass.toString() + "; limit=" + limit);
+ setStackTrace(FAKE_STACK);
+ mClass = klass;
+ mInstances = instances;
+ mLimit = limit;
+ }
+ }
}
diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java
index 9f0ea32..82fe7de 100644
--- a/core/java/android/provider/MediaStore.java
+++ b/core/java/android/provider/MediaStore.java
@@ -57,6 +57,8 @@
* Broadcast Action: A broadcast to indicate the end of an MTP session with the host.
* This broadcast is only sent if MTP activity has modified the media database during the
* most recent MTP session.
+ *
+ * @hide
*/
public static final String ACTION_MTP_SESSION_END = "android.provider.action.MTP_SESSION_END";
diff --git a/core/java/android/server/BluetoothEventLoop.java b/core/java/android/server/BluetoothEventLoop.java
index 539a696..cd3bc3e 100644
--- a/core/java/android/server/BluetoothEventLoop.java
+++ b/core/java/android/server/BluetoothEventLoop.java
@@ -748,9 +748,9 @@
}
}
- private void onInputDeviceConnectionResult(String path, boolean result) {
+ private void onInputDeviceConnectionResult(String path, int result) {
// Success case gets handled by Property Change signal
- if (!result) {
+ if (result != BluetoothInputDevice.INPUT_OPERATION_SUCCESS) {
String address = mBluetoothService.getAddressFromObjectPath(path);
if (address == null) return;
@@ -758,9 +758,18 @@
BluetoothDevice device = mAdapter.getRemoteDevice(address);
int state = mBluetoothService.getInputDeviceState(device);
if (state == BluetoothInputDevice.STATE_CONNECTING) {
- connected = false;
+ if (result == BluetoothInputDevice.INPUT_CONNECT_FAILED_ALREADY_CONNECTED) {
+ connected = true;
+ } else {
+ connected = false;
+ }
} else if (state == BluetoothInputDevice.STATE_DISCONNECTING) {
- connected = true;
+ if (result == BluetoothInputDevice.INPUT_DISCONNECT_FAILED_NOT_CONNECTED) {
+ connected = false;
+ } else {
+ // There is no better way to handle this, this shouldn't happen
+ connected = true;
+ }
} else {
Log.e(TAG, "Error onInputDeviceConnectionResult. State is:" + state);
}
@@ -768,10 +777,10 @@
}
}
- private void onPanDeviceConnectionResult(String path, boolean result) {
+ private void onPanDeviceConnectionResult(String path, int result) {
log ("onPanDeviceConnectionResult " + path + " " + result);
// Success case gets handled by Property Change signal
- if (!result) {
+ if (result != BluetoothPan.PAN_OPERATION_SUCCESS) {
String address = mBluetoothService.getAddressFromObjectPath(path);
if (address == null) return;
@@ -779,9 +788,18 @@
BluetoothDevice device = mAdapter.getRemoteDevice(address);
int state = mBluetoothService.getPanDeviceState(device);
if (state == BluetoothPan.STATE_CONNECTING) {
- connected = false;
+ if (result == BluetoothPan.PAN_CONNECT_FAILED_ALREADY_CONNECTED) {
+ connected = true;
+ } else {
+ connected = false;
+ }
} else if (state == BluetoothPan.STATE_DISCONNECTING) {
- connected = true;
+ if (result == BluetoothPan.PAN_DISCONNECT_FAILED_NOT_CONNECTED) {
+ connected = false;
+ } else {
+ // There is no better way to handle this, this shouldn't happen
+ connected = true;
+ }
} else {
Log.e(TAG, "Error onPanDeviceConnectionResult. State is: "
+ state + " result: "+ result);
diff --git a/core/java/android/speech/tts/TextToSpeech.java b/core/java/android/speech/tts/TextToSpeech.java
index f010076..c46d2c5 100755
--- a/core/java/android/speech/tts/TextToSpeech.java
+++ b/core/java/android/speech/tts/TextToSpeech.java
@@ -349,19 +349,17 @@
*/
public static final String KEY_PARAM_UTTERANCE_ID = "utteranceId";
/**
- * {@hide}
* Parameter key to specify the speech volume relative to the current stream type
* volume used when speaking text. Volume is specified as a float ranging from 0 to 1
- * where 0 is silence, and 1 is the maximum volume.
+ * where 0 is silence, and 1 is the maximum volume (the default behavior).
* @see TextToSpeech#speak(String, int, HashMap)
* @see TextToSpeech#playEarcon(String, int, HashMap)
*/
public static final String KEY_PARAM_VOLUME = "volume";
/**
- * {@hide}
* Parameter key to specify how the speech is panned from left to right when speaking text.
* Pan is specified as a float ranging from -1 to +1 where -1 maps to a hard-left pan,
- * 0 to center, and +1 to hard-right.
+ * 0 to center (the default behavior), and +1 to hard-right.
* @see TextToSpeech#speak(String, int, HashMap)
* @see TextToSpeech#playEarcon(String, int, HashMap)
*/
diff --git a/core/java/android/view/DragEvent.java b/core/java/android/view/DragEvent.java
index 6634f00..25b680e6 100644
--- a/core/java/android/view/DragEvent.java
+++ b/core/java/android/view/DragEvent.java
@@ -274,7 +274,7 @@
public String toString() {
return "DragEvent{" + Integer.toHexString(System.identityHashCode(this))
+ " action=" + mAction + " @ (" + mX + ", " + mY + ") desc=" + mClipDescription
- + " data=" + mClipData + " result=" + mDragResult
+ + " data=" + mClipData + " local=" + mLocalState + " result=" + mDragResult
+ "}";
}
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index 99b686e..f480554 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -452,11 +452,14 @@
@Override
public int saveLayer(float left, float top, float right, float bottom, Paint paint,
int saveFlags) {
- boolean hasColorFilter = paint != null && setupColorFilter(paint);
- final int nativePaint = paint == null ? 0 : paint.mNativePaint;
- int count = nSaveLayer(mRenderer, left, top, right, bottom, nativePaint, saveFlags);
- if (hasColorFilter) nResetModifiers(mRenderer);
- return count;
+ if (left < right && top < bottom) {
+ boolean hasColorFilter = paint != null && setupColorFilter(paint);
+ final int nativePaint = paint == null ? 0 : paint.mNativePaint;
+ int count = nSaveLayer(mRenderer, left, top, right, bottom, nativePaint, saveFlags);
+ if (hasColorFilter) nResetModifiers(mRenderer);
+ return count;
+ }
+ return save(saveFlags);
}
private native int nSaveLayer(int renderer, float left, float top, float right, float bottom,
@@ -471,7 +474,10 @@
@Override
public int saveLayerAlpha(float left, float top, float right, float bottom, int alpha,
int saveFlags) {
- return nSaveLayerAlpha(mRenderer, left, top, right, bottom, alpha, saveFlags);
+ if (left < right && top < bottom) {
+ return nSaveLayerAlpha(mRenderer, left, top, right, bottom, alpha, saveFlags);
+ }
+ return save(saveFlags);
}
private native int nSaveLayerAlpha(int renderer, float left, float top, float right,
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index f9a6c1b..addd1b3 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -84,6 +84,13 @@
* @return True if the initialization was successful, false otherwise.
*/
abstract boolean initialize(SurfaceHolder holder);
+
+ /**
+ * Updates the hardware renderer for the specified surface.
+ *
+ * @param holder The holder for the surface to hardware accelerate.
+ */
+ abstract void updateSurface(SurfaceHolder holder);
/**
* Setup the hardware renderer for drawing. This is called for every
@@ -330,6 +337,13 @@
}
return false;
}
+
+ @Override
+ void updateSurface(SurfaceHolder holder) {
+ if (isRequested() && isEnabled()) {
+ createEglSurface(holder);
+ }
+ }
abstract GLES20Canvas createCanvas();
diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java
index e203355..0326a8f 100644
--- a/core/java/android/view/Surface.java
+++ b/core/java/android/view/Surface.java
@@ -159,6 +159,8 @@
private Canvas mCanvas;
@SuppressWarnings("unused")
private int mNativeSurface;
+ @SuppressWarnings("unused")
+ private int mSurfaceGenerationId;
private String mName;
// The display metrics used to provide the pseudo canvas size for applications
@@ -308,6 +310,13 @@
* returns false.
*/
public native boolean isValid();
+
+ /**
+ * @hide
+ */
+ public int getGenerationId() {
+ return mSurfaceGenerationId;
+ }
/** Free all server-side state associated with this surface and
* release this object's reference. {@hide} */
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 53fc0c0..2447f8c 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -58,7 +58,6 @@
import android.util.Pools;
import android.util.SparseArray;
import android.view.ContextMenu.ContextMenuInfo;
-import android.view.View.MeasureSpec;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityEventSource;
import android.view.accessibility.AccessibilityManager;
@@ -10606,13 +10605,38 @@
private final WeakReference<View> mView;
/**
- * Construct a shadow builder object for use with the given view.
- * @param view
+ * Construct a shadow builder object for use with the given View object. The
+ * default implementation will construct a drag shadow the same size and
+ * appearance as the supplied View.
+ *
+ * @param view A view within the application's layout whose appearance
+ * should be replicated as the drag shadow.
*/
public DragShadowBuilder(View view) {
mView = new WeakReference<View>(view);
}
+ /**
+ * Construct a shadow builder object with no associated View. This
+ * constructor variant is only useful when the {@link #onProvideShadowMetrics(Point, Point)}
+ * and {@link #onDrawShadow(Canvas)} methods are also overridden in order
+ * to supply the drag shadow's dimensions and appearance without
+ * reference to any View object.
+ */
+ public DragShadowBuilder() {
+ mView = new WeakReference<View>(null);
+ }
+
+ /**
+ * Returns the View object that had been passed to the
+ * {@link #View.DragShadowBuilder(View)}
+ * constructor. If that View parameter was {@code null} or if the
+ * {@link #View.DragShadowBuilder()}
+ * constructor was used to instantiate the builder object, this method will return
+ * null.
+ *
+ * @return The View object associate with this builder object.
+ */
final public View getView() {
return mView.get();
}
@@ -10623,8 +10647,10 @@
* be centered under the touch location while dragging.
* <p>
* The default implementation sets the dimensions of the shadow to be the
- * same as the dimensions of the View itself and centers the shadow under
- * the touch point.
+ * same as the dimensions of the View object that had been supplied to the
+ * {@link #View.DragShadowBuilder(View)} constructor
+ * when the builder object was instantiated, and centers the shadow under the touch
+ * point.
*
* @param shadowSize The application should set the {@code x} member of this
* parameter to the desired shadow width, and the {@code y} member to
@@ -10647,6 +10673,11 @@
* Draw the shadow image for the upcoming drag. The shadow canvas was
* created with the dimensions supplied by the
* {@link #onProvideShadowMetrics(Point, Point)} callback.
+ * <p>
+ * The default implementation replicates the appearance of the View object
+ * that had been supplied to the
+ * {@link #View.DragShadowBuilder(View)}
+ * constructor when the builder object was instantiated.
*
* @param canvas
*/
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index d1781cc..115431e 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -935,15 +935,17 @@
} break;
case DragEvent.ACTION_DRAG_ENDED: {
- // If a child was notified about an ongoing drag, it's told that it's over
- for (View child : mDragNotifiedChildren) {
- child.dispatchDragEvent(event);
- }
-
// Release the bookkeeping now that the drag lifecycle has ended
- mDragNotifiedChildren.clear();
- mCurrentDrag.recycle();
- mCurrentDrag = null;
+ if (mDragNotifiedChildren != null) {
+ for (View child : mDragNotifiedChildren) {
+ // If a child was notified about an ongoing drag, it's told that it's over
+ child.dispatchDragEvent(event);
+ }
+
+ mDragNotifiedChildren.clear();
+ mCurrentDrag.recycle();
+ mCurrentDrag = null;
+ }
// We consider drag-ended to have been handled if one of our children
// had offered to handle the drag.
diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java
index 96f8cdc..1f15628 100644
--- a/core/java/android/view/ViewRoot.java
+++ b/core/java/android/view/ViewRoot.java
@@ -983,6 +983,8 @@
Log.i(TAG, "host=w:" + host.getMeasuredWidth() + ", h:" +
host.getMeasuredHeight() + ", params=" + params);
}
+
+ final int surfaceGenerationId = mSurface.getGenerationId();
relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);
if (params != null) {
@@ -1043,6 +1045,9 @@
mScroller.abortAnimation();
}
disposeResizeBitmap();
+ } else if (surfaceGenerationId != mSurface.getGenerationId() &&
+ mSurfaceHolder == null && mAttachInfo.mHardwareRenderer != null) {
+ mAttachInfo.mHardwareRenderer.updateSurface(mHolder);
}
} catch (RemoteException e) {
}
@@ -2798,6 +2803,7 @@
// Report the drop result when we're done
if (what == DragEvent.ACTION_DROP) {
+ mDragDescription = null;
try {
Log.i(TAG, "Reporting drop result: " + result);
sWindowSession.reportDropResult(mWindow, result);
diff --git a/core/java/android/view/VolumePanel.java b/core/java/android/view/VolumePanel.java
index e21824e..e447dbb 100644
--- a/core/java/android/view/VolumePanel.java
+++ b/core/java/android/view/VolumePanel.java
@@ -284,10 +284,11 @@
synchronized (this) {
ToneGenerator toneGen = getOrCreateToneGenerator(streamType);
- toneGen.startTone(ToneGenerator.TONE_PROP_BEEP);
+ if (toneGen != null) {
+ toneGen.startTone(ToneGenerator.TONE_PROP_BEEP);
+ sendMessageDelayed(obtainMessage(MSG_STOP_SOUNDS), BEEP_DURATION);
+ }
}
-
- sendMessageDelayed(obtainMessage(MSG_STOP_SOUNDS), BEEP_DURATION);
}
protected void onStopSounds() {
@@ -319,10 +320,16 @@
private ToneGenerator getOrCreateToneGenerator(int streamType) {
synchronized (this) {
if (mToneGenerators[streamType] == null) {
- return mToneGenerators[streamType] = new ToneGenerator(streamType, MAX_VOLUME);
- } else {
- return mToneGenerators[streamType];
+ try {
+ mToneGenerators[streamType] = new ToneGenerator(streamType, MAX_VOLUME);
+ } catch (RuntimeException e) {
+ if (LOGD) {
+ Log.d(TAG, "ToneGenerator constructor failed with "
+ + "RuntimeException: " + e);
+ }
+ }
}
+ return mToneGenerators[streamType];
}
}
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index f1883dc..217e731 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -795,8 +795,11 @@
}
/** @hide */
- public boolean hasSetCloseOnTouchOutside() {
- return mSetCloseOnTouchOutside;
+ public void setCloseOnTouchOutsideIfNotSet(boolean close) {
+ if (!mSetCloseOnTouchOutside) {
+ mCloseOnTouchOutside = close;
+ mSetCloseOnTouchOutside = true;
+ }
}
/** @hide */
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index c54a3cf..8eb4269 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -817,7 +817,7 @@
public static final int SOFT_INPUT_IS_FORWARD_NAVIGATION = 0x100;
/**
- * Desired operating mode for any soft input area. May any combination
+ * Desired operating mode for any soft input area. May be any combination
* of:
*
* <ul>
diff --git a/core/java/android/webkit/HTML5VideoViewProxy.java b/core/java/android/webkit/HTML5VideoViewProxy.java
index 85bff4f..d8f34e0 100644
--- a/core/java/android/webkit/HTML5VideoViewProxy.java
+++ b/core/java/android/webkit/HTML5VideoViewProxy.java
@@ -495,6 +495,7 @@
break;
}
case ENDED:
+ mSeekPosition = 0;
nativeOnEnded(mNativePointer);
break;
case PAUSED:
@@ -538,10 +539,15 @@
* Play a video stream.
* @param url is the URL of the video stream.
*/
- public void play(String url) {
+ public void play(String url, int position) {
if (url == null) {
return;
}
+
+ if (position > 0) {
+ seek(position);
+ }
+
Message message = obtainMessage(PLAY);
message.obj = url;
sendMessage(message);
diff --git a/core/java/android/webkit/WebIconDatabase.java b/core/java/android/webkit/WebIconDatabase.java
index bb9ec48..54dfab3 100644
--- a/core/java/android/webkit/WebIconDatabase.java
+++ b/core/java/android/webkit/WebIconDatabase.java
@@ -24,6 +24,7 @@
import android.provider.Browser;
import android.util.Log;
+import java.io.File;
import java.util.HashMap;
import java.util.Vector;
@@ -194,13 +195,16 @@
/**
* Open a the icon database and store the icons in the given path.
* @param path The directory path where the icon database will be stored.
- * @return True if the database was successfully opened or created in
- * the given path.
*/
public void open(String path) {
if (path != null) {
+ // Make the directories and parents if they don't exist
+ File db = new File(path);
+ if (!db.exists()) {
+ db.mkdirs();
+ }
mEventHandler.postMessage(
- Message.obtain(null, EventHandler.OPEN, path));
+ Message.obtain(null, EventHandler.OPEN, db.getAbsolutePath()));
}
}
diff --git a/core/java/android/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java
index 2f96782b4..518ba69 100644
--- a/core/java/android/webkit/WebSettings.java
+++ b/core/java/android/webkit/WebSettings.java
@@ -1569,6 +1569,7 @@
public void setCacheMode(int mode) {
if (mode != mOverrideCacheMode) {
mOverrideCacheMode = mode;
+ postSync();
}
}
diff --git a/core/java/android/webkit/WebTextView.java b/core/java/android/webkit/WebTextView.java
index 1313fcc..72b0023 100644
--- a/core/java/android/webkit/WebTextView.java
+++ b/core/java/android/webkit/WebTextView.java
@@ -132,6 +132,10 @@
private boolean mAutoFillable; // Is this textview part of an autofillable form?
private int mQueryId;
private boolean mAutoFillProfileIsSet;
+ // Used to determine whether onFocusChanged was called as a result of
+ // calling remove().
+ private boolean mInsideRemove;
+ private boolean mInPassword;
// Types used with setType. Keep in sync with CachedInput.h
private static final int NORMAL_TEXT_FIELD = 0;
@@ -540,6 +544,11 @@
Rect previouslyFocusedRect) {
mFromFocusChange = true;
super.onFocusChanged(focused, direction, previouslyFocusedRect);
+ if (focused) {
+ mWebView.setActive(true);
+ } else if (!mInsideRemove) {
+ mWebView.setActive(false);
+ }
mFromFocusChange = false;
}
@@ -770,26 +779,17 @@
if (imm.isActive(this)) {
imm.hideSoftInputFromWindow(getWindowToken(), 0);
}
+ mInsideRemove = true;
mWebView.removeView(this);
mWebView.requestFocus();
- }
-
- /**
- * Move the caret/selection into view.
- */
- /* package */ void bringIntoView() {
- bringPointIntoView(Selection.getSelectionEnd(getText()));
+ mInsideRemove = false;
}
@Override
public boolean bringPointIntoView(int offset) {
- if (mWebView == null) return false;
- if (mWebView.nativeFocusCandidateIsPassword()) {
+ if (mInPassword) {
return getLayout() != null && super.bringPointIntoView(offset);
}
- // For non password text input, tell webkit to move the caret/selection
- // on screen, since webkit draws them.
- mWebView.revealSelection();
return true;
}
@@ -904,6 +904,7 @@
* @param inPassword True if the textfield is a password field.
*/
/* package */ void setInPassword(boolean inPassword) {
+ mInPassword = inPassword;
if (inPassword) {
setInputType(EditorInfo.TYPE_CLASS_TEXT | EditorInfo.
TYPE_TEXT_VARIATION_WEB_PASSWORD);
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 78d4cd2..7b3ea74 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -408,10 +408,13 @@
PluginFullScreenHolder mFullScreenHolder;
/**
- * Position of the last touch event.
+ * Position of the last touch event in pixels.
+ * Use integer to prevent loss of dragging delta calculation accuracy;
+ * which was done in float and converted to integer, and resulted in gradual
+ * and compounding touch position and view dragging mismatch.
*/
- private float mLastTouchX;
- private float mLastTouchY;
+ private int mLastTouchX;
+ private int mLastTouchY;
/**
* Time of the last touch event.
@@ -2218,8 +2221,8 @@
if (type == HitTestResult.UNKNOWN_TYPE
|| type == HitTestResult.SRC_ANCHOR_TYPE) {
// Now check to see if it is an image.
- int contentX = viewToContentX((int) mLastTouchX + mScrollX);
- int contentY = viewToContentY((int) mLastTouchY + mScrollY);
+ int contentX = viewToContentX(mLastTouchX + mScrollX);
+ int contentY = viewToContentY(mLastTouchY + mScrollY);
String text = nativeImageURI(contentX, contentY);
if (text != null) {
result.setType(type == HitTestResult.UNKNOWN_TYPE ?
@@ -2256,8 +2259,8 @@
if (hrefMsg == null) {
return;
}
- int contentX = viewToContentX((int) mLastTouchX + mScrollX);
- int contentY = viewToContentY((int) mLastTouchY + mScrollY);
+ int contentX = viewToContentX(mLastTouchX + mScrollX);
+ int contentY = viewToContentY(mLastTouchY + mScrollY);
mWebViewCore.sendMessage(EventHub.REQUEST_CURSOR_HREF,
contentX, contentY, hrefMsg);
}
@@ -2271,8 +2274,8 @@
*/
public void requestImageRef(Message msg) {
if (0 == mNativeClass) return; // client isn't initialized
- int contentX = viewToContentX((int) mLastTouchX + mScrollX);
- int contentY = viewToContentY((int) mLastTouchY + mScrollY);
+ int contentX = viewToContentX(mLastTouchX + mScrollX);
+ int contentY = viewToContentY(mLastTouchY + mScrollY);
String ref = nativeImageURI(contentX, contentY);
Bundle data = msg.getData();
data.putString("url", ref);
@@ -3856,8 +3859,8 @@
* @hide pending API council approval
*/
public boolean selectText() {
- int x = viewToContentX((int) mLastTouchX + mScrollX);
- int y = viewToContentY((int) mLastTouchY + mScrollY);
+ int x = viewToContentX(mLastTouchX + mScrollX);
+ int y = viewToContentY(mLastTouchY + mScrollY);
return selectText(x, y);
}
@@ -4268,7 +4271,7 @@
Rect vBox = contentToViewRect(bounds);
mWebTextView.setRect(vBox.left, vBox.top, vBox.width(), vBox.height());
if (!Rect.intersects(bounds, visibleRect)) {
- mWebTextView.bringIntoView();
+ revealSelection();
}
String text = nativeFocusCandidateText();
int nodePointer = nativeFocusCandidatePointer();
@@ -4858,8 +4861,8 @@
mSelectX = contentToViewX(rect.left);
mSelectY = contentToViewY(rect.top);
} else if (mLastTouchY > getVisibleTitleHeight()) {
- mSelectX = mScrollX + (int) mLastTouchX;
- mSelectY = mScrollY + (int) mLastTouchY;
+ mSelectX = mScrollX + mLastTouchX;
+ mSelectY = mScrollY + mLastTouchY;
} else {
mSelectX = mScrollX + getViewWidth() / 2;
mSelectY = mScrollY + getViewHeightWithTitle() / 2;
@@ -5050,7 +5053,7 @@
public void onGlobalFocusChanged(View oldFocus, View newFocus) {
}
- private void setActive(boolean active) {
+ void setActive(boolean active) {
if (active) {
if (hasFocus()) {
// If our window regained focus, and we have focus, then begin
@@ -5235,7 +5238,7 @@
if (event.getAction() == KeyEvent.ACTION_DOWN) {
mGotKeyDown = true;
} else {
- if (!mGotKeyDown) {
+ if (!mGotKeyDown && event.getAction() != KeyEvent.ACTION_MULTIPLE) {
/*
* We got a key up for which we were not the recipient of
* the original key down. Don't give it to the view.
@@ -5357,7 +5360,7 @@
return true;
}
- return handleTouchEventCommon(ev, ev.getX(), ev.getY());
+ return handleTouchEventCommon(ev, Math.round(ev.getX()), Math.round(ev.getY()));
}
/*
@@ -5365,7 +5368,7 @@
* (x, y) denotes current focus point, which is the touch point for single touch
* and the middle point for multi-touch.
*/
- private boolean handleTouchEventCommon(MotionEvent ev, float x, float y) {
+ private boolean handleTouchEventCommon(MotionEvent ev, int x, int y) {
int action = ev.getAction();
long eventTime = ev.getEventTime();
@@ -5377,12 +5380,10 @@
x = Math.min(x, getViewWidth() - 1);
y = Math.min(y, getViewHeightWithTitle() - 1);
- float fDeltaX = mLastTouchX - x;
- float fDeltaY = mLastTouchY - y;
- int deltaX = (int) fDeltaX;
- int deltaY = (int) fDeltaY;
- int contentX = viewToContentX((int) x + mScrollX);
- int contentY = viewToContentY((int) y + mScrollY);
+ int deltaX = mLastTouchX - x;
+ int deltaY = mLastTouchY - y;
+ int contentX = viewToContentX(x + mScrollX);
+ int contentY = viewToContentY(y + mScrollY);
switch (action) {
case MotionEvent.ACTION_DOWN: {
@@ -5607,8 +5608,6 @@
mTouchMode = TOUCH_DRAG_MODE;
mLastTouchX = x;
mLastTouchY = y;
- fDeltaX = 0.0f;
- fDeltaY = 0.0f;
deltaX = 0;
deltaY = 0;
@@ -5619,9 +5618,7 @@
// do pan
boolean done = false;
boolean keepScrollBarsVisible = false;
- if (Math.abs(fDeltaX) < 1.0f && Math.abs(fDeltaY) < 1.0f) {
- mLastTouchX = x;
- mLastTouchY = y;
+ if (deltaX == 0 && deltaY == 0) {
keepScrollBarsVisible = done = true;
} else {
if (mSnapScrollMode == SNAP_X || mSnapScrollMode == SNAP_Y) {
@@ -5670,12 +5667,6 @@
mLastTouchY = y;
}
mHeldMotionless = MOTIONLESS_FALSE;
- } else {
- // keep the scrollbar on the screen even there is no
- // scroll
- mLastTouchX = x;
- mLastTouchY = y;
- keepScrollBarsVisible = true;
}
mLastTouchTime = eventTime;
mUserScroll = true;
@@ -5937,8 +5928,8 @@
action = MotionEvent.ACTION_DOWN;
} else if (action == MotionEvent.ACTION_POINTER_UP) {
// set mLastTouchX/Y to the remaining point
- mLastTouchX = x;
- mLastTouchY = y;
+ mLastTouchX = Math.round(x);
+ mLastTouchY = Math.round(y);
} else if (action == MotionEvent.ACTION_MOVE) {
// negative x or y indicate it is on the edge, skip it.
if (x < 0 || y < 0) {
@@ -5946,7 +5937,7 @@
}
}
- return handleTouchEventCommon(ev, x, y);
+ return handleTouchEventCommon(ev, Math.round(x), Math.round(y));
}
private void cancelWebCoreTouchEvent(int x, int y, boolean removeEvents) {
@@ -5967,8 +5958,8 @@
private void startTouch(float x, float y, long eventTime) {
// Remember where the motion event started
- mLastTouchX = x;
- mLastTouchY = y;
+ mLastTouchX = Math.round(x);
+ mLastTouchY = Math.round(y);
mLastTouchTime = eventTime;
mVelocityTracker = VelocityTracker.obtain();
mSnapScrollMode = SNAP_NONE;
@@ -6598,8 +6589,8 @@
return;
}
// mLastTouchX and mLastTouchY are the point in the current viewport
- int contentX = viewToContentX((int) mLastTouchX + mScrollX);
- int contentY = viewToContentY((int) mLastTouchY + mScrollY);
+ int contentX = viewToContentX(mLastTouchX + mScrollX);
+ int contentY = viewToContentY(mLastTouchY + mScrollY);
Rect rect = new Rect(contentX - mNavSlop, contentY - mNavSlop,
contentX + mNavSlop, contentY + mNavSlop);
nativeSelectBestAt(rect);
@@ -6630,8 +6621,8 @@
if (!inEditingMode()) {
return;
}
- mLastTouchX = x + (float) (mWebTextView.getLeft() - mScrollX);
- mLastTouchY = y + (float) (mWebTextView.getTop() - mScrollY);
+ mLastTouchX = Math.round(x + mWebTextView.getLeft() - mScrollX);
+ mLastTouchY = Math.round(y + mWebTextView.getTop() - mScrollY);
mLastTouchTime = eventTime;
if (!mScroller.isFinished()) {
abortAnimation();
@@ -6690,8 +6681,8 @@
mTouchMode = TOUCH_DONE_MODE;
switchOutDrawHistory();
// mLastTouchX and mLastTouchY are the point in the current viewport
- int contentX = viewToContentX((int) mLastTouchX + mScrollX);
- int contentY = viewToContentY((int) mLastTouchY + mScrollY);
+ int contentX = viewToContentX(mLastTouchX + mScrollX);
+ int contentY = viewToContentY(mLastTouchY + mScrollY);
if (getSettings().supportTouchOnly()) {
removeTouchHighlight(false);
WebViewCore.TouchUpData touchUpData = new WebViewCore.TouchUpData();
@@ -7052,8 +7043,8 @@
|| (msg.arg1 == MotionEvent.ACTION_MOVE
&& mPreventDefault == PREVENT_DEFAULT_NO_FROM_TOUCH_DOWN)) {
cancelWebCoreTouchEvent(
- viewToContentX((int) mLastTouchX + mScrollX),
- viewToContentY((int) mLastTouchY + mScrollY),
+ viewToContentX(mLastTouchX + mScrollX),
+ viewToContentY(mLastTouchY + mScrollY),
true);
}
break;
@@ -7104,8 +7095,8 @@
ted.mIds = new int[1];
ted.mIds[0] = 0;
ted.mPoints = new Point[1];
- ted.mPoints[0] = new Point(viewToContentX((int) mLastTouchX + mScrollX),
- viewToContentY((int) mLastTouchY + mScrollY));
+ ted.mPoints[0] = new Point(viewToContentX(mLastTouchX + mScrollX),
+ viewToContentY(mLastTouchY + mScrollY));
// metaState for long press is tricky. Should it be the
// state when the press started or when the press was
// released? Or some intermediary key state? For
@@ -7274,7 +7265,6 @@
// this is sent after finishing resize in WebViewCore. Make
// sure the text edit box is still on the screen.
if (inEditingMode() && nativeCursorIsTextInput()) {
- mWebTextView.bringIntoView();
rebuildWebTextView();
}
break;
diff --git a/core/java/android/webkit/ZoomManager.java b/core/java/android/webkit/ZoomManager.java
index 88a54ea..9a050c5 100644
--- a/core/java/android/webkit/ZoomManager.java
+++ b/core/java/android/webkit/ZoomManager.java
@@ -148,13 +148,13 @@
*/
private float mInitialScale;
- private static float MINIMUM_SCALE_INCREMENT = 0.01f;
+ private static float MINIMUM_SCALE_INCREMENT = 0.007f;
/*
* The touch points could be changed even the fingers stop moving.
* We use the following to filter out the zooming jitters.
*/
- private static float MINIMUM_SCALE_WITHOUT_JITTER = 0.05f;
+ private static float MINIMUM_SCALE_WITHOUT_JITTER = 0.007f;
/*
* The following member variables are only to be used for animating zoom. If
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index d8f5972..a65de13 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -2439,8 +2439,12 @@
if (adapter != null && mItemCount > 0 &&
motionPosition != INVALID_POSITION &&
motionPosition < adapter.getCount() && sameWindow()) {
- performItemClick(getChildAt(motionPosition - mFirstPosition), motionPosition,
- adapter.getItemId(motionPosition));
+ final View view = getChildAt(motionPosition - mFirstPosition);
+ // If there is no view, something bad happened (the view scrolled off the
+ // screen, etc.) and we should cancel the click
+ if (view != null) {
+ performItemClick(view, motionPosition, adapter.getItemId(motionPosition));
+ }
}
}
}
@@ -5315,6 +5319,24 @@
mRecycler.mRecyclerListener = listener;
}
+ class AdapterDataSetObserver extends AdapterView<ListAdapter>.AdapterDataSetObserver {
+ @Override
+ public void onChanged() {
+ super.onChanged();
+ if (mFastScroller != null) {
+ mFastScroller.onSectionsChanged();
+ }
+ }
+
+ @Override
+ public void onInvalidated() {
+ super.onInvalidated();
+ if (mFastScroller != null) {
+ mFastScroller.onSectionsChanged();
+ }
+ }
+ }
+
/**
* A MultiChoiceModeListener receives events for {@link AbsListView#CHOICE_MODE_MULTIPLE_MODAL}.
* It acts as the {@link ActionMode.Callback} for the selection mode and also receives
diff --git a/core/java/android/widget/ArrayAdapter.java b/core/java/android/widget/ArrayAdapter.java
index b4ece24..593cb59 100644
--- a/core/java/android/widget/ArrayAdapter.java
+++ b/core/java/android/widget/ArrayAdapter.java
@@ -25,9 +25,9 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
-import java.util.List;
-import java.util.Comparator;
import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
/**
* A concrete BaseAdapter that is backed by an array of arbitrary
@@ -86,6 +86,8 @@
private Context mContext;
+ // A copy of the original mObjects array, initialized from and then used instead as soon as
+ // the mFilter ArrayFilter is used. mObjects will then only contain the filtered values.
private ArrayList<T> mOriginalValues;
private ArrayFilter mFilter;
@@ -170,15 +172,14 @@
* @param object The object to add at the end of the array.
*/
public void add(T object) {
- if (mOriginalValues != null) {
- synchronized (mLock) {
+ synchronized (mLock) {
+ if (mOriginalValues != null) {
mOriginalValues.add(object);
- if (mNotifyOnChange) notifyDataSetChanged();
+ } else {
+ mObjects.add(object);
}
- } else {
- mObjects.add(object);
- if (mNotifyOnChange) notifyDataSetChanged();
}
+ if (mNotifyOnChange) notifyDataSetChanged();
}
/**
@@ -187,15 +188,14 @@
* @param collection The Collection to add at the end of the array.
*/
public void addAll(Collection<? extends T> collection) {
- if (mOriginalValues != null) {
- synchronized (mLock) {
+ synchronized (mLock) {
+ if (mOriginalValues != null) {
mOriginalValues.addAll(collection);
- if (mNotifyOnChange) notifyDataSetChanged();
+ } else {
+ mObjects.addAll(collection);
}
- } else {
- mObjects.addAll(collection);
- if (mNotifyOnChange) notifyDataSetChanged();
}
+ if (mNotifyOnChange) notifyDataSetChanged();
}
/**
@@ -204,19 +204,18 @@
* @param items The items to add at the end of the array.
*/
public void addAll(T ... items) {
- if (mOriginalValues != null) {
- synchronized (mLock) {
+ synchronized (mLock) {
+ if (mOriginalValues != null) {
for (T item : items) {
mOriginalValues.add(item);
}
- if (mNotifyOnChange) notifyDataSetChanged();
+ } else {
+ for (T item : items) {
+ mObjects.add(item);
+ }
}
- } else {
- for (T item : items) {
- mObjects.add(item);
- }
- if (mNotifyOnChange) notifyDataSetChanged();
}
+ if (mNotifyOnChange) notifyDataSetChanged();
}
/**
@@ -226,15 +225,14 @@
* @param index The index at which the object must be inserted.
*/
public void insert(T object, int index) {
- if (mOriginalValues != null) {
- synchronized (mLock) {
+ synchronized (mLock) {
+ if (mOriginalValues != null) {
mOriginalValues.add(index, object);
- if (mNotifyOnChange) notifyDataSetChanged();
+ } else {
+ mObjects.add(index, object);
}
- } else {
- mObjects.add(index, object);
- if (mNotifyOnChange) notifyDataSetChanged();
}
+ if (mNotifyOnChange) notifyDataSetChanged();
}
/**
@@ -243,12 +241,12 @@
* @param object The object to remove.
*/
public void remove(T object) {
- if (mOriginalValues != null) {
- synchronized (mLock) {
+ synchronized (mLock) {
+ if (mOriginalValues != null) {
mOriginalValues.remove(object);
+ } else {
+ mObjects.remove(object);
}
- } else {
- mObjects.remove(object);
}
if (mNotifyOnChange) notifyDataSetChanged();
}
@@ -257,12 +255,12 @@
* Remove all elements from the list.
*/
public void clear() {
- if (mOriginalValues != null) {
- synchronized (mLock) {
+ synchronized (mLock) {
+ if (mOriginalValues != null) {
mOriginalValues.clear();
+ } else {
+ mObjects.clear();
}
- } else {
- mObjects.clear();
}
if (mNotifyOnChange) notifyDataSetChanged();
}
@@ -274,7 +272,13 @@
* in this adapter.
*/
public void sort(Comparator<? super T> comparator) {
- Collections.sort(mObjects, comparator);
+ synchronized (mLock) {
+ if (mOriginalValues != null) {
+ Collections.sort(mOriginalValues, comparator);
+ } else {
+ Collections.sort(mObjects, comparator);
+ }
+ }
if (mNotifyOnChange) notifyDataSetChanged();
}
@@ -482,6 +486,7 @@
final String[] words = valueText.split(" ");
final int wordCount = words.length;
+ // Start at index 0, in case valueText starts with space(s)
for (int k = 0; k < wordCount; k++) {
if (words[k].startsWith(prefixString)) {
newValues.add(value);
diff --git a/core/java/android/widget/AutoCompleteTextView.java b/core/java/android/widget/AutoCompleteTextView.java
index 4d8d21f..707b92d5 100644
--- a/core/java/android/widget/AutoCompleteTextView.java
+++ b/core/java/android/widget/AutoCompleteTextView.java
@@ -16,6 +16,8 @@
package android.widget;
+import com.android.internal.R;
+
import android.content.Context;
import android.content.res.TypedArray;
import android.database.DataSetObserver;
@@ -36,8 +38,6 @@
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
-import com.android.internal.R;
-
/**
* <p>An editable text view that shows completion suggestions automatically
@@ -113,6 +113,7 @@
private Validator mValidator = null;
+ // Set to true when text is set directly and no filtering shall be performed
private boolean mBlockCompletion;
private PassThroughClickListener mPassThroughClickListener;
@@ -721,6 +722,10 @@
return;
}
+ updateList();
+ }
+
+ private void updateList() {
// the drop down is shown only when a minimum number of characters
// was typed in the text view
if (enoughToFilter()) {
@@ -840,7 +845,7 @@
mBlockCompletion = true;
replaceText(convertSelectionToString(selectedItem));
- mBlockCompletion = false;
+ mBlockCompletion = false;
if (mItemClickListener != null) {
final ListPopupWindow list = mPopup;
@@ -903,10 +908,10 @@
/** {@inheritDoc} */
public void onFilterComplete(int count) {
- updateDropDownForFilter(count);
+ updateDropDownForFilter(count, true);
}
- private void updateDropDownForFilter(int count) {
+ private void updateDropDownForFilter(int count, boolean forceShow) {
// Not attached to window, don't update drop-down
if (getWindowVisibility() == View.GONE) return;
@@ -919,7 +924,7 @@
final boolean dropDownAlwaysVisible = mPopup.isDropDownAlwaysVisible();
if ((count > 0 || dropDownAlwaysVisible) && enoughToFilter()) {
- if (hasFocus() && hasWindowFocus()) {
+ if (hasFocus() && hasWindowFocus() && (forceShow || isPopupShowing())) {
showDropDown();
}
} else if (!dropDownAlwaysVisible) {
@@ -1182,12 +1187,14 @@
// If the popup is not showing already, showing it will cause
// the list of data set observers attached to the adapter to
// change. We can't do it from here, because we are in the middle
- // of iterating throught he list of observers.
+ // of iterating through the list of observers.
post(new Runnable() {
public void run() {
final ListAdapter adapter = mAdapter;
if (adapter != null) {
- updateDropDownForFilter(adapter.getCount());
+ // This will re-layout, thus resetting mDataChanged, so that the
+ // listView click listener stays responsive
+ updateDropDownForFilter(adapter.getCount(), false);
}
}
});
diff --git a/core/java/android/widget/DatePicker.java b/core/java/android/widget/DatePicker.java
index 2c53005..af5de8a 100644
--- a/core/java/android/widget/DatePicker.java
+++ b/core/java/android/widget/DatePicker.java
@@ -129,27 +129,30 @@
}
public DatePicker(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
+ this(context, attrs, R.attr.datePickerStyle);
}
public DatePicker(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
- TypedArray attributesArray = context.obtainStyledAttributes(attrs, R.styleable.DatePicker);
+ TypedArray attributesArray = context.obtainStyledAttributes(attrs, R.styleable.DatePicker,
+ defStyle, 0);
boolean spinnersShown = attributesArray.getBoolean(R.styleable.DatePicker_spinnersShown,
DEFAULT_SPINNERS_SHOWN);
boolean calendarViewShown = attributesArray.getBoolean(
R.styleable.DatePicker_calendarViewShown, DEFAULT_CALENDAR_VIEW_SHOWN);
- int startYear = attributesArray
- .getInt(R.styleable.DatePicker_startYear, DEFAULT_START_YEAR);
+ int startYear = attributesArray.getInt(R.styleable.DatePicker_startYear,
+ DEFAULT_START_YEAR);
int endYear = attributesArray.getInt(R.styleable.DatePicker_endYear, DEFAULT_END_YEAR);
String minDate = attributesArray.getString(R.styleable.DatePicker_minDate);
String maxDate = attributesArray.getString(R.styleable.DatePicker_maxDate);
+ int layoutResourceId = attributesArray.getResourceId(R.styleable.DatePicker_layout,
+ R.layout.date_picker);
attributesArray.recycle();
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- inflater.inflate(R.layout.date_picker, this, true);
+ inflater.inflate(layoutResourceId, this, true);
OnValueChangedListener onChangeListener = new OnValueChangedListener() {
public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
diff --git a/core/java/android/widget/FastScroller.java b/core/java/android/widget/FastScroller.java
index dfa94c7..200c870 100644
--- a/core/java/android/widget/FastScroller.java
+++ b/core/java/android/widget/FastScroller.java
@@ -476,6 +476,10 @@
}
}
+ public void onSectionsChanged() {
+ mListAdapter = null;
+ }
+
private void scrollTo(float position) {
int count = mList.getCount();
mScrollCompleted = false;
diff --git a/core/java/android/widget/NumberPicker.java b/core/java/android/widget/NumberPicker.java
index 63dbfbf..ba1c0ec 100644
--- a/core/java/android/widget/NumberPicker.java
+++ b/core/java/android/widget/NumberPicker.java
@@ -62,8 +62,6 @@
* <p>
* For an example of using this widget, see {@link android.widget.TimePicker}.
* </p>
- *
- * @attr ref android.R.styleable#NumberPicker_solidColor
*/
@Widget
public class NumberPicker extends LinearLayout {
@@ -325,6 +323,11 @@
private final int mSolidColor;
/**
+ * Flag indicating if this widget supports flinging.
+ */
+ private final boolean mFlingable;
+
+ /**
* Reusable {@link Rect} instance.
*/
private final Rect mTempRect = new Rect();
@@ -427,9 +430,8 @@
// process style attributes
TypedArray attributesArray = context.obtainStyledAttributes(attrs,
R.styleable.NumberPicker, defStyle, 0);
- int orientation = attributesArray.getInt(R.styleable.NumberPicker_orientation, VERTICAL);
- setOrientation(orientation);
mSolidColor = attributesArray.getColor(R.styleable.NumberPicker_solidColor, 0);
+ mFlingable = attributesArray.getBoolean(R.styleable.NumberPicker_flingable, true);
attributesArray.recycle();
// By default Linearlayout that we extend is not drawn. This is
@@ -563,7 +565,7 @@
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
- if (!isEnabled()) {
+ if (!isEnabled() || !mFlingable) {
return false;
}
switch (event.getActionMasked()) {
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 8f25311..482ce56 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -59,6 +59,12 @@
private static final String LOG_TAG = "RemoteViews";
/**
+ * The intent extra that contains the appWidgetId.
+ * @hide
+ */
+ static final String EXTRA_REMOTEADAPTER_APPWIDGET_ID = "remoteAdapterAppWidgetId";
+
+ /**
* The package name of the package containing the layout
* resource. (Added to the parcel)
*/
@@ -1271,11 +1277,15 @@
/**
* Equivalent to calling {@link android.widget.AbsListView#setRemoteViewsAdapter(Intent)}.
*
+ * @param appWidgetId The id of the app widget which contains the specified view
* @param viewId The id of the view whose text should change
* @param intent The intent of the service which will be
* providing data to the RemoteViewsAdapter
*/
- public void setRemoteAdapter(int viewId, Intent intent) {
+ public void setRemoteAdapter(int appWidgetId, int viewId, Intent intent) {
+ // Embed the AppWidget Id for use in RemoteViewsAdapter when connecting to the intent
+ // RemoteViewsService
+ intent.putExtra(EXTRA_REMOTEADAPTER_APPWIDGET_ID, appWidgetId);
setIntent(viewId, "setRemoteViewsAdapter", intent);
}
diff --git a/core/java/android/widget/RemoteViewsAdapter.java b/core/java/android/widget/RemoteViewsAdapter.java
index ab69725..f329a3e 100644
--- a/core/java/android/widget/RemoteViewsAdapter.java
+++ b/core/java/android/widget/RemoteViewsAdapter.java
@@ -22,20 +22,21 @@
import java.util.LinkedList;
import java.util.Map;
-import android.content.ComponentName;
+import android.appwidget.AppWidgetManager;
import android.content.Context;
import android.content.Intent;
-import android.content.ServiceConnection;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Looper;
+import android.os.Message;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.View.MeasureSpec;
+import com.android.internal.widget.IRemoteViewsAdapterConnection;
import com.android.internal.widget.IRemoteViewsFactory;
/**
@@ -43,11 +44,22 @@
* to be later inflated as child views.
*/
/** @hide */
-public class RemoteViewsAdapter extends BaseAdapter {
+public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback {
private static final String TAG = "RemoteViewsAdapter";
- private Context mContext;
- private Intent mIntent;
+ // The max number of items in the cache
+ private static final int sDefaultCacheSize = 36;
+ // The delay (in millis) to wait until attempting to unbind from a service after a request.
+ // This ensures that we don't stay continually bound to the service and that it can be destroyed
+ // if we need the memory elsewhere in the system.
+ private static final int sUnbindServiceDelay = 5000;
+ // Type defs for controlling different messages across the main and worker message queues
+ private static final int sDefaultMessageType = 0;
+ private static final int sUnbindServiceMessageType = 1;
+
+ private final Context mContext;
+ private final Intent mIntent;
+ private final int mAppWidgetId;
private LayoutInflater mLayoutInflater;
private RemoteViewsAdapterServiceConnection mServiceConnection;
private WeakReference<RemoteAdapterConnectionCallback> mCallback;
@@ -79,7 +91,8 @@
* garbage collected, and would cause us to leak activities due to the caching mechanism for
* FrameLayouts in the adapter).
*/
- private static class RemoteViewsAdapterServiceConnection implements ServiceConnection {
+ private static class RemoteViewsAdapterServiceConnection extends
+ IRemoteViewsAdapterConnection.Stub {
private boolean mConnected;
private WeakReference<RemoteViewsAdapter> mAdapter;
private IRemoteViewsFactory mRemoteViewsFactory;
@@ -88,8 +101,7 @@
mAdapter = new WeakReference<RemoteViewsAdapter>(adapter);
}
- public void onServiceConnected(ComponentName name,
- IBinder service) {
+ public void onServiceConnected(IBinder service) {
mRemoteViewsFactory = IRemoteViewsFactory.Stub.asInterface(service);
mConnected = true;
@@ -137,7 +149,7 @@
});
}
- public void onServiceDisconnected(ComponentName name) {
+ public void onServiceDisconnected() {
mConnected = false;
mRemoteViewsFactory = null;
@@ -145,8 +157,9 @@
if (adapter == null) return;
// Clear the main/worker queues
- adapter.mMainQueue.removeMessages(0);
- adapter.mWorkerQueue.removeMessages(0);
+ adapter.mMainQueue.removeMessages(sUnbindServiceMessageType);
+ adapter.mMainQueue.removeMessages(sDefaultMessageType);
+ adapter.mWorkerQueue.removeMessages(sDefaultMessageType);
final RemoteAdapterConnectionCallback callback = adapter.mCallback.get();
if (callback != null) {
@@ -574,20 +587,26 @@
public RemoteViewsAdapter(Context context, Intent intent, RemoteAdapterConnectionCallback callback) {
mContext = context;
mIntent = intent;
+ mAppWidgetId = intent.getIntExtra(RemoteViews.EXTRA_REMOTEADAPTER_APPWIDGET_ID, -1);
mLayoutInflater = LayoutInflater.from(context);
if (mIntent == null) {
throw new IllegalArgumentException("Non-null Intent must be specified.");
}
mRequestedViews = new RemoteViewsFrameLayoutRefSet();
- // initialize the worker thread
+ // Strip the previously injected app widget id from service intent
+ if (intent.hasExtra(RemoteViews.EXTRA_REMOTEADAPTER_APPWIDGET_ID)) {
+ intent.removeExtra(RemoteViews.EXTRA_REMOTEADAPTER_APPWIDGET_ID);
+ }
+
+ // Initialize the worker thread
mWorkerThread = new HandlerThread("RemoteViewsCache-loader");
mWorkerThread.start();
mWorkerQueue = new Handler(mWorkerThread.getLooper());
- mMainQueue = new Handler(Looper.myLooper());
+ mMainQueue = new Handler(Looper.myLooper(), this);
- // initialize the cache and the service connection on startup
- mCache = new FixedSizeRemoteViewsCache(50);
+ // Initialize the cache and the service connection on startup
+ mCache = new FixedSizeRemoteViewsCache(sDefaultCacheSize);
mCallback = new WeakReference<RemoteAdapterConnectionCallback>(callback);
mServiceConnection = new RemoteViewsAdapterServiceConnection(this);
requestBindService();
@@ -687,6 +706,7 @@
@Override
public void run() {
mRequestedViews.notifyOnRemoteViewsLoaded(position, rv, typeId);
+ enqueueDeferredUnbindServiceMessage();
}
});
}
@@ -879,10 +899,36 @@
super.notifyDataSetChanged();
}
+ @Override
+ public boolean handleMessage(Message msg) {
+ boolean result = false;
+ switch (msg.what) {
+ case sUnbindServiceMessageType:
+ final AppWidgetManager mgr = AppWidgetManager.getInstance(mContext);
+ if (mServiceConnection.isConnected()) {
+ mgr.unbindRemoteViewsService(mAppWidgetId, mIntent);
+ }
+ result = true;
+ break;
+ default:
+ break;
+ }
+ return result;
+ }
+
+ private void enqueueDeferredUnbindServiceMessage() {
+ /* Temporarily disable delayed service unbinding
+ // Remove any existing deferred-unbind messages
+ mMainQueue.removeMessages(sUnbindServiceMessageType);
+ mMainQueue.sendEmptyMessageDelayed(sUnbindServiceMessageType, sUnbindServiceDelay);
+ */
+ }
+
private boolean requestBindService() {
- // try binding the service (which will start it if it's not already running)
+ // Try binding the service (which will start it if it's not already running)
if (!mServiceConnection.isConnected()) {
- mContext.bindService(mIntent, mServiceConnection, Context.BIND_AUTO_CREATE);
+ final AppWidgetManager mgr = AppWidgetManager.getInstance(mContext);
+ mgr.bindRemoteViewsService(mAppWidgetId, mIntent, mServiceConnection.asBinder());
}
return mServiceConnection.isConnected();
diff --git a/core/java/android/widget/SuggestionsAdapter.java b/core/java/android/widget/SuggestionsAdapter.java
index 1ebe622..2cfc016 100644
--- a/core/java/android/widget/SuggestionsAdapter.java
+++ b/core/java/android/widget/SuggestionsAdapter.java
@@ -78,15 +78,15 @@
// URL color
private ColorStateList mUrlColor;
- // Cached column indexes, updated when the cursor changes.
- private int mText1Col;
- private int mText2Col;
- private int mText2UrlCol;
- private int mIconName1Col;
- private int mIconName2Col;
- private int mFlagsCol;
+ static final int INVALID_INDEX = -1;
- static final int NONE = -1;
+ // Cached column indexes, updated when the cursor changes.
+ private int mText1Col = INVALID_INDEX;
+ private int mText2Col = INVALID_INDEX;
+ private int mText2UrlCol = INVALID_INDEX;
+ private int mIconName1Col = INVALID_INDEX;
+ private int mIconName2Col = INVALID_INDEX;
+ private int mFlagsCol = INVALID_INDEX;
private final Runnable mStartSpinnerRunnable;
private final Runnable mStopSpinnerRunnable;
@@ -308,7 +308,7 @@
ChildViewCache views = (ChildViewCache) view.getTag();
int flags = 0;
- if (mFlagsCol != -1) {
+ if (mFlagsCol != INVALID_INDEX) {
flags = cursor.getInt(mFlagsCol);
}
if (views.mText1 != null) {
@@ -391,7 +391,7 @@
}
private Drawable getIcon1(Cursor cursor) {
- if (mIconName1Col < 0) {
+ if (mIconName1Col == INVALID_INDEX) {
return null;
}
String value = cursor.getString(mIconName1Col);
@@ -403,7 +403,7 @@
}
private Drawable getIcon2(Cursor cursor) {
- if (mIconName2Col < 0) {
+ if (mIconName2Col == INVALID_INDEX) {
return null;
}
String value = cursor.getString(mIconName2Col);
@@ -687,7 +687,7 @@
}
private static String getStringOrNull(Cursor cursor, int col) {
- if (col == NONE) {
+ if (col == INVALID_INDEX) {
return null;
}
try {
diff --git a/core/java/android/widget/TimePicker.java b/core/java/android/widget/TimePicker.java
index 8f3442e..26fbbbd 100644
--- a/core/java/android/widget/TimePicker.java
+++ b/core/java/android/widget/TimePicker.java
@@ -20,6 +20,7 @@
import android.annotation.Widget;
import android.content.Context;
+import android.content.res.TypedArray;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.AttributeSet;
@@ -31,50 +32,55 @@
import java.util.Calendar;
/**
- * A view for selecting the time of day, in either 24 hour or AM/PM mode.
- *
- * The hour, each minute digit, and AM/PM (if applicable) can be conrolled by
- * vertical spinners.
- *
- * The hour can be entered by keyboard input. Entering in two digit hours
- * can be accomplished by hitting two digits within a timeout of about a
- * second (e.g. '1' then '2' to select 12).
- *
- * The minutes can be entered by entering single digits.
- *
- * Under AM/PM mode, the user can hit 'a', 'A", 'p' or 'P' to pick.
- *
- * For a dialog using this view, see {@link android.app.TimePickerDialog}.
- *
- * <p>See the <a href="{@docRoot}resources/tutorials/views/hello-timepicker.html">Time Picker
- * tutorial</a>.</p>
+ * A view for selecting the time of day, in either 24 hour or AM/PM mode. The
+ * hour, each minute digit, and AM/PM (if applicable) can be conrolled by
+ * vertical spinners. The hour can be entered by keyboard input. Entering in two
+ * digit hours can be accomplished by hitting two digits within a timeout of
+ * about a second (e.g. '1' then '2' to select 12). The minutes can be entered
+ * by entering single digits. Under AM/PM mode, the user can hit 'a', 'A", 'p'
+ * or 'P' to pick. For a dialog using this view, see
+ * {@link android.app.TimePickerDialog}.
+ *<p>
+ * See the <a href="{@docRoot}
+ * resources/tutorials/views/hello-timepicker.html">Time Picker tutorial</a>.
+ * </p>
*/
@Widget
public class TimePicker extends FrameLayout {
private static final boolean DEFAULT_ENABLED_STATE = true;
+ private static final int HOURS_IN_HALF_DAY = 12;
+
/**
- * A no-op callback used in the constructor to avoid null checks
- * later in the code.
+ * A no-op callback used in the constructor to avoid null checks later in
+ * the code.
*/
private static final OnTimeChangedListener NO_OP_CHANGE_LISTENER = new OnTimeChangedListener() {
public void onTimeChanged(TimePicker view, int hourOfDay, int minute) {
}
};
-
+
// state
- private int mCurrentHour = 0; // 0-23
- private int mCurrentMinute = 0; // 0-59
- private Boolean mIs24HourView = false;
+ private boolean mIs24HourView;
+
private boolean mIsAm;
// ui components
private final NumberPicker mHourSpinner;
+
private final NumberPicker mMinuteSpinner;
+
private final NumberPicker mAmPmSpinner;
+
private final TextView mDivider;
+ // Note that the legacy implementation of the TimePicker is
+ // using a button for toggling between AM/PM while the new
+ // version uses a NumberPicker spinner. Therefore the code
+ // accommodates these two cases to be backwards compatible.
+ private final Button mAmPmButton;
+
private final String[] mAmPmStrings;
private boolean mIsEnabled = DEFAULT_ENABLED_STATE;
@@ -98,45 +104,51 @@
public TimePicker(Context context) {
this(context, null);
}
-
+
public TimePicker(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
+ this(context, attrs, R.attr.timePickerStyle);
}
public TimePicker(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
- LayoutInflater inflater =
- (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- inflater.inflate(R.layout.time_picker,
- this, // we are the parent
- true);
+ // process style attributes
+ TypedArray attributesArray = context.obtainStyledAttributes(
+ attrs, R.styleable.TimePicker, defStyle, 0);
+ int layoutResourceId = attributesArray.getResourceId(
+ R.styleable.TimePicker_layout, R.layout.time_picker);
+ attributesArray.recycle();
+
+ LayoutInflater inflater = (LayoutInflater) context.getSystemService(
+ Context.LAYOUT_INFLATER_SERVICE);
+ inflater.inflate(layoutResourceId, this, true);
// hour
mHourSpinner = (NumberPicker) findViewById(R.id.hour);
mHourSpinner.setOnValueChangedListener(new NumberPicker.OnValueChangedListener() {
public void onValueChange(NumberPicker spinner, int oldVal, int newVal) {
- mCurrentHour = newVal;
- if (!mIs24HourView) {
- // adjust from [1-12] to [0-11] internally, with the times
- // written "12:xx" being the start of the half-day
- if (mCurrentHour == 12) {
- mCurrentHour = 0;
- }
- if (!mIsAm) {
- // PM means 12 hours later than nominal
- mCurrentHour += 12;
+ if (!is24HourView()) {
+ int minValue = mHourSpinner.getMinValue();
+ int maxValue = mHourSpinner.getMaxValue();
+ // toggle AM/PM if the spinner has wrapped and not in 24
+ // format
+ if ((oldVal == maxValue && newVal == minValue)
+ || (oldVal == minValue && newVal == maxValue)) {
+ mIsAm = !mIsAm;
+ updateAmPmControl();
}
}
onTimeChanged();
}
});
- // divider
+ // divider (only for the new widget style)
mDivider = (TextView) findViewById(R.id.divider);
- mDivider.setText(R.string.time_picker_separator);
+ if (mDivider != null) {
+ mDivider.setText(R.string.time_picker_separator);
+ }
- // digits of minute
+ // minute
mMinuteSpinner = (NumberPicker) findViewById(R.id.minute);
mMinuteSpinner.setMinValue(0);
mMinuteSpinner.setMaxValue(59);
@@ -144,28 +156,25 @@
mMinuteSpinner.setFormatter(NumberPicker.TWO_DIGIT_FORMATTER);
mMinuteSpinner.setOnValueChangedListener(new NumberPicker.OnValueChangedListener() {
public void onValueChange(NumberPicker spinner, int oldVal, int newVal) {
- mCurrentMinute = newVal;
- onTimeChanged();
- }
- });
-
- // am/pm
- mAmPmSpinner = (NumberPicker) findViewById(R.id.amPm);
- mAmPmSpinner.setOnValueChangedListener(new OnValueChangedListener() {
- public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
- picker.requestFocus();
- if (mIsAm) {
- // Currently AM switching to PM
- if (mCurrentHour < 12) {
- mCurrentHour += 12;
+ int minValue = mMinuteSpinner.getMinValue();
+ int maxValue = mMinuteSpinner.getMaxValue();
+ if (oldVal == maxValue && newVal == minValue) {
+ int currentHour = mHourSpinner.getValue();
+ // toggle AM/PM if the spinner is about to wrap
+ if (!is24HourView() && currentHour == mHourSpinner.getMaxValue()) {
+ mIsAm = !mIsAm;
+ updateAmPmControl();
}
- } else {
- // Currently PM switching to AM
- if (mCurrentHour >= 12) {
- mCurrentHour -= 12;
+ mHourSpinner.setValue(currentHour + 1);
+ } else if (oldVal == minValue && newVal == maxValue) {
+ int currentHour = mHourSpinner.getValue();
+ // toggle AM/PM if the spinner is about to wrap
+ if (!is24HourView() && currentHour == mHourSpinner.getMinValue()) {
+ mIsAm = !mIsAm;
+ updateAmPmControl();
}
+ mHourSpinner.setValue(currentHour - 1);
}
- mIsAm = !mIsAm;
onTimeChanged();
}
});
@@ -173,17 +182,44 @@
/* Get the localized am/pm strings and use them in the spinner */
mAmPmStrings = new DateFormatSymbols().getAmPmStrings();
- // now that the hour/minute picker objects have been initialized, set
- // the hour range properly based on the 12/24 hour display mode.
- configurePickerRanges();
+ // am/pm
+ View amPmView = findViewById(R.id.amPm);
+ if (amPmView instanceof Button) {
+ mAmPmSpinner = null;
+ mAmPmButton = (Button) amPmView;
+ mAmPmButton.setOnClickListener(new OnClickListener() {
+ public void onClick(View button) {
+ button.requestFocus();
+ mIsAm = !mIsAm;
+ updateAmPmControl();
+ }
+ });
+ } else {
+ mAmPmButton = null;
+ mAmPmSpinner = (NumberPicker) amPmView;
+ mAmPmSpinner.setMinValue(0);
+ mAmPmSpinner.setMaxValue(1);
+ mAmPmSpinner.setDisplayedValues(mAmPmStrings);
+ mAmPmSpinner.setOnValueChangedListener(new OnValueChangedListener() {
+ public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
+ picker.requestFocus();
+ mIsAm = !mIsAm;
+ updateAmPmControl();
+ }
+ });
+ }
+
+ // update controls to initial state
+ updateHourControl();
+ updateAmPmControl();
// initialize to current time
- Calendar cal = Calendar.getInstance();
+ Calendar calendar = Calendar.getInstance();
setOnTimeChangedListener(NO_OP_CHANGE_LISTENER);
- // by default we're not in 24 hour mode
- setCurrentHour(cal.get(Calendar.HOUR_OF_DAY));
- setCurrentMinute(cal.get(Calendar.MINUTE));
+ // set to current time
+ setCurrentHour(calendar.get(Calendar.HOUR_OF_DAY));
+ setCurrentMinute(calendar.get(Calendar.MINUTE));
if (!isEnabled()) {
setEnabled(false);
@@ -197,9 +233,15 @@
}
super.setEnabled(enabled);
mMinuteSpinner.setEnabled(enabled);
- mDivider.setEnabled(enabled);
+ if (mDivider != null) {
+ mDivider.setEnabled(enabled);
+ }
mHourSpinner.setEnabled(enabled);
- mAmPmSpinner.setEnabled(enabled);
+ if (mAmPmSpinner != null) {
+ mAmPmSpinner.setEnabled(enabled);
+ } else {
+ mAmPmButton.setEnabled(enabled);
+ }
mIsEnabled = enabled;
}
@@ -214,6 +256,7 @@
private static class SavedState extends BaseSavedState {
private final int mHour;
+
private final int mMinute;
private SavedState(Parcelable superState, int hour, int minute) {
@@ -221,7 +264,7 @@
mHour = hour;
mMinute = minute;
}
-
+
private SavedState(Parcel in) {
super(in);
mHour = in.readInt();
@@ -244,8 +287,7 @@
}
@SuppressWarnings("unused")
- public static final Parcelable.Creator<SavedState> CREATOR
- = new Creator<SavedState>() {
+ public static final Parcelable.Creator<SavedState> CREATOR = new Creator<SavedState>() {
public SavedState createFromParcel(Parcel in) {
return new SavedState(in);
}
@@ -259,7 +301,7 @@
@Override
protected Parcelable onSaveInstanceState() {
Parcelable superState = super.onSaveInstanceState();
- return new SavedState(superState, mCurrentHour, mCurrentMinute);
+ return new SavedState(superState, getCurrentHour(), getCurrentMinute());
}
@Override
@@ -272,6 +314,7 @@
/**
* Set the callback that indicates the time has been adjusted by the user.
+ *
* @param onTimeChangedListener the callback, should not be null.
*/
public void setOnTimeChangedListener(OnTimeChangedListener onTimeChangedListener) {
@@ -279,30 +322,58 @@
}
/**
- * @return The current hour (0-23).
+ * @return The current hour in the range (0-23).
*/
public Integer getCurrentHour() {
- return mCurrentHour;
+ int currentHour = mHourSpinner.getValue();
+ if (is24HourView() || mIsAm) {
+ return currentHour;
+ } else {
+ return (currentHour == HOURS_IN_HALF_DAY) ? 0 : currentHour + HOURS_IN_HALF_DAY;
+ }
}
/**
* Set the current hour.
*/
public void setCurrentHour(Integer currentHour) {
- this.mCurrentHour = currentHour;
- updateHourDisplay();
+ // why was Integer used in the first place?
+ if (currentHour == null || currentHour == getCurrentHour()) {
+ return;
+ }
+ if (!is24HourView()) {
+ // convert [0,23] ordinal to wall clock display
+ if (currentHour > HOURS_IN_HALF_DAY) {
+ currentHour -= HOURS_IN_HALF_DAY;
+ mIsAm = false;
+ } else {
+ if (currentHour == 0) {
+ currentHour = HOURS_IN_HALF_DAY;
+ }
+ mIsAm = true;
+ }
+ updateAmPmControl();
+ }
+ mHourSpinner.setValue(currentHour);
+ onTimeChanged();
}
/**
* Set whether in 24 hour or AM/PM mode.
+ *
* @param is24HourView True = 24 hour mode. False = AM/PM.
*/
public void setIs24HourView(Boolean is24HourView) {
- if (mIs24HourView != is24HourView) {
- mIs24HourView = is24HourView;
- configurePickerRanges();
- updateHourDisplay();
+ if (mIs24HourView == is24HourView) {
+ return;
}
+ mIs24HourView = is24HourView;
+ // cache the current hour since spinner range changes
+ int currentHour = getCurrentHour();
+ updateHourControl();
+ // set value after spinner range is updated
+ setCurrentHour(currentHour);
+ updateAmPmControl();
}
/**
@@ -311,20 +382,23 @@
public boolean is24HourView() {
return mIs24HourView;
}
-
+
/**
* @return The current minute.
*/
public Integer getCurrentMinute() {
- return mCurrentMinute;
+ return mMinuteSpinner.getValue();
}
/**
* Set the current minute (0-59).
*/
public void setCurrentMinute(Integer currentMinute) {
- this.mCurrentMinute = currentMinute;
- updateMinuteDisplay();
+ if (currentMinute == getCurrentMinute()) {
+ return;
+ }
+ mMinuteSpinner.setValue(currentMinute);
+ onTimeChanged();
}
@Override
@@ -332,39 +406,34 @@
return mHourSpinner.getBaseline();
}
- /**
- * Set the state of the spinners appropriate to the current hour.
- */
- private void updateHourDisplay() {
- int currentHour = mCurrentHour;
- if (!mIs24HourView) {
- // convert [0,23] ordinal to wall clock display
- if (currentHour > 12) {
- currentHour -= 12;
- } else if (currentHour == 0) {
- currentHour = 12;
- }
- }
- mHourSpinner.setValue(currentHour);
- mIsAm = mCurrentHour < 12;
- mAmPmSpinner.setValue(mIsAm ? Calendar.AM : Calendar.PM);
- onTimeChanged();
- }
-
- private void configurePickerRanges() {
- if (mIs24HourView) {
+ private void updateHourControl() {
+ if (is24HourView()) {
mHourSpinner.setMinValue(0);
mHourSpinner.setMaxValue(23);
mHourSpinner.setFormatter(NumberPicker.TWO_DIGIT_FORMATTER);
- mAmPmSpinner.setVisibility(View.GONE);
} else {
mHourSpinner.setMinValue(1);
mHourSpinner.setMaxValue(12);
mHourSpinner.setFormatter(null);
- mAmPmSpinner.setVisibility(View.VISIBLE);
- mAmPmSpinner.setMinValue(0);
- mAmPmSpinner.setMaxValue(1);
- mAmPmSpinner.setDisplayedValues(mAmPmStrings);
+ }
+ }
+
+ private void updateAmPmControl() {
+ if (is24HourView()) {
+ if (mAmPmSpinner != null) {
+ mAmPmSpinner.setVisibility(View.GONE);
+ } else {
+ mAmPmButton.setVisibility(View.GONE);
+ }
+ } else {
+ int index = mIsAm ? Calendar.AM : Calendar.PM;
+ if (mAmPmSpinner != null) {
+ mAmPmSpinner.setValue(index);
+ mAmPmSpinner.setVisibility(View.VISIBLE);
+ } else {
+ mAmPmButton.setText(mAmPmStrings[index]);
+ mAmPmButton.setVisibility(View.VISIBLE);
+ }
}
}
@@ -373,12 +442,4 @@
mOnTimeChangedListener.onTimeChanged(this, getCurrentHour(), getCurrentMinute());
}
}
-
- /**
- * Set the state of the spinners appropriate to the current minute.
- */
- private void updateMinuteDisplay() {
- mMinuteSpinner.setValue(mCurrentMinute);
- onTimeChanged();
- }
}
diff --git a/core/java/android/widget/Toast.java b/core/java/android/widget/Toast.java
index 29ca49a..6a7db1f0 100644
--- a/core/java/android/widget/Toast.java
+++ b/core/java/android/widget/Toast.java
@@ -67,15 +67,9 @@
*/
public static final int LENGTH_LONG = 1;
- final Handler mHandler = new Handler();
final Context mContext;
final TN mTN;
int mDuration;
- int mGravity = Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
- int mX, mY;
- float mHorizontalMargin;
- float mVerticalMargin;
- View mView;
View mNextView;
/**
@@ -88,7 +82,7 @@
public Toast(Context context) {
mContext = context;
mTN = new TN();
- mY = context.getResources().getDimensionPixelSize(
+ mTN.mY = context.getResources().getDimensionPixelSize(
com.android.internal.R.dimen.toast_y_offset);
}
@@ -101,10 +95,9 @@
}
INotificationManager service = getService();
-
String pkg = mContext.getPackageName();
-
TN tn = mTN;
+ tn.mNextView = mNextView;
try {
service.enqueueToast(pkg, tn, mDuration);
@@ -167,22 +160,22 @@
* notification
*/
public void setMargin(float horizontalMargin, float verticalMargin) {
- mHorizontalMargin = horizontalMargin;
- mVerticalMargin = verticalMargin;
+ mTN.mHorizontalMargin = horizontalMargin;
+ mTN.mVerticalMargin = verticalMargin;
}
/**
* Return the horizontal margin.
*/
public float getHorizontalMargin() {
- return mHorizontalMargin;
+ return mTN.mHorizontalMargin;
}
/**
* Return the vertical margin.
*/
public float getVerticalMargin() {
- return mVerticalMargin;
+ return mTN.mVerticalMargin;
}
/**
@@ -191,9 +184,9 @@
* @see #getGravity
*/
public void setGravity(int gravity, int xOffset, int yOffset) {
- mGravity = gravity;
- mX = xOffset;
- mY = yOffset;
+ mTN.mGravity = gravity;
+ mTN.mX = xOffset;
+ mTN.mY = yOffset;
}
/**
@@ -202,21 +195,21 @@
* @see #getGravity
*/
public int getGravity() {
- return mGravity;
+ return mTN.mGravity;
}
/**
* Return the X offset in pixels to apply to the gravity's location.
*/
public int getXOffset() {
- return mX;
+ return mTN.mX;
}
/**
* Return the Y offset in pixels to apply to the gravity's location.
*/
public int getYOffset() {
- return mY;
+ return mTN.mY;
}
/**
@@ -283,21 +276,6 @@
tv.setText(s);
}
- private void trySendAccessibilityEvent() {
- AccessibilityManager accessibilityManager = AccessibilityManager.getInstance(mContext);
- if (!accessibilityManager.isEnabled()) {
- return;
- }
- // treat toasts as notifications since they are used to
- // announce a transient piece of information to the user
- AccessibilityEvent event = AccessibilityEvent.obtain(
- AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED);
- event.setClassName(getClass().getName());
- event.setPackageName(mContext.getPackageName());
- mView.dispatchPopulateAccessibilityEvent(event);
- accessibilityManager.sendAccessibilityEvent(event);
- }
-
// =======================================================================================
// All the gunk below is the interaction with the Notification Service, which handles
// the proper ordering of these system-wide.
@@ -313,7 +291,7 @@
return sService;
}
- private class TN extends ITransientNotification.Stub {
+ private static class TN extends ITransientNotification.Stub {
final Runnable mShow = new Runnable() {
public void run() {
handleShow();
@@ -327,6 +305,16 @@
};
private final WindowManager.LayoutParams mParams = new WindowManager.LayoutParams();
+ final Handler mHandler = new Handler();
+
+ int mGravity = Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
+ int mX, mY;
+ float mHorizontalMargin;
+ float mVerticalMargin;
+
+
+ View mView;
+ View mNextView;
WindowManagerImpl mWM;
@@ -382,8 +370,7 @@
mParams.verticalMargin = mVerticalMargin;
mParams.horizontalMargin = mHorizontalMargin;
if (mView.getParent() != null) {
- if (localLOGV) Log.v(
- TAG, "REMOVE! " + mView + " in " + this);
+ if (localLOGV) Log.v(TAG, "REMOVE! " + mView + " in " + this);
mWM.removeView(mView);
}
if (localLOGV) Log.v(TAG, "ADD! " + mView + " in " + this);
@@ -392,6 +379,22 @@
}
}
+ private void trySendAccessibilityEvent() {
+ AccessibilityManager accessibilityManager =
+ AccessibilityManager.getInstance(mView.getContext());
+ if (!accessibilityManager.isEnabled()) {
+ return;
+ }
+ // treat toasts as notifications since they are used to
+ // announce a transient piece of information to the user
+ AccessibilityEvent event = AccessibilityEvent.obtain(
+ AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED);
+ event.setClassName(getClass().getName());
+ event.setPackageName(mView.getContext().getPackageName());
+ mView.dispatchPopulateAccessibilityEvent(event);
+ accessibilityManager.sendAccessibilityEvent(event);
+ }
+
public void handleHide() {
if (localLOGV) Log.v(TAG, "HANDLE HIDE: " + this + " mView=" + mView);
if (mView != null) {
@@ -399,12 +402,12 @@
// been added... i have seen cases where we get here when
// the view isn't yet added, so let's try not to crash.
if (mView.getParent() != null) {
- if (localLOGV) Log.v(
- TAG, "REMOVE! " + mView + " in " + this);
+ if (localLOGV) Log.v(TAG, "REMOVE! " + mView + " in " + this);
mWM.removeView(mView);
}
mView = null;
+ mNextView = null;
}
}
}
diff --git a/core/java/com/android/internal/app/ActionBarImpl.java b/core/java/com/android/internal/app/ActionBarImpl.java
index 0e31fef..a8eb6fe 100644
--- a/core/java/com/android/internal/app/ActionBarImpl.java
+++ b/core/java/com/android/internal/app/ActionBarImpl.java
@@ -388,6 +388,7 @@
mActionMode.finish();
}
+ mUpperContextView.killMode();
ActionMode mode = new ActionModeImpl(callback);
if (callback.onCreateActionMode(mode, mode.getMenu())) {
mode.invalidate();
diff --git a/core/java/com/android/internal/app/AlertController.java b/core/java/com/android/internal/app/AlertController.java
index a139d31..71a7a52 100644
--- a/core/java/com/android/internal/app/AlertController.java
+++ b/core/java/com/android/internal/app/AlertController.java
@@ -391,6 +391,7 @@
View buttonPanel = mWindow.findViewById(R.id.buttonPanel);
if (!hasButtons) {
buttonPanel.setVisibility(View.GONE);
+ mWindow.setCloseOnTouchOutsideIfNotSet(true);
}
FrameLayout customPanel = null;
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 9ed4dd8..38ac37d 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -17,7 +17,6 @@
package com.android.internal.app;
import android.content.Intent;
-import android.content.pm.ResolveInfo;
import android.os.Bundle;
import android.os.Parcelable;
import android.util.Log;
diff --git a/core/java/com/android/internal/app/PlatLogoActivity.java b/core/java/com/android/internal/app/PlatLogoActivity.java
index e1c5564..9fbbb3d 100644
--- a/core/java/com/android/internal/app/PlatLogoActivity.java
+++ b/core/java/com/android/internal/app/PlatLogoActivity.java
@@ -29,11 +29,11 @@
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- mToast = Toast.makeText(this, "Zombie art by Jack Larson", Toast.LENGTH_SHORT);
+ mToast = Toast.makeText(this, "REZZZZZZZ...", Toast.LENGTH_SHORT);
ImageView content = new ImageView(this);
content.setImageResource(com.android.internal.R.drawable.platlogo);
- content.setScaleType(ImageView.ScaleType.FIT_CENTER);
+ content.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
setContentView(content);
}
diff --git a/core/java/com/android/internal/appwidget/IAppWidgetService.aidl b/core/java/com/android/internal/appwidget/IAppWidgetService.aidl
index 4d56745..fa0873d 100644
--- a/core/java/com/android/internal/appwidget/IAppWidgetService.aidl
+++ b/core/java/com/android/internal/appwidget/IAppWidgetService.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 The Android Open Source Project
+ * Copyright (C) 2011 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,8 +17,10 @@
package com.android.internal.appwidget;
import android.content.ComponentName;
+import android.content.Intent;
import android.appwidget.AppWidgetProviderInfo;
import com.android.internal.appwidget.IAppWidgetHost;
+import android.os.IBinder;
import android.widget.RemoteViews;
/** {@hide} */
@@ -46,6 +48,8 @@
List<AppWidgetProviderInfo> getInstalledProviders();
AppWidgetProviderInfo getAppWidgetInfo(int appWidgetId);
void bindAppWidgetId(int appWidgetId, in ComponentName provider);
+ void bindRemoteViewsService(int appWidgetId, in Intent intent, in IBinder connection);
+ void unbindRemoteViewsService(int appWidgetId, in Intent intent);
int[] getAppWidgetIds(in ComponentName provider);
}
diff --git a/core/java/com/android/internal/widget/ActionBarContextView.java b/core/java/com/android/internal/widget/ActionBarContextView.java
index 31e7bab..bb0c752 100644
--- a/core/java/com/android/internal/widget/ActionBarContextView.java
+++ b/core/java/com/android/internal/widget/ActionBarContextView.java
@@ -160,10 +160,6 @@
}
public void initForMode(final ActionMode mode) {
- if (mAnimationMode != ANIMATE_IDLE || mAnimateInOnLayout) {
- killMode();
- }
-
if (mClose == null) {
LayoutInflater inflater = LayoutInflater.from(mContext);
mClose = inflater.inflate(R.layout.action_mode_close_item, this, false);
@@ -198,15 +194,15 @@
return;
}
- mAnimationMode = ANIMATE_OUT;
finishAnimation();
+ mAnimationMode = ANIMATE_OUT;
mCurrentAnimation = makeOutAnimation();
mCurrentAnimation.start();
}
private void finishAnimation() {
final Animator a = mCurrentAnimation;
- if (a != null && a.isRunning()) {
+ if (a != null) {
mCurrentAnimation = null;
a.end();
}
@@ -448,7 +444,7 @@
@Override
public void onAnimationEnd(Animator animation) {
- if (mAnimationMode != ANIMATE_IN) {
+ if (mAnimationMode == ANIMATE_OUT) {
killMode();
}
mAnimationMode = ANIMATE_IDLE;
diff --git a/core/java/com/android/internal/widget/IRemoteViewsAdapterConnection.aidl b/core/java/com/android/internal/widget/IRemoteViewsAdapterConnection.aidl
new file mode 100644
index 0000000..7eb2aef
--- /dev/null
+++ b/core/java/com/android/internal/widget/IRemoteViewsAdapterConnection.aidl
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.widget;
+
+import android.os.IBinder;
+
+/** {@hide} */
+interface IRemoteViewsAdapterConnection {
+ void onServiceConnected(IBinder service);
+ void onServiceDisconnected();
+}
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index f023e94..342b884 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -568,6 +568,7 @@
char jniOptsBuf[sizeof("-Xjniopts:")-1 + PROPERTY_VALUE_MAX];
char heapstartsizeOptsBuf[sizeof("-Xms")-1 + PROPERTY_VALUE_MAX];
char heapsizeOptsBuf[sizeof("-Xmx")-1 + PROPERTY_VALUE_MAX];
+ char heapgrowthlimitOptsBuf[sizeof("-XX:HeapGrowthLimit=")-1 + PROPERTY_VALUE_MAX];
char extraOptsBuf[PROPERTY_VALUE_MAX];
char* stackTraceFile = NULL;
bool checkJni = false;
@@ -659,6 +660,13 @@
opt.optionString = heapsizeOptsBuf;
mOptions.add(opt);
+ strcpy(heapgrowthlimitOptsBuf, "-XX:HeapGrowthLimit=");
+ property_get("dalvik.vm.heapgrowthlimit", heapgrowthlimitOptsBuf+20, "");
+ if (heapgrowthlimitOptsBuf[20] != '\0') {
+ opt.optionString = heapgrowthlimitOptsBuf;
+ mOptions.add(opt);
+ }
+
/*
* Enable or disable dexopt features, such as bytecode verification and
* calculation of register maps for precise GC.
diff --git a/core/jni/android/graphics/Region.cpp b/core/jni/android/graphics/Region.cpp
index c43b5ce..2445229 100644
--- a/core/jni/android/graphics/Region.cpp
+++ b/core/jni/android/graphics/Region.cpp
@@ -154,6 +154,16 @@
scale_rgn(rgn, *rgn, scale);
}
+static jstring Region_toString(JNIEnv* env, jobject clazz, SkRegion* region) {
+ char* str = region->toString();
+ if (str == NULL) {
+ return NULL;
+ }
+ jstring result = env->NewStringUTF(str);
+ free(str);
+ return result;
+}
+
////////////////////////////////////////////////////////////////////////////////////////////////////////////
static SkRegion* Region_createFromParcel(JNIEnv* env, jobject clazz, jobject parcel)
@@ -262,6 +272,7 @@
{ "quickReject", "(Landroid/graphics/Region;)Z", (void*)Region_quickRejectRgn },
{ "scale", "(FLandroid/graphics/Region;)V", (void*)Region_scale },
{ "translate", "(IILandroid/graphics/Region;)V", (void*)Region_translate },
+ { "nativeToString", "(I)Ljava/lang/String;", (void*)Region_toString },
// parceling methods
{ "nativeCreateFromParcel", "(Landroid/os/Parcel;)I", (void*)Region_createFromParcel },
{ "nativeWriteToParcel", "(ILandroid/os/Parcel;)Z", (void*)Region_writeToParcel },
diff --git a/core/jni/android_bluetooth_common.h b/core/jni/android_bluetooth_common.h
index 9222e1a..3364703 100644
--- a/core/jni/android_bluetooth_common.h
+++ b/core/jni/android_bluetooth_common.h
@@ -38,6 +38,7 @@
#ifdef HAVE_BLUETOOTH
#define BLUEZ_DBUS_BASE_PATH "/org/bluez"
#define BLUEZ_DBUS_BASE_IFC "org.bluez"
+#define BLUEZ_ERROR_IFC "org.bluez.Error"
// It would be nicer to retrieve this from bluez using GetDefaultAdapter,
// but this is only possible when the adapter is up (and hcid is running).
@@ -171,6 +172,30 @@
bool debug_no_encrypt();
+
+// Result codes from Bluez DBus calls
+#define BOND_RESULT_ERROR -1
+#define BOND_RESULT_SUCCESS 0
+#define BOND_RESULT_AUTH_FAILED 1
+#define BOND_RESULT_AUTH_REJECTED 2
+#define BOND_RESULT_AUTH_CANCELED 3
+#define BOND_RESULT_REMOTE_DEVICE_DOWN 4
+#define BOND_RESULT_DISCOVERY_IN_PROGRESS 5
+#define BOND_RESULT_AUTH_TIMEOUT 6
+#define BOND_RESULT_REPEATED_ATTEMPTS 7
+
+#define PAN_DISCONNECT_FAILED_NOT_CONNECTED 1000
+#define PAN_CONNECT_FAILED_ALREADY_CONNECTED 1001
+#define PAN_CONNECT_FAILED_ATTEMPT_FAILED 1002
+#define PAN_OPERATION_GENERIC_FAILURE 1003
+#define PAN_OPERATION_SUCCESS 1004
+
+#define INPUT_DISCONNECT_FAILED_NOT_CONNECTED 5000
+#define INPUT_CONNECT_FAILED_ALREADY_CONNECTED 5001
+#define INPUT_CONNECT_FAILED_ATTEMPT_FAILED 5002
+#define INPUT_OPERATION_GENERIC_FAILURE 5003
+#define INPUT_OPERATION_SUCCESS 5004
+
#endif
} /* namespace android */
diff --git a/core/jni/android_server_BluetoothEventLoop.cpp b/core/jni/android_server_BluetoothEventLoop.cpp
index b0ba695..fd12c2d7 100644
--- a/core/jni/android_server_BluetoothEventLoop.cpp
+++ b/core/jni/android_server_BluetoothEventLoop.cpp
@@ -134,11 +134,11 @@
method_onInputDevicePropertyChanged = env->GetMethodID(clazz, "onInputDevicePropertyChanged",
"(Ljava/lang/String;[Ljava/lang/String;)V");
method_onInputDeviceConnectionResult = env->GetMethodID(clazz, "onInputDeviceConnectionResult",
- "(Ljava/lang/String;Z)V");
+ "(Ljava/lang/String;I)V");
method_onPanDevicePropertyChanged = env->GetMethodID(clazz, "onPanDevicePropertyChanged",
"(Ljava/lang/String;[Ljava/lang/String;)V");
method_onPanDeviceConnectionResult = env->GetMethodID(clazz, "onPanDeviceConnectionResult",
- "(Ljava/lang/String;Z)V");
+ "(Ljava/lang/String;I)V");
method_onRequestOobData = env->GetMethodID(clazz, "onRequestOobData",
"(Ljava/lang/String;I)V");
@@ -1227,16 +1227,6 @@
#ifdef HAVE_BLUETOOTH
-//TODO: Unify result codes in a header
-#define BOND_RESULT_ERROR -1000
-#define BOND_RESULT_SUCCESS 0
-#define BOND_RESULT_AUTH_FAILED 1
-#define BOND_RESULT_AUTH_REJECTED 2
-#define BOND_RESULT_AUTH_CANCELED 3
-#define BOND_RESULT_REMOTE_DEVICE_DOWN 4
-#define BOND_RESULT_DISCOVERY_IN_PROGRESS 5
-#define BOND_RESULT_AUTH_TIMEOUT 6
-#define BOND_RESULT_REPEATED_ATTEMPTS 7
void onCreatePairedDeviceResult(DBusMessage *msg, void *user, void *n) {
LOGV(__FUNCTION__);
@@ -1406,11 +1396,25 @@
JNIEnv *env;
nat->vm->GetEnv((void**)&env, nat->envVer);
- bool result = JNI_TRUE;
+ jint result = INPUT_OPERATION_SUCCESS;
if (dbus_set_error_from_message(&err, msg)) {
+ if (!strcmp(err.name, BLUEZ_ERROR_IFC ".ConnectionAttemptFailed")) {
+ result = INPUT_CONNECT_FAILED_ATTEMPT_FAILED;
+ } else if (!strcmp(err.name, BLUEZ_ERROR_IFC ".AlreadyConnected")) {
+ result = INPUT_CONNECT_FAILED_ALREADY_CONNECTED;
+ } else if (!strcmp(err.name, BLUEZ_ERROR_IFC ".Failed")) {
+ // TODO():This is flaky, need to change Bluez to add new error codes
+ if (!strcmp(err.message, "Transport endpoint is not connected")) {
+ result = INPUT_DISCONNECT_FAILED_NOT_CONNECTED;
+ } else {
+ result = INPUT_OPERATION_GENERIC_FAILURE;
+ }
+ } else {
+ result = INPUT_OPERATION_GENERIC_FAILURE;
+ }
LOG_AND_FREE_DBUS_ERROR(&err);
- result = JNI_FALSE;
}
+
LOGV("... Device Path = %s, result = %d", path, result);
jstring jPath = env->NewStringUTF(path);
env->CallVoidMethod(nat->me,
@@ -1431,11 +1435,25 @@
JNIEnv *env;
nat->vm->GetEnv((void**)&env, nat->envVer);
- bool result = JNI_TRUE;
+ jint result = PAN_OPERATION_SUCCESS;
if (dbus_set_error_from_message(&err, msg)) {
+ if (!strcmp(err.name, BLUEZ_ERROR_IFC ".ConnectionAttemptFailed")) {
+ result = PAN_CONNECT_FAILED_ATTEMPT_FAILED;
+ } else if (!strcmp(err.name, BLUEZ_ERROR_IFC ".Failed")) {
+ // TODO():This is flaky, need to change Bluez to add new error codes
+ if (!strcmp(err.message, "Device already connected")) {
+ result = PAN_CONNECT_FAILED_ALREADY_CONNECTED;
+ } else if (!strcmp(err.message, "Device not connected")) {
+ result = PAN_DISCONNECT_FAILED_NOT_CONNECTED;
+ } else {
+ result = PAN_OPERATION_GENERIC_FAILURE;
+ }
+ } else {
+ result = PAN_OPERATION_GENERIC_FAILURE;
+ }
LOG_AND_FREE_DBUS_ERROR(&err);
- result = JNI_FALSE;
}
+
LOGV("... Pan Device Path = %s, result = %d", path, result);
jstring jPath = env->NewStringUTF(path);
env->CallVoidMethod(nat->me,
diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp
index 8c30987..e4af33f 100644
--- a/core/jni/android_view_Surface.cpp
+++ b/core/jni/android_view_Surface.cpp
@@ -61,6 +61,7 @@
struct so_t {
jfieldID surfaceControl;
+ jfieldID surfaceGenerationId;
jfieldID surface;
jfieldID saveCount;
jfieldID canvas;
@@ -189,6 +190,12 @@
p->decStrong(clazz);
}
env->SetIntField(clazz, so.surface, (int)surface.get());
+ // This test is conservative and it would be better to compare the ISurfaces
+ if (p && p != surface.get()) {
+ jint generationId = env->GetIntField(clazz, so.surfaceGenerationId);
+ generationId++;
+ env->SetIntField(clazz, so.surfaceGenerationId, generationId);
+ }
}
// ----------------------------------------------------------------------------
@@ -785,6 +792,7 @@
void nativeClassInit(JNIEnv* env, jclass clazz)
{
so.surface = env->GetFieldID(clazz, ANDROID_VIEW_SURFACE_JNI_ID, "I");
+ so.surfaceGenerationId = env->GetFieldID(clazz, "mSurfaceGenerationId", "I");
so.surfaceControl = env->GetFieldID(clazz, "mSurfaceControl", "I");
so.saveCount = env->GetFieldID(clazz, "mSaveCount", "I");
so.canvas = env->GetFieldID(clazz, "mCanvas", "Landroid/graphics/Canvas;");
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 41c911a..9b890fa 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1210,6 +1210,13 @@
android:description="@string/permdesc_backup"
android:protectionLevel="signatureOrSystem" />
+ <!-- Must be required by a {@link android.widget.RemoteViewsService},
+ to ensure that only the system can bind to it. -->
+ <permission android:name="android.permission.BIND_REMOTEVIEWS"
+ android:label="@string/permlab_bindRemoteViews"
+ android:description="@string/permdesc_bindRemoteViews"
+ android:protectionLevel="signatureOrSystem" />
+
<!-- Allows an application to tell the AppWidget service which application
can access AppWidget's data. The normal user flow is that a user
picks an AppWidget to go into a particular host, thereby giving that
diff --git a/core/res/res/drawable-hdpi/ic_menu_moreoverflow_focused_holo_dark.png b/core/res/res/drawable-hdpi/ic_menu_moreoverflow_focused_holo_dark.png
deleted file mode 100644
index 3ecaa9d..0000000
--- a/core/res/res/drawable-hdpi/ic_menu_moreoverflow_focused_holo_dark.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_moreoverflow_focused_holo_light.png b/core/res/res/drawable-hdpi/ic_menu_moreoverflow_focused_holo_light.png
deleted file mode 100644
index 40009af..0000000
--- a/core/res/res/drawable-hdpi/ic_menu_moreoverflow_focused_holo_light.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_menu_moreoverflow_focused_holo_dark.png b/core/res/res/drawable-mdpi/ic_menu_moreoverflow_focused_holo_dark.png
deleted file mode 100644
index c369e6f..0000000
--- a/core/res/res/drawable-mdpi/ic_menu_moreoverflow_focused_holo_dark.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_menu_moreoverflow_focused_holo_light.png b/core/res/res/drawable-mdpi/ic_menu_moreoverflow_focused_holo_light.png
deleted file mode 100644
index a4df2bf..0000000
--- a/core/res/res/drawable-mdpi/ic_menu_moreoverflow_focused_holo_light.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-nodpi/platlogo.png b/core/res/res/drawable-nodpi/platlogo.png
index e5af356..67e6ac3 100644
--- a/core/res/res/drawable-nodpi/platlogo.png
+++ b/core/res/res/drawable-nodpi/platlogo.png
Binary files differ
diff --git a/core/res/res/drawable/ic_menu_moreoverflow_holo_dark.xml b/core/res/res/drawable/ic_menu_moreoverflow_holo_dark.xml
index 4691edf..f2b846a 100644
--- a/core/res/res/drawable/ic_menu_moreoverflow_holo_dark.xml
+++ b/core/res/res/drawable/ic_menu_moreoverflow_holo_dark.xml
@@ -14,6 +14,5 @@
limitations under the License.
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_focused="true" android:drawable="@drawable/ic_menu_moreoverflow_focused_holo_dark" />
<item android:drawable="@drawable/ic_menu_moreoverflow_normal_holo_dark" />
</selector>
diff --git a/core/res/res/drawable/ic_menu_moreoverflow_holo_light.xml b/core/res/res/drawable/ic_menu_moreoverflow_holo_light.xml
index 5c52ff4..34afa71 100644
--- a/core/res/res/drawable/ic_menu_moreoverflow_holo_light.xml
+++ b/core/res/res/drawable/ic_menu_moreoverflow_holo_light.xml
@@ -14,6 +14,5 @@
limitations under the License.
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_focused="true" android:drawable="@drawable/ic_menu_moreoverflow_focused_holo_light" />
<item android:drawable="@drawable/ic_menu_moreoverflow_normal_holo_light" />
</selector>
diff --git a/core/res/res/layout-xlarge/keyguard_screen_glogin_unlock.xml b/core/res/res/layout-xlarge/keyguard_screen_glogin_unlock.xml
index 4f5beff..9779074 100644
--- a/core/res/res/layout-xlarge/keyguard_screen_glogin_unlock.xml
+++ b/core/res/res/layout-xlarge/keyguard_screen_glogin_unlock.xml
@@ -100,6 +100,16 @@
android:text="@android:string/lockscreen_glogin_submit_button"
/>
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/ok"
+ android:layout_marginTop="50dip"
+ android:text="@android:string/lockscreen_glogin_account_recovery_hint"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:gravity="center_horizontal"
+ />
+
</RelativeLayout>
</ScrollView>
diff --git a/core/res/res/layout/date_picker.xml b/core/res/res/layout/date_picker.xml
index e9663b1..1649466 100644
--- a/core/res/res/layout/date_picker.xml
+++ b/core/res/res/layout/date_picker.xml
@@ -40,10 +40,10 @@
<!-- Month -->
<NumberPicker
android:id="@+id/month"
- android:layout_width="48dip"
+ android:layout_width="80dip"
android:layout_height="wrap_content"
- android:layout_marginLeft="22dip"
- android:layout_marginRight="22dip"
+ android:layout_marginLeft="1dip"
+ android:layout_marginRight="1dip"
android:focusable="true"
android:focusableInTouchMode="true"
/>
@@ -51,10 +51,10 @@
<!-- Day -->
<NumberPicker
android:id="@+id/day"
- android:layout_width="48dip"
+ android:layout_width="80dip"
android:layout_height="wrap_content"
- android:layout_marginLeft="22dip"
- android:layout_marginRight="22dip"
+ android:layout_marginLeft="1dip"
+ android:layout_marginRight="1dip"
android:focusable="true"
android:focusableInTouchMode="true"
/>
@@ -62,10 +62,10 @@
<!-- Year -->
<NumberPicker
android:id="@+id/year"
- android:layout_width="48dip"
+ android:layout_width="95dip"
android:layout_height="wrap_content"
- android:layout_marginLeft="22dip"
- android:layout_marginRight="22dip"
+ android:layout_marginLeft="1dip"
+ android:layout_marginRight="1dip"
android:focusable="true"
android:focusableInTouchMode="true"
/>
@@ -81,6 +81,7 @@
android:layout_weight="1"
android:focusable="true"
android:focusableInTouchMode="true"
+ android:visibility="gone"
/>
</LinearLayout>
diff --git a/core/res/res/layout/date_picker_holo.xml b/core/res/res/layout/date_picker_holo.xml
new file mode 100644
index 0000000..026cbfb
--- /dev/null
+++ b/core/res/res/layout/date_picker_holo.xml
@@ -0,0 +1,86 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 2011, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- Layout of date picker-->
+
+<!-- Warning: everything within the "pickers" layout is removed and re-ordered
+ depending on the date format selected by the user.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:layout_gravity="center_horizontal"
+ android:orientation="horizontal"
+ android:gravity="center">
+
+ <LinearLayout android:id="@+id/pickers"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginRight="22dip"
+ android:layout_weight="1"
+ android:orientation="horizontal"
+ android:gravity="center">
+
+ <!-- Month -->
+ <NumberPicker
+ android:id="@+id/month"
+ android:layout_width="48dip"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="22dip"
+ android:layout_marginRight="22dip"
+ android:focusable="true"
+ android:focusableInTouchMode="true"
+ />
+
+ <!-- Day -->
+ <NumberPicker
+ android:id="@+id/day"
+ android:layout_width="48dip"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="22dip"
+ android:layout_marginRight="22dip"
+ android:focusable="true"
+ android:focusableInTouchMode="true"
+ />
+
+ <!-- Year -->
+ <NumberPicker
+ android:id="@+id/year"
+ android:layout_width="48dip"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="22dip"
+ android:layout_marginRight="22dip"
+ android:focusable="true"
+ android:focusableInTouchMode="true"
+ />
+
+ </LinearLayout>
+
+ <!-- calendar view -->
+ <CalendarView
+ android:id="@+id/calendar_view"
+ android:layout_width="245dip"
+ android:layout_height="280dip"
+ android:layout_marginLeft="22dip"
+ android:layout_weight="1"
+ android:focusable="true"
+ android:focusableInTouchMode="true"
+ />
+
+</LinearLayout>
diff --git a/core/res/res/layout/time_picker.xml b/core/res/res/layout/time_picker.xml
index 382b2f6..df46db4 100644
--- a/core/res/res/layout/time_picker.xml
+++ b/core/res/res/layout/time_picker.xml
@@ -28,42 +28,33 @@
<!-- hour -->
<NumberPicker
android:id="@+id/hour"
- android:layout_width="48dip"
+ android:layout_width="70dip"
android:layout_height="wrap_content"
- android:layout_marginLeft="22dip"
- android:layout_marginRight="20dip"
android:focusable="true"
android:focusableInTouchMode="true"
/>
- <!-- divider -->
- <TextView
- android:id="@+id/divider"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center_vertical"
- />
-
<!-- minute -->
<NumberPicker
android:id="@+id/minute"
- android:layout_width="48dip"
+ android:layout_width="70dip"
android:layout_height="wrap_content"
- android:layout_marginLeft="20dip"
- android:layout_marginRight="22dip"
+ android:layout_marginLeft="5dip"
android:focusable="true"
android:focusableInTouchMode="true"
/>
<!-- AM / PM -->
- <NumberPicker
+ <Button
android:id="@+id/amPm"
- android:layout_width="48dip"
+ android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginLeft="22dip"
- android:layout_marginRight="22dip"
- android:focusable="true"
- android:focusableInTouchMode="true"
+ android:layout_marginTop="43dip"
+ android:layout_marginLeft="5dip"
+ android:paddingLeft="20dip"
+ android:paddingRight="20dip"
+ style="?android:attr/textAppearanceLargeInverse"
+ android:textColor="@android:color/primary_text_light_nodisable"
/>
</LinearLayout>
diff --git a/core/res/res/layout/time_picker_holo.xml b/core/res/res/layout/time_picker_holo.xml
new file mode 100644
index 0000000..ca6fe2d
--- /dev/null
+++ b/core/res/res/layout/time_picker_holo.xml
@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 2011, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- Layout of time picker -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="horizontal"
+ android:layout_gravity="center_horizontal"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content">
+
+ <!-- hour -->
+ <NumberPicker
+ android:id="@+id/hour"
+ android:layout_width="48dip"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="22dip"
+ android:layout_marginRight="20dip"
+ android:focusable="true"
+ android:focusableInTouchMode="true"
+ />
+
+ <!-- divider -->
+ <TextView
+ android:id="@+id/divider"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ />
+
+ <!-- minute -->
+ <NumberPicker
+ android:id="@+id/minute"
+ android:layout_width="48dip"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="20dip"
+ android:layout_marginRight="22dip"
+ android:focusable="true"
+ android:focusableInTouchMode="true"
+ />
+
+ <!-- AM / PM -->
+ <NumberPicker
+ android:id="@+id/amPm"
+ android:layout_width="48dip"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="22dip"
+ android:layout_marginRight="22dip"
+ android:focusable="true"
+ android:focusableInTouchMode="true"
+ />
+
+</LinearLayout>
diff --git a/core/res/res/values-large/config.xml b/core/res/res/values-large/config.xml
index 4449fd0..05dd050 100644
--- a/core/res/res/values-large/config.xml
+++ b/core/res/res/values-large/config.xml
@@ -22,6 +22,4 @@
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- see comment in values/config.xml -->
<dimen name="config_prefDialogWidth">440dp</dimen>
- <!-- see comment in values/config.xml -->
- <bool name="config_closeDialogWhenTouchOutside">true</bool>
</resources>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index de233c8..457baa6 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -534,6 +534,12 @@
<!-- The CalndarView style. -->
<attr name="calendarViewStyle" format="reference" />
+ <!-- The TimePicker style. -->
+ <attr name="timePickerStyle" format="reference" />
+
+ <!-- The DatePicker style. -->
+ <attr name="datePickerStyle" format="reference" />
+
<!-- Fast scroller styles -->
<eat-comment />
@@ -2869,6 +2875,7 @@
<!-- Gravity setting for positioning the currently selected item. -->
<attr name="gravity" />
</declare-styleable>
+
<declare-styleable name="DatePicker">
<!-- The first year (inclusive), for example "1940". -->
<attr name="startYear" format="integer" />
@@ -2882,6 +2889,8 @@
<attr name="minDate" format="string" />
<!-- The minimal date shown by this calendar view in mm/dd/yyyy format. -->
<attr name="maxDate" format="string" />
+ <!-- @hide The layout of the time picker. -->
+ <attr name="layout" />
</declare-styleable>
<declare-styleable name="TwoLineListItem">
@@ -3080,9 +3089,20 @@
</declare-styleable>
<declare-styleable name="NumberPicker">
- <attr name="orientation" />
- <!-- Color for the solid color background if such for optimized rendering. -->
+ <!-- @hide Color for the solid color background if such for optimized rendering. -->
<attr name="solidColor" format="color|reference" />
+ <!-- @hide Whether the number picker supports fligning. -->
+ <attr name="flingable" format="boolean" />
+ </declare-styleable>
+
+ <declare-styleable name="TimePicker">
+ <!-- @hide The layout of the time picker. -->
+ <attr name="layout" />
+ </declare-styleable>
+
+ <declare-styleable name="DatePicker">
+ <!-- @hide The layout of the time picker. -->
+ <attr name="layout" />
</declare-styleable>
<!-- ========================= -->
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 552c2f7..e0c26d4 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -82,8 +82,7 @@
<dimen name="config_prefDialogWidth">0px</dimen>
<!-- Whether dialogs should close automatically when the user touches outside
- of them. This should not normally be modified; the default value will
- pick the correct behavior depending on the screen size. -->
+ of them. This should not normally be modified. -->
<bool name="config_closeDialogWhenTouchOutside">false</bool>
<!-- The duration (in milliseconds) that the radio will scan for a signal
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 1b47b54..a30e316 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1426,6 +1426,8 @@
<public type="attr" name="fastScrollTextColor" />
<public type="attr" name="largeHeap" />
<public type="attr" name="windowCloseOnTouchOutside" />
+ <public type="attr" name="datePickerStyle" />
+ <public type="attr" name="calendarViewStyle" />
<!-- A simple fade-in animation. -->
<public type="animator" name="fade_in" id="0x010b0000" />
@@ -1627,21 +1629,15 @@
<public type="style" name="Holo.Light.ButtonBar.AlertDialog" />
<public type="style" name="Holo.SegmentedButton" />
<public type="style" name="Holo.Light.SegmentedButton" />
- <public type="style" name="Widget.ImageButton.NumberPickerUpButton" />
- <public type="style" name="Widget.EditText.NumberPickerInputText" />
- <public type="style" name="Widget.ImageButton.NumberPickerDownButton" />
- <public type="style" name="Widget.Holo.ImageButton.NumberPickerUpButton" />
- <public type="style" name="Widget.Holo.EditText.NumberPickerInputText" />
- <public type="style" name="Widget.Holo.ImageButton.NumberPickerDownButton" />
- <public type="style" name="Widget.Holo.Light.ImageButton.NumberPickerUpButton" />
- <public type="style" name="Widget.Holo.Light.EditText.NumberPickerInputText" />
- <public type="style" name="Widget.Holo.Light.ImageButton.NumberPickerDownButton" />
<public type="style" name="Widget.CalendarView" />
<public type="style" name="Widget.Holo.CalendarView" />
<public type="style" name="Widget.Holo.Light.CalendarView" />
+ <public type="style" name="Widget.DatePicker" />
+ <public type="style" name="Widget.Holo.DatePicker" />
<public type="string" name="selectTextMode" />
<!-- Default icon for applications that don't specify an icon. -->
<public type="mipmap" name="sym_def_app_icon" id="0x010d0000" />
+
</resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 2658b53..9a1b42d 100755
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -681,6 +681,12 @@
interface of a wallpaper. Should never be needed for normal applications.</string>
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permlab_bindRemoteViews">bind to a widget service</string>
+ <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permdesc_bindRemoteViews">Allows the holder to bind to the top-level
+ interface of a widget service. Should never be needed for normal applications.</string>
+
+ <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permlab_bindDeviceAdmin">interact with a device admin</string>
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permdesc_bindDeviceAdmin">Allows the holder to send intents to
@@ -1784,6 +1790,8 @@
<string name="lockscreen_glogin_submit_button">Sign in</string>
<!-- Displayed to the user when unlocking the phone with a username and password fails. -->
<string name="lockscreen_glogin_invalid_input">Invalid username or password.</string>
+ <!-- Hint displayed on account unlock screen to advise the user on how to recover the account. -->
+ <string name="lockscreen_glogin_account_recovery_hint">Forgot your username or password\?\nVisit <b>google.com/accounts/recovery</b></string>
<!-- Displayed in a progress dialog while a username and password are being checked. -->
<string name="lockscreen_glogin_checking_password">Checking...</string>
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index 16c80d0..b7b43e0 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -489,7 +489,16 @@
<item name="android:orientation">vertical</item>
<item name="android:fadingEdge">vertical</item>
<item name="android:fadingEdgeLength">50dip</item>
- <item name="android:solidColor">@android:color/transparent</item>
+ <item name="android:flingable">false</item>
+ </style>
+
+ <style name="Widget.TimePicker">
+ <item name="android:layout">@android:layout/time_picker</item>
+ </style>
+
+ <style name="Widget.DatePicker">
+ <item name="android:layout">@android:layout/date_picker</item>
+ <item name="android:calendarViewShown">false</item>
</style>
<style name="Widget.ImageButton.NumberPickerUpButton">
@@ -1502,6 +1511,20 @@
<item name="android:background">@android:drawable/btn_default_holo_dark</item>
</style>
+ <style name="Widget.Holo.NumberPicker" parent="Widget.NumberPicker">
+ <item name="android:solidColor">@android:color/transparent</item>
+ <item name="android:flingable">true</item>
+ </style>
+
+ <style name="Widget.Holo.TimePicker" parent="Widget.TimePicker">
+ <item name="android:layout">@android:layout/time_picker_holo</item>
+ </style>
+
+ <style name="Widget.Holo.DatePicker" parent="Widget.DatePicker">
+ <item name="android:layout">@android:layout/date_picker_holo</item>
+ <item name="android:calendarViewShown">true</item>
+ </style>
+
<style name="Widget.Holo.ImageButton.NumberPickerUpButton">
<item name="android:background">@null</item>
<item name="android:src">@android:drawable/numberpicker_up_btn_holo_dark</item>
@@ -1870,6 +1893,15 @@
<item name="android:weekDayTextAppearance">@android:style/TextAppearance.Holo.Light.CalendarViewWeekDayView</item>
</style>
+ <style name="Widget.Holo.Light.NumberPicker" parent="Widget.Holo.NumberPicker">
+ </style>
+
+ <style name="Widget.Holo.Light.TimePicker" parent="Widget.Holo.TimePicker">
+ </style>
+
+ <style name="Widget.Holo.Light.DatePicker" parent="Widget.Holo.DatePicker">
+ </style>
+
<style name="Widget.Holo.Light.ImageButton.NumberPickerUpButton" parent="Widget.Holo.ImageButton.NumberPickerUpButton">
<item name="android:src">@android:drawable/numberpicker_up_btn_holo_light</item>
</style>
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index b257a73..2f8cffc 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -290,6 +290,12 @@
<!-- CalendarView style-->
<item name="calendarViewStyle">@style/Widget.CalendarView</item>
+ <!-- TimePicker style -->
+ <item name="timePickerStyle">@style/Widget.TimePicker</item>
+
+ <!-- DatePicker style -->
+ <item name="datePickerStyle">@style/Widget.DatePicker</item>
+
<item name="fastScrollThumbDrawable">@android:drawable/scrollbar_handle_accelerated_anim2</item>
<item name="fastScrollTrackDrawable">@null</item>
<item name="fastScrollPreviewBackgroundRight">@android:drawable/menu_submenu_background</item>
@@ -978,10 +984,17 @@
<item name="numberPickerUpButtonStyle">@style/Widget.Holo.ImageButton.NumberPickerUpButton</item>
<item name="numberPickerDownButtonStyle">@style/Widget.Holo.ImageButton.NumberPickerDownButton</item>
<item name="numberPickerInputTextStyle">@style/Widget.Holo.EditText.NumberPickerInputText</item>
+ <item name="numberPickerStyle">@style/Widget.Holo.NumberPicker</item>
<!-- CalendarView style-->
<item name="calendarViewStyle">@style/Widget.Holo.CalendarView</item>
+ <!-- TimePicker style -->
+ <item name="timePickerStyle">@style/Widget.Holo.TimePicker</item>
+
+ <!-- DatePicker style -->
+ <item name="datePickerStyle">@style/Widget.Holo.DatePicker</item>
+
<item name="fastScrollThumbDrawable">@android:drawable/fastscroll_thumb_holo</item>
<item name="fastScrollPreviewBackgroundLeft">@android:drawable/fastscroll_label_left_holo_dark</item>
<item name="fastScrollPreviewBackgroundRight">@android:drawable/fastscroll_label_right_holo_dark</item>
@@ -1003,6 +1016,7 @@
<item name="disabledAlpha">0.5</item>
<item name="backgroundDimAmount">0.6</item>
+
<!-- Text styles -->
<item name="textAppearance">@android:style/TextAppearance.Holo.Light</item>
<item name="textAppearanceInverse">@android:style/TextAppearance.Holo.Light.Inverse</item>
@@ -1236,10 +1250,17 @@
<item name="numberPickerUpButtonStyle">@style/Widget.Holo.Light.ImageButton.NumberPickerUpButton</item>
<item name="numberPickerDownButtonStyle">@style/Widget.Holo.Light.ImageButton.NumberPickerDownButton</item>
<item name="numberPickerInputTextStyle">@style/Widget.Holo.Light.EditText.NumberPickerInputText</item>
+ <item name="numberPickerStyle">@style/Widget.Holo.Light.NumberPicker</item>
<!-- CalendarView style-->
<item name="calendarViewStyle">@style/Widget.Holo.Light.CalendarView</item>
+ <!-- TimePicker style -->
+ <item name="timePickerStyle">@style/Widget.Holo.Light.TimePicker</item>
+
+ <!-- DatePicker style -->
+ <item name="datePickerStyle">@style/Widget.Holo.Light.DatePicker</item>
+
<item name="fastScrollThumbDrawable">@android:drawable/fastscroll_thumb_holo</item>
<item name="fastScrollPreviewBackgroundLeft">@android:drawable/fastscroll_label_left_holo_light</item>
<item name="fastScrollPreviewBackgroundRight">@android:drawable/fastscroll_label_right_holo_light</item>
diff --git a/core/tests/coretests/src/android/bluetooth/BluetoothStressTest.java b/core/tests/coretests/src/android/bluetooth/BluetoothStressTest.java
index 43cf06a3..96b028a 100644
--- a/core/tests/coretests/src/android/bluetooth/BluetoothStressTest.java
+++ b/core/tests/coretests/src/android/bluetooth/BluetoothStressTest.java
@@ -19,6 +19,16 @@
import android.content.Context;
import android.test.InstrumentationTestCase;
+/**
+ * Stress test suite for Bluetooth related functions.
+ *
+ * Includes tests for enabling/disabling bluetooth, enabling/disabling discoverable mode,
+ * starting/stopping scans, connecting/disconnecting to HFP, A2DP, HID, PAN profiles, and verifying
+ * that remote connections/disconnections occur for the PAN profile.
+ * <p>
+ * This test suite uses {@link android.bluetooth.BluetoothTestRunner} to for parameters such as the
+ * number of iterations and the addresses of remote Bluetooth devices.
+ */
public class BluetoothStressTest extends InstrumentationTestCase {
private static final String TAG = "BluetoothStressTest";
private static final String OUTPUT_FILE = "BluetoothStressTestOutput.txt";
@@ -40,6 +50,9 @@
mTestUtils.close();
}
+ /**
+ * Stress test for enabling and disabling Bluetooth.
+ */
public void testEnable() {
int iterations = BluetoothTestRunner.sEnableIterations;
if (iterations == 0) {
@@ -55,6 +68,9 @@
}
}
+ /**
+ * Stress test for putting the device in and taking the device out of discoverable mode.
+ */
public void testDiscoverable() {
int iterations = BluetoothTestRunner.sDiscoverableIterations;
if (iterations == 0) {
@@ -73,6 +89,9 @@
mTestUtils.disable(adapter);
}
+ /**
+ * Stress test for starting and stopping Bluetooth scans.
+ */
public void testScan() {
int iterations = BluetoothTestRunner.sScanIterations;
if (iterations == 0) {
@@ -91,6 +110,30 @@
mTestUtils.disable(adapter);
}
+ /**
+ * Stress test for enabling and disabling the PAN NAP profile.
+ */
+ public void testEnablePan() {
+ int iterations = BluetoothTestRunner.sEnablePanIterations;
+ BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+ mTestUtils.enable(adapter);
+
+ for (int i = 0; i < iterations; i++) {
+ mTestUtils.writeOutput("testEnablePan iteration " + (i + 1) + " of "
+ + iterations);
+ mTestUtils.enablePan(adapter);
+ mTestUtils.disablePan(adapter);
+ }
+
+ mTestUtils.disable(adapter);
+ }
+
+ /**
+ * Stress test for pairing and unpairing with a remote device.
+ * <p>
+ * In this test, the local device initiates pairing with a remote device, and then unpairs with
+ * the device after the pairing has successfully completed.
+ */
public void testPair() {
int iterations = BluetoothTestRunner.sPairIterations;
if (iterations == 0) {
@@ -110,6 +153,12 @@
mTestUtils.disable(adapter);
}
+ /**
+ * Stress test for accepting a pairing request and unpairing with a remote device.
+ * <p>
+ * In this test, the local device waits for a pairing request from a remote device. It accepts
+ * the request and then unpairs after the paring has successfully completed.
+ */
public void testAcceptPair() {
int iterations = BluetoothTestRunner.sPairIterations;
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
@@ -125,6 +174,12 @@
mTestUtils.disable(adapter);
}
+ /**
+ * Stress test for connecting and disconnecting with an A2DP source.
+ * <p>
+ * In this test, the local device plays the role of an A2DP sink, and initiates connections and
+ * disconnections with an A2DP source.
+ */
public void testConnectA2dp() {
int iterations = BluetoothTestRunner.sConnectA2dpIterations;
if (iterations == 0) {
@@ -143,10 +198,16 @@
mTestUtils.disconnectProfile(adapter, device, BluetoothProfile.A2DP);
}
- // TODO: Unpair from device if device can accept pairing after unpairing
+ mTestUtils.unpair(adapter, device);
mTestUtils.disable(adapter);
}
+ /**
+ * Stress test for connecting and disconnecting the HFP with a hands free device.
+ * <p>
+ * In this test, the local device plays the role of an HFP audio gateway, and initiates
+ * connections and disconnections with a hands free device.
+ */
public void testConnectHeadset() {
int iterations = BluetoothTestRunner.sConnectHeadsetIterations;
if (iterations == 0) {
@@ -165,7 +226,94 @@
mTestUtils.disconnectProfile(adapter, device, BluetoothProfile.HEADSET);
}
- // TODO: Unpair from device if device can accept pairing after unpairing
+ mTestUtils.unpair(adapter, device);
+ mTestUtils.disable(adapter);
+ }
+
+ /**
+ * Stress test for connecting and disconnecting with a HID device.
+ * <p>
+ * In this test, the local device plays the role of a HID host, and initiates connections and
+ * disconnections with a HID device.
+ */
+ public void testConnectInput() {
+ int iterations = BluetoothTestRunner.sConnectInputIterations;
+ if (iterations == 0) {
+ return;
+ }
+
+ BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+ BluetoothDevice device = adapter.getRemoteDevice(BluetoothTestRunner.sInputAddress);
+ mTestUtils.enable(adapter);
+ mTestUtils.pair(adapter, device, BluetoothTestRunner.sPairPasskey,
+ BluetoothTestRunner.sPairPin);
+
+ for (int i = 0; i < iterations; i++) {
+ mTestUtils.writeOutput("connectInput iteration " + (i + 1) + " of " + iterations);
+ mTestUtils.connectInput(adapter, device);
+ mTestUtils.disconnectInput(adapter, device);
+ }
+
+ mTestUtils.unpair(adapter, device);
+ mTestUtils.disable(adapter);
+ }
+
+ /**
+ * Stress test for connecting and disconnecting with a PAN NAP.
+ * <p>
+ * In this test, the local device plays the role of a PANU, and initiates connections and
+ * disconnections with a NAP.
+ */
+ public void testConnectPan() {
+ int iterations = BluetoothTestRunner.sConnectPanIterations;
+ if (iterations == 0) {
+ return;
+ }
+
+ BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+ BluetoothDevice device = adapter.getRemoteDevice(BluetoothTestRunner.sPanAddress);
+ mTestUtils.enable(adapter);
+ mTestUtils.pair(adapter, device, BluetoothTestRunner.sPairPasskey,
+ BluetoothTestRunner.sPairPin);
+
+ for (int i = 0; i < iterations; i++) {
+ mTestUtils.writeOutput("connectPan iteration " + (i + 1) + " of " + iterations);
+ mTestUtils.connectPan(adapter, device);
+ mTestUtils.disconnectPan(adapter, device);
+ }
+
+ mTestUtils.unpair(adapter, device);
+ mTestUtils.disable(adapter);
+ }
+
+ /**
+ * Stress test for verifying a PANU connecting and disconnecting with the device.
+ * <p>
+ * In this test, the local device plays the role of a NAP which a remote PANU connects and
+ * disconnects from.
+ */
+ public void testIncomingPanConnection() {
+ int iterations = BluetoothTestRunner.sConnectPanIterations;
+ if (iterations == 0) {
+ return;
+ }
+
+ BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+ BluetoothDevice device = adapter.getRemoteDevice(BluetoothTestRunner.sPanAddress);
+ mTestUtils.enable(adapter);
+ mTestUtils.enablePan(adapter);
+ mTestUtils.acceptPair(adapter, device, BluetoothTestRunner.sPairPasskey,
+ BluetoothTestRunner.sPairPin);
+
+ for (int i = 0; i < iterations; i++) {
+ mTestUtils.writeOutput("incomingPanConnection iteration " + (i + 1) + " of "
+ + iterations);
+ mTestUtils.incomingPanConnection(adapter, device);
+ mTestUtils.incomingPanDisconnection(adapter, device);
+ }
+
+ mTestUtils.unpair(adapter, device);
+ mTestUtils.disablePan(adapter);
mTestUtils.disable(adapter);
}
}
diff --git a/core/tests/coretests/src/android/bluetooth/BluetoothTestRunner.java b/core/tests/coretests/src/android/bluetooth/BluetoothTestRunner.java
index 3e589fc..cede05a 100644
--- a/core/tests/coretests/src/android/bluetooth/BluetoothTestRunner.java
+++ b/core/tests/coretests/src/android/bluetooth/BluetoothTestRunner.java
@@ -23,19 +23,51 @@
import android.test.InstrumentationTestSuite;
import android.util.Log;
+/**
+ * Instrumentation test runner for Bluetooth tests.
+ * <p>
+ * To run:
+ * <pre>
+ * {@code
+ * adb shell am instrument \
+ * [-e enable_iterations <iterations>] \
+ * [-e discoverable_iterations <iterations>] \
+ * [-e scan_iterations <iterations>] \
+ * [-e enable_pan_iterations <iterations>] \
+ * [-e pair_iterations <iterations>] \
+ * [-e connect_a2dp_iterations <iterations>] \
+ * [-e connect_headset_iterations <iterations>] \
+ * [-e connect_input_iterations <iterations>] \
+ * [-e connect_pan_iterations <iterations>] \
+ * [-e pair_address <address>] \
+ * [-e headset_address <address>] \
+ * [-e a2dp_address <address>] \
+ * [-e input_address <address>] \
+ * [-e pan_address <address>] \
+ * [-e pair_pin <pin>] \
+ * [-e pair_passkey <passkey>] \
+ * -w com.android.frameworks.coretests/android.bluetooth.BluetoothTestRunner
+ * }
+ * </pre>
+ */
public class BluetoothTestRunner extends InstrumentationTestRunner {
private static final String TAG = "BluetoothTestRunner";
public static int sEnableIterations = 100;
public static int sDiscoverableIterations = 1000;
public static int sScanIterations = 1000;
+ public static int sEnablePanIterations = 1000;
public static int sPairIterations = 100;
public static int sConnectHeadsetIterations = 100;
public static int sConnectA2dpIterations = 100;
+ public static int sConnectInputIterations = 100;
+ public static int sConnectPanIterations = 100;
public static String sPairAddress = "";
public static String sHeadsetAddress = "";
public static String sA2dpAddress = "";
+ public static String sInputAddress = "";
+ public static String sPanAddress = "";
public static byte[] sPairPin = {'1', '2', '3', '4'};
public static int sPairPasskey = 123456;
@@ -81,6 +113,15 @@
}
}
+ val = arguments.getString("enable_pan_iterations");
+ if (val != null) {
+ try {
+ sEnablePanIterations = Integer.parseInt(val);
+ } catch (NumberFormatException e) {
+ // Invalid argument, fall back to default value
+ }
+ }
+
val = arguments.getString("pair_iterations");
if (val != null) {
try {
@@ -108,6 +149,24 @@
}
}
+ val = arguments.getString("connect_input_iterations");
+ if (val != null) {
+ try {
+ sConnectInputIterations = Integer.parseInt(val);
+ } catch (NumberFormatException e) {
+ // Invalid argument, fall back to default value
+ }
+ }
+
+ val = arguments.getString("connect_pan_iterations");
+ if (val != null) {
+ try {
+ sConnectPanIterations = Integer.parseInt(val);
+ } catch (NumberFormatException e) {
+ // Invalid argument, fall back to default value
+ }
+ }
+
val = arguments.getString("pair_address");
if (val != null) {
sPairAddress = val;
@@ -123,6 +182,16 @@
sA2dpAddress = val;
}
+ val = arguments.getString("input_address");
+ if (val != null) {
+ sInputAddress = val;
+ }
+
+ val = arguments.getString("pan_address");
+ if (val != null) {
+ sPanAddress = val;
+ }
+
val = arguments.getString("pair_pin");
if (val != null) {
sPairPin = BluetoothDevice.convertPinToBytes(val);
@@ -143,9 +212,13 @@
Log.i(TAG, String.format("pair_iterations=%d", sPairIterations));
Log.i(TAG, String.format("connect_a2dp_iterations=%d", sConnectA2dpIterations));
Log.i(TAG, String.format("connect_headset_iterations=%d", sConnectHeadsetIterations));
+ Log.i(TAG, String.format("connect_input_iterations=%d", sConnectInputIterations));
+ Log.i(TAG, String.format("connect_pan_iterations=%d", sConnectPanIterations));
Log.i(TAG, String.format("pair_address=%s", sPairAddress));
Log.i(TAG, String.format("a2dp_address=%s", sA2dpAddress));
Log.i(TAG, String.format("headset_address=%s", sHeadsetAddress));
+ Log.i(TAG, String.format("input_address=%s", sInputAddress));
+ Log.i(TAG, String.format("pan_address=%s", sPanAddress));
Log.i(TAG, String.format("pair_pin=%s", new String(sPairPin)));
Log.i(TAG, String.format("pair_passkey=%d", sPairPasskey));
diff --git a/core/tests/coretests/src/android/bluetooth/BluetoothTestUtils.java b/core/tests/coretests/src/android/bluetooth/BluetoothTestUtils.java
index 6da38a7..effed76 100644
--- a/core/tests/coretests/src/android/bluetooth/BluetoothTestUtils.java
+++ b/core/tests/coretests/src/android/bluetooth/BluetoothTestUtils.java
@@ -35,49 +35,29 @@
public class BluetoothTestUtils extends Assert {
/**
- * Timeout for {@link BluetoothAdapter#disable()} in ms.
+ * Timeout for enable/disable in ms.
*/
- private static final int DISABLE_TIMEOUT = 20000;
+ private static final int ENABLE_DISABLE_TIMEOUT = 20000;
/**
- * Timeout for {@link BluetoothAdapter#enable()} in ms.
+ * Timeout for discoverable/undiscoverable in ms.
*/
- private static final int ENABLE_TIMEOUT = 20000;
+ private static final int DISCOVERABLE_UNDISCOVERABLE_TIMEOUT = 5000;
/**
- * Timeout for {@link BluetoothAdapter#setScanMode(int)} in ms.
+ * Timeout for starting/stopping a scan in ms.
*/
- private static final int SET_SCAN_MODE_TIMEOUT = 5000;
+ private static final int START_STOP_SCAN_TIMEOUT = 5000;
/**
- * Timeout for {@link BluetoothAdapter#startDiscovery()} in ms.
+ * Timeout for pair/unpair in ms.
*/
- private static final int START_DISCOVERY_TIMEOUT = 5000;
+ private static final int PAIR_UNPAIR_TIMEOUT = 20000;
/**
- * Timeout for {@link BluetoothAdapter#cancelDiscovery()} in ms.
+ * Timeout for connecting/disconnecting a profile in ms.
*/
- private static final int CANCEL_DISCOVERY_TIMEOUT = 5000;
-
- /**
- * Timeout for {@link BluetoothDevice#createBond()} in ms.
- */
- private static final int PAIR_TIMEOUT = 20000;
-
- /**
- * Timeout for {@link BluetoothDevice#removeBond()} in ms.
- */
- private static final int UNPAIR_TIMEOUT = 20000;
-
- /**
- * Timeout for {@link BluetoothProfile#connect(BluetoothDevice)} in ms.
- */
- private static final int CONNECT_PROFILE_TIMEOUT = 20000;
-
- /**
- * Timeout for {@link BluetoothProfile#disconnect(BluetoothDevice)} in ms.
- */
- private static final int DISCONNECT_PROFILE_TIMEOUT = 20000;
+ private static final int CONNECT_DISCONNECT_PROFILE_TIMEOUT = 20000;
/**
* Timeout to connect a profile proxy in ms.
@@ -265,7 +245,6 @@
@Override
public void onReceive(Context context, Intent intent) {
-
if (mConnectionAction != null && mConnectionAction.equals(intent.getAction())) {
if (!mDevice.equals(intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE))) {
return;
@@ -291,6 +270,91 @@
}
}
+ private class ConnectInputReceiver extends FlagReceiver {
+ private static final int STATE_DISCONNECTED_FLAG = 1;
+ private static final int STATE_CONNECTING_FLAG = 1 << 1;
+ private static final int STATE_CONNECTED_FLAG = 1 << 2;
+ private static final int STATE_DISCONNECTING_FLAG = 1 << 3;
+
+ private BluetoothDevice mDevice;
+
+ public ConnectInputReceiver(BluetoothDevice device, int expectedFlags) {
+ super(expectedFlags);
+
+ mDevice = device;
+ }
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (!mDevice.equals(intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE))) {
+ return;
+ }
+
+ if (BluetoothInputDevice.ACTION_INPUT_DEVICE_STATE_CHANGED.equals(intent.getAction())) {
+ int state = intent.getIntExtra(BluetoothInputDevice.EXTRA_INPUT_DEVICE_STATE, -1);
+ assertNotSame(-1, state);
+ switch (state) {
+ case BluetoothInputDevice.STATE_DISCONNECTED:
+ setFiredFlag(STATE_DISCONNECTED_FLAG);
+ break;
+ case BluetoothInputDevice.STATE_CONNECTING:
+ setFiredFlag(STATE_CONNECTING_FLAG);
+ break;
+ case BluetoothInputDevice.STATE_CONNECTED:
+ setFiredFlag(STATE_CONNECTED_FLAG);
+ break;
+ case BluetoothInputDevice.STATE_DISCONNECTING:
+ setFiredFlag(STATE_DISCONNECTING_FLAG);
+ break;
+ }
+ }
+ }
+ }
+
+ private class ConnectPanReceiver extends FlagReceiver {
+ private static final int STATE_DISCONNECTED_FLAG = 1;
+ private static final int STATE_CONNECTING_FLAG = 1 << 1;
+ private static final int STATE_CONNECTED_FLAG = 1 << 2;
+ private static final int STATE_DISCONNECTING_FLAG = 1 << 3;
+
+ private BluetoothDevice mDevice;
+ private int mRole;
+
+ public ConnectPanReceiver(BluetoothDevice device, int role, int expectedFlags) {
+ super (expectedFlags);
+
+ mDevice = device;
+ mRole = role;
+ }
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (!mDevice.equals(intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE))
+ || mRole != intent.getIntExtra(BluetoothPan.EXTRA_LOCAL_ROLE, -1)) {
+ return;
+ }
+
+ if (BluetoothPan.ACTION_PAN_STATE_CHANGED.equals(intent.getAction())) {
+ int state = intent.getIntExtra(BluetoothPan.EXTRA_PAN_STATE, -1);
+ assertNotSame(-1, state);
+ switch (state) {
+ case BluetoothPan.STATE_DISCONNECTED:
+ setFiredFlag(STATE_DISCONNECTED_FLAG);
+ break;
+ case BluetoothPan.STATE_CONNECTING:
+ setFiredFlag(STATE_CONNECTING_FLAG);
+ break;
+ case BluetoothPan.STATE_CONNECTED:
+ setFiredFlag(STATE_CONNECTED_FLAG);
+ break;
+ case BluetoothPan.STATE_DISCONNECTING:
+ setFiredFlag(STATE_DISCONNECTING_FLAG);
+ break;
+ }
+ }
+ }
+ }
+
private BluetoothProfile.ServiceListener mServiceListener =
new BluetoothProfile.ServiceListener() {
public void onServiceConnected(int profile, BluetoothProfile proxy) {
@@ -330,10 +394,24 @@
private BluetoothA2dp mA2dp;
private BluetoothHeadset mHeadset;
+ /**
+ * Creates a utility instance for testing Bluetooth.
+ *
+ * @param context The context of the application using the utility.
+ * @param tag The log tag of the application using the utility.
+ */
public BluetoothTestUtils(Context context, String tag) {
this(context, tag, null);
}
+ /**
+ * Creates a utility instance for testing Bluetooth.
+ *
+ * @param context The context of the application using the utility.
+ * @param tag The log tag of the application using the utility.
+ * @param outputFile The path to an output file if the utility is to write results to a
+ * separate file.
+ */
public BluetoothTestUtils(Context context, String tag, String outputFile) {
mContext = context;
mTag = tag;
@@ -352,6 +430,9 @@
}
}
+ /**
+ * Closes the utility instance and unregisters any BroadcastReceivers.
+ */
public void close() {
while (!mReceivers.isEmpty()) {
mContext.unregisterReceiver(mReceivers.remove(0));
@@ -366,6 +447,12 @@
}
}
+ /**
+ * Enables Bluetooth and checks to make sure that Bluetooth was turned on and that the correct
+ * actions were broadcast.
+ *
+ * @param adapter The BT adapter.
+ */
public void enable(BluetoothAdapter adapter) {
int mask = (BluetoothReceiver.STATE_TURNING_ON_FLAG | BluetoothReceiver.STATE_ON_FLAG
| BluetoothReceiver.SCAN_MODE_CONNECTABLE_FLAG);
@@ -397,22 +484,19 @@
}
long s = System.currentTimeMillis();
- while (System.currentTimeMillis() - s < ENABLE_TIMEOUT) {
+ while (System.currentTimeMillis() - s < ENABLE_DISABLE_TIMEOUT) {
state = adapter.getState();
- if (state == BluetoothAdapter.STATE_ON) {
+ if (state == BluetoothAdapter.STATE_ON
+ && (receiver.getFiredFlags() & mask) == mask) {
assertTrue(adapter.isEnabled());
- if ((receiver.getFiredFlags() & mask) == mask) {
- long finish = receiver.getCompletedTime();
- if (start != -1 && finish != -1) {
- writeOutput(String.format("enable() completed in %d ms", (finish - start)));
- } else {
- writeOutput("enable() completed");
- }
- removeReceiver(receiver);
- return;
+ long finish = receiver.getCompletedTime();
+ if (start != -1 && finish != -1) {
+ writeOutput(String.format("enable() completed in %d ms", (finish - start)));
+ } else {
+ writeOutput("enable() completed");
}
- } else {
- assertEquals(BluetoothAdapter.STATE_TURNING_ON, state);
+ removeReceiver(receiver);
+ return;
}
sleep(POLL_TIME);
}
@@ -423,6 +507,12 @@
state, BluetoothAdapter.STATE_ON, firedFlags, mask));
}
+ /**
+ * Disables Bluetooth and checks to make sure that Bluetooth was turned off and that the correct
+ * actions were broadcast.
+ *
+ * @param adapter The BT adapter.
+ */
public void disable(BluetoothAdapter adapter) {
int mask = (BluetoothReceiver.STATE_TURNING_OFF_FLAG | BluetoothReceiver.STATE_OFF_FLAG
| BluetoothReceiver.SCAN_MODE_NONE_FLAG);
@@ -454,23 +544,19 @@
}
long s = System.currentTimeMillis();
- while (System.currentTimeMillis() - s < DISABLE_TIMEOUT) {
+ while (System.currentTimeMillis() - s < ENABLE_DISABLE_TIMEOUT) {
state = adapter.getState();
- if (state == BluetoothAdapter.STATE_OFF) {
+ if (state == BluetoothAdapter.STATE_OFF
+ && (receiver.getFiredFlags() & mask) == mask) {
assertFalse(adapter.isEnabled());
- if ((receiver.getFiredFlags() & mask) == mask) {
- long finish = receiver.getCompletedTime();
- if (start != -1 && finish != -1) {
- writeOutput(String.format("disable() completed in %d ms",
- (finish - start)));
- } else {
- writeOutput("disable() completed");
- }
- removeReceiver(receiver);
- return;
+ long finish = receiver.getCompletedTime();
+ if (start != -1 && finish != -1) {
+ writeOutput(String.format("disable() completed in %d ms", (finish - start)));
+ } else {
+ writeOutput("disable() completed");
}
- } else {
- assertEquals(BluetoothAdapter.STATE_TURNING_OFF, state);
+ removeReceiver(receiver);
+ return;
}
sleep(POLL_TIME);
}
@@ -481,6 +567,12 @@
state, BluetoothAdapter.STATE_OFF, firedFlags, mask));
}
+ /**
+ * Puts the local device into discoverable mode and checks to make sure that the local device
+ * is in discoverable mode and that the correct actions were broadcast.
+ *
+ * @param adapter The BT adapter.
+ */
public void discoverable(BluetoothAdapter adapter) {
int mask = BluetoothReceiver.SCAN_MODE_CONNECTABLE_DISCOVERABLE_FLAG;
@@ -499,17 +591,14 @@
long start = System.currentTimeMillis();
assertTrue(adapter.setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE));
- while (System.currentTimeMillis() - start < SET_SCAN_MODE_TIMEOUT) {
+ while (System.currentTimeMillis() - start < DISCOVERABLE_UNDISCOVERABLE_TIMEOUT) {
scanMode = adapter.getScanMode();
- if (scanMode == BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE) {
- if ((receiver.getFiredFlags() & mask) == mask) {
- writeOutput(String.format("discoverable() completed in %d ms",
- (receiver.getCompletedTime() - start)));
- removeReceiver(receiver);
- return;
- }
- } else {
- assertEquals(BluetoothAdapter.SCAN_MODE_CONNECTABLE, scanMode);
+ if (scanMode == BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE
+ && (receiver.getFiredFlags() & mask) == mask) {
+ writeOutput(String.format("discoverable() completed in %d ms",
+ (receiver.getCompletedTime() - start)));
+ removeReceiver(receiver);
+ return;
}
sleep(POLL_TIME);
}
@@ -521,6 +610,12 @@
firedFlags, mask));
}
+ /**
+ * Puts the local device into connectable only mode and checks to make sure that the local
+ * device is in in connectable mode and that the correct actions were broadcast.
+ *
+ * @param adapter The BT adapter.
+ */
public void undiscoverable(BluetoothAdapter adapter) {
int mask = BluetoothReceiver.SCAN_MODE_CONNECTABLE_FLAG;
@@ -539,17 +634,14 @@
long start = System.currentTimeMillis();
assertTrue(adapter.setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE));
- while (System.currentTimeMillis() - start < SET_SCAN_MODE_TIMEOUT) {
+ while (System.currentTimeMillis() - start < DISCOVERABLE_UNDISCOVERABLE_TIMEOUT) {
scanMode = adapter.getScanMode();
- if (scanMode == BluetoothAdapter.SCAN_MODE_CONNECTABLE) {
- if ((receiver.getFiredFlags() & mask) == mask) {
- writeOutput(String.format("undiscoverable() completed in %d ms",
- (receiver.getCompletedTime() - start)));
- removeReceiver(receiver);
- return;
- }
- } else {
- assertEquals(BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE, scanMode);
+ if (scanMode == BluetoothAdapter.SCAN_MODE_CONNECTABLE
+ && (receiver.getFiredFlags() & mask) == mask) {
+ writeOutput(String.format("undiscoverable() completed in %d ms",
+ (receiver.getCompletedTime() - start)));
+ removeReceiver(receiver);
+ return;
}
sleep(POLL_TIME);
}
@@ -561,6 +653,12 @@
mask));
}
+ /**
+ * Starts a scan for remote devices and checks to make sure that the local device is scanning
+ * and that the correct actions were broadcast.
+ *
+ * @param adapter The BT adapter.
+ */
public void startScan(BluetoothAdapter adapter) {
int mask = BluetoothReceiver.DISCOVERY_STARTED_FLAG;
@@ -577,7 +675,7 @@
long start = System.currentTimeMillis();
assertTrue(adapter.startDiscovery());
- while (System.currentTimeMillis() - start < START_DISCOVERY_TIMEOUT) {
+ while (System.currentTimeMillis() - start < START_STOP_SCAN_TIMEOUT) {
if (adapter.isDiscovering() && ((receiver.getFiredFlags() & mask) == mask)) {
writeOutput(String.format("startScan() completed in %d ms",
(receiver.getCompletedTime() - start)));
@@ -593,6 +691,12 @@
adapter.isDiscovering(), firedFlags, mask));
}
+ /**
+ * Stops a scan for remote devices and checks to make sure that the local device is not scanning
+ * and that the correct actions were broadcast.
+ *
+ * @param adapter The BT adapter.
+ */
public void stopScan(BluetoothAdapter adapter) {
int mask = BluetoothReceiver.DISCOVERY_FINISHED_FLAG;
@@ -610,7 +714,7 @@
// TODO: put assertTrue() around cancelDiscovery() once it starts returning true.
adapter.cancelDiscovery();
- while (System.currentTimeMillis() - start < CANCEL_DISCOVERY_TIMEOUT) {
+ while (System.currentTimeMillis() - start < START_STOP_SCAN_TIMEOUT) {
if (!adapter.isDiscovering() && ((receiver.getFiredFlags() & mask) == mask)) {
writeOutput(String.format("stopScan() completed in %d ms",
(receiver.getCompletedTime() - start)));
@@ -627,20 +731,84 @@
}
+ /**
+ * Enables PAN tethering on the local device and checks to make sure that tethering is enabled.
+ *
+ * @param adapter The BT adapter.
+ */
+ public void enablePan(BluetoothAdapter adapter) {
+ BluetoothPan pan = new BluetoothPan(mContext);
+ assertNotNull(pan);
+
+ long start = System.currentTimeMillis();
+ pan.setBluetoothTethering(true);
+ long stop = System.currentTimeMillis();
+ assertTrue(pan.isTetheringOn());
+
+ writeOutput(String.format("enablePan() completed in %d ms", (stop - start)));
+ }
+
+ /**
+ * Disables PAN tethering on the local device and checks to make sure that tethering is
+ * disabled.
+ *
+ * @param adapter The BT adapter.
+ */
+ public void disablePan(BluetoothAdapter adapter) {
+ BluetoothPan pan = new BluetoothPan(mContext);
+ assertNotNull(pan);
+
+ long start = System.currentTimeMillis();
+ pan.setBluetoothTethering(false);
+ long stop = System.currentTimeMillis();
+ assertFalse(pan.isTetheringOn());
+
+ writeOutput(String.format("disablePan() completed in %d ms", (stop - start)));
+ }
+
+ /**
+ * Initiates a pairing with a remote device and checks to make sure that the devices are paired
+ * and that the correct actions were broadcast.
+ *
+ * @param adapter The BT adapter.
+ * @param device The remote device.
+ * @param passkey The pairing passkey if pairing requires a passkey. Any value if not.
+ * @param pin The pairing pin if pairing requires a pin. Any value if not.
+ */
public void pair(BluetoothAdapter adapter, BluetoothDevice device, int passkey, byte[] pin) {
pairOrAcceptPair(adapter, device, passkey, pin, true);
}
+ /**
+ * Accepts a pairing with a remote device and checks to make sure that the devices are paired
+ * and that the correct actions were broadcast.
+ *
+ * @param adapter The BT adapter.
+ * @param device The remote device.
+ * @param passkey The pairing passkey if pairing requires a passkey. Any value if not.
+ * @param pin The pairing pin if pairing requires a pin. Any value if not.
+ */
public void acceptPair(BluetoothAdapter adapter, BluetoothDevice device, int passkey,
byte[] pin) {
pairOrAcceptPair(adapter, device, passkey, pin, false);
}
+ /**
+ * Helper method used by {@link #pair(BluetoothAdapter, BluetoothDevice, int, byte[])} and
+ * {@link #acceptPair(BluetoothAdapter, BluetoothDevice, int, byte[])} to either pair or accept
+ * a pairing request.
+ *
+ * @param adapter The BT adapter.
+ * @param device The remote device.
+ * @param passkey The pairing passkey if pairing requires a passkey. Any value if not.
+ * @param pin The pairing pin if pairing requires a pin. Any value if not.
+ * @param shouldPair Whether to pair or accept the pair.
+ */
private void pairOrAcceptPair(BluetoothAdapter adapter, BluetoothDevice device, int passkey,
- byte[] pin, boolean pair) {
+ byte[] pin, boolean shouldPair) {
int mask = PairReceiver.STATE_BONDING_FLAG | PairReceiver.STATE_BONDED_FLAG;
long start = -1;
- String methodName = pair ? "pair()" : "acceptPair()";
+ String methodName = shouldPair ? "pair()" : "acceptPair()";
if (!adapter.isEnabled()) {
fail(methodName + " bluetooth not enabled");
@@ -653,7 +821,7 @@
case BluetoothDevice.BOND_NONE:
assertFalse(adapter.getBondedDevices().contains(device));
start = System.currentTimeMillis();
- if (pair) {
+ if (shouldPair) {
assertTrue(device.createBond());
}
break;
@@ -670,21 +838,19 @@
}
long s = System.currentTimeMillis();
- while (System.currentTimeMillis() - s < PAIR_TIMEOUT) {
+ while (System.currentTimeMillis() - s < PAIR_UNPAIR_TIMEOUT) {
state = device.getBondState();
- if (state == BluetoothDevice.BOND_BONDED) {
+ if (state == BluetoothDevice.BOND_BONDED && (receiver.getFiredFlags() & mask) == mask) {
assertTrue(adapter.getBondedDevices().contains(device));
- if ((receiver.getFiredFlags() & mask) == mask) {
- long finish = receiver.getCompletedTime();
- if (start != -1 && finish != -1) {
- writeOutput(String.format("%s completed in %d ms: device=%s", methodName,
- (finish - start), device));
- } else {
- writeOutput(String.format("%s completed: device=%s", methodName, device));
- }
- removeReceiver(receiver);
- return;
+ long finish = receiver.getCompletedTime();
+ if (start != -1 && finish != -1) {
+ writeOutput(String.format("%s completed in %d ms: device=%s", methodName,
+ (finish - start), device));
+ } else {
+ writeOutput(String.format("%s completed: device=%s", methodName, device));
}
+ removeReceiver(receiver);
+ return;
}
sleep(POLL_TIME);
}
@@ -696,6 +862,13 @@
BluetoothDevice.BOND_BONDED, firedFlags, mask));
}
+ /**
+ * Deletes a pairing with a remote device and checks to make sure that the devices are unpaired
+ * and that the correct actions were broadcast.
+ *
+ * @param adapter The BT adapter.
+ * @param device The remote device.
+ */
public void unpair(BluetoothAdapter adapter, BluetoothDevice device) {
int mask = PairReceiver.STATE_NONE_FLAG;
long start = -1;
@@ -727,20 +900,19 @@
}
long s = System.currentTimeMillis();
- while (System.currentTimeMillis() - s < UNPAIR_TIMEOUT) {
- if (device.getBondState() == BluetoothDevice.BOND_NONE) {
+ while (System.currentTimeMillis() - s < PAIR_UNPAIR_TIMEOUT) {
+ if (device.getBondState() == BluetoothDevice.BOND_NONE
+ && (receiver.getFiredFlags() & mask) == mask) {
assertFalse(adapter.getBondedDevices().contains(device));
- if ((receiver.getFiredFlags() & mask) == mask) {
- long finish = receiver.getCompletedTime();
- if (start != -1 && finish != -1) {
- writeOutput(String.format("unpair() completed in %d ms: device=%s",
- (finish - start), device));
- } else {
- writeOutput(String.format("unpair() completed: device=%s", device));
- }
- removeReceiver(receiver);
- return;
+ long finish = receiver.getCompletedTime();
+ if (start != -1 && finish != -1) {
+ writeOutput(String.format("unpair() completed in %d ms: device=%s",
+ (finish - start), device));
+ } else {
+ writeOutput(String.format("unpair() completed: device=%s", device));
}
+ removeReceiver(receiver);
+ return;
}
}
@@ -751,6 +923,15 @@
firedFlags, mask));
}
+ /**
+ * Connects a profile from the local device to a remote device and checks to make sure that the
+ * profile is connected and that the correct actions were broadcast.
+ *
+ * @param adapter The BT adapter.
+ * @param device The remote device.
+ * @param profile The profile to connect. One of {@link BluetoothProfile#A2DP} or
+ * {@link BluetoothProfile#HEADSET}.
+ */
public void connectProfile(BluetoothAdapter adapter, BluetoothDevice device, int profile) {
int mask = (ConnectProfileReceiver.STATE_CONNECTING_FLAG
| ConnectProfileReceiver.STATE_CONNECTED_FLAG);
@@ -794,21 +975,20 @@
}
long s = System.currentTimeMillis();
- while (System.currentTimeMillis() - s < CONNECT_PROFILE_TIMEOUT) {
+ while (System.currentTimeMillis() - s < CONNECT_DISCONNECT_PROFILE_TIMEOUT) {
state = proxy.getConnectionState(device);
- if (state == BluetoothProfile.STATE_CONNECTED) {
- if ((receiver.getFiredFlags() & mask) == mask) {
- long finish = receiver.getCompletedTime();
- if (start != -1 && finish != -1) {
- writeOutput(String.format("connectProfile() completed in %d ms: "
- + "device=%s, profile=%d", (finish - start), device, profile));
- } else {
- writeOutput(String.format("connectProfile() completed: device=%s, "
- + "profile=%d", device, profile));
- }
- removeReceiver(receiver);
- return;
+ if (state == BluetoothProfile.STATE_CONNECTED
+ && (receiver.getFiredFlags() & mask) == mask) {
+ long finish = receiver.getCompletedTime();
+ if (start != -1 && finish != -1) {
+ writeOutput(String.format("connectProfile() completed in %d ms: "
+ + "device=%s, profile=%d", (finish - start), device, profile));
+ } else {
+ writeOutput(String.format("connectProfile() completed: device=%s, "
+ + "profile=%d", device, profile));
}
+ removeReceiver(receiver);
+ return;
}
sleep(POLL_TIME);
}
@@ -820,6 +1000,15 @@
BluetoothProfile.STATE_CONNECTED, firedFlags, mask));
}
+ /**
+ * Disconnects a profile between the local device and a remote device and checks to make sure
+ * that the profile is disconnected and that the correct actions were broadcast.
+ *
+ * @param adapter The BT adapter.
+ * @param device The remote device.
+ * @param profile The profile to disconnect. One of {@link BluetoothProfile#A2DP} or
+ * {@link BluetoothProfile#HEADSET}.
+ */
public void disconnectProfile(BluetoothAdapter adapter, BluetoothDevice device, int profile) {
int mask = (ConnectProfileReceiver.STATE_DISCONNECTING_FLAG
| ConnectProfileReceiver.STATE_DISCONNECTED_FLAG);
@@ -863,21 +1052,20 @@
}
long s = System.currentTimeMillis();
- while (System.currentTimeMillis() - s < DISCONNECT_PROFILE_TIMEOUT) {
+ while (System.currentTimeMillis() - s < CONNECT_DISCONNECT_PROFILE_TIMEOUT) {
state = proxy.getConnectionState(device);
- if (state == BluetoothProfile.STATE_DISCONNECTED) {
- if ((receiver.getFiredFlags() & mask) == mask) {
- long finish = receiver.getCompletedTime();
- if (start != -1 && finish != -1) {
- writeOutput(String.format("disconnectProfile() completed in %d ms: "
- + "device=%s, profile=%d", (finish - start), device, profile));
- } else {
- writeOutput(String.format("disconnectProfile() completed: device=%s, "
- + "profile=%d", device, profile));
- }
- removeReceiver(receiver);
- return;
+ if (state == BluetoothProfile.STATE_DISCONNECTED
+ && (receiver.getFiredFlags() & mask) == mask) {
+ long finish = receiver.getCompletedTime();
+ if (start != -1 && finish != -1) {
+ writeOutput(String.format("disconnectProfile() completed in %d ms: "
+ + "device=%s, profile=%d", (finish - start), device, profile));
+ } else {
+ writeOutput(String.format("disconnectProfile() completed: device=%s, "
+ + "profile=%d", device, profile));
}
+ removeReceiver(receiver);
+ return;
}
sleep(POLL_TIME);
}
@@ -889,6 +1077,360 @@
BluetoothProfile.STATE_DISCONNECTED, firedFlags, mask));
}
+ /**
+ * Connects the local device with a remote HID device and checks to make sure that the profile
+ * is connected and that the correct actions were broadcast.
+ *
+ * @param adapter The BT adapter.
+ * @param device The remote device.
+ */
+ public void connectInput(BluetoothAdapter adapter, BluetoothDevice device) {
+ int mask = (ConnectInputReceiver.STATE_CONNECTING_FLAG
+ | ConnectInputReceiver.STATE_CONNECTED_FLAG);
+ long start = -1;
+
+ if (!adapter.isEnabled()) {
+ fail(String.format("connectInput() bluetooth not enabled: device=%s", device));
+ }
+
+ if (!adapter.getBondedDevices().contains(device)) {
+ fail(String.format("connectInput() device not paired: device=%s", device));
+ }
+
+ BluetoothInputDevice inputDevice = new BluetoothInputDevice(mContext);
+ assertNotNull(inputDevice);
+ ConnectInputReceiver receiver = getConnectInputReceiver(device, mask);
+
+ int state = inputDevice.getInputDeviceState(device);
+ switch (state) {
+ case BluetoothInputDevice.STATE_CONNECTED:
+ removeReceiver(receiver);
+ return;
+ case BluetoothInputDevice.STATE_CONNECTING:
+ mask = 0; // Don't check for received intents since we might have missed them.
+ break;
+ case BluetoothInputDevice.STATE_DISCONNECTED:
+ case BluetoothInputDevice.STATE_DISCONNECTING:
+ start = System.currentTimeMillis();
+ assertTrue(inputDevice.connectInputDevice(device));
+ break;
+ default:
+ removeReceiver(receiver);
+ fail(String.format("connectInput() invalid state: device=%s, state=%d", device,
+ state));
+ }
+
+ long s = System.currentTimeMillis();
+ while (System.currentTimeMillis() - s < CONNECT_DISCONNECT_PROFILE_TIMEOUT) {
+ state = inputDevice.getInputDeviceState(device);
+ if (state == BluetoothInputDevice.STATE_CONNECTED
+ && (receiver.getFiredFlags() & mask) == mask) {
+ long finish = receiver.getCompletedTime();
+ if (start != -1 && finish != -1) {
+ writeOutput(String.format("connectInput() completed in %d ms: device=%s",
+ (finish - start), device));
+ } else {
+ writeOutput(String.format("connectInput() completed: device=%s", device));
+ }
+ removeReceiver(receiver);
+ return;
+ }
+ sleep(POLL_TIME);
+ }
+
+ int firedFlags = receiver.getFiredFlags();
+ removeReceiver(receiver);
+ fail(String.format("connectInput() timeout: device=%s, state=%d (expected %d), "
+ + "flags=0x%x (expected 0x%s)", device, state, BluetoothInputDevice.STATE_CONNECTED,
+ firedFlags, mask));
+ }
+
+ /**
+ * Disconnects the local device with a remote HID device and checks to make sure that the
+ * profile is connected and that the correct actions were broadcast.
+ *
+ * @param adapter The BT adapter.
+ * @param device The remote device.
+ */
+ public void disconnectInput(BluetoothAdapter adapter, BluetoothDevice device) {
+ int mask = (ConnectInputReceiver.STATE_DISCONNECTING_FLAG
+ | ConnectInputReceiver.STATE_DISCONNECTED_FLAG);
+ long start = -1;
+
+ if (!adapter.isEnabled()) {
+ fail(String.format("disconnectInput() bluetooth not enabled: device=%s", device));
+ }
+
+ if (!adapter.getBondedDevices().contains(device)) {
+ fail(String.format("disconnectInput() device not paired: device=%s", device));
+ }
+
+ BluetoothInputDevice inputDevice = new BluetoothInputDevice(mContext);
+ assertNotNull(inputDevice);
+ ConnectInputReceiver receiver = getConnectInputReceiver(device, mask);
+
+ int state = inputDevice.getInputDeviceState(device);
+ switch (state) {
+ case BluetoothInputDevice.STATE_CONNECTED:
+ case BluetoothInputDevice.STATE_CONNECTING:
+ start = System.currentTimeMillis();
+ assertTrue(inputDevice.disconnectInputDevice(device));
+ break;
+ case BluetoothInputDevice.STATE_DISCONNECTED:
+ removeReceiver(receiver);
+ return;
+ case BluetoothInputDevice.STATE_DISCONNECTING:
+ mask = 0; // Don't check for received intents since we might have missed them.
+ break;
+ default:
+ removeReceiver(receiver);
+ fail(String.format("disconnectInput() invalid state: device=%s, state=%d", device,
+ state));
+ }
+
+ long s = System.currentTimeMillis();
+ while (System.currentTimeMillis() - s < CONNECT_DISCONNECT_PROFILE_TIMEOUT) {
+ state = inputDevice.getInputDeviceState(device);
+ if (state == BluetoothInputDevice.STATE_DISCONNECTED
+ && (receiver.getFiredFlags() & mask) == mask) {
+ long finish = receiver.getCompletedTime();
+ if (start != -1 && finish != -1) {
+ writeOutput(String.format("disconnectInput() completed in %d ms: device=%s",
+ (finish - start), device));
+ } else {
+ writeOutput(String.format("disconnectInput() completed: device=%s", device));
+ }
+ removeReceiver(receiver);
+ return;
+ }
+ sleep(POLL_TIME);
+ }
+
+ int firedFlags = receiver.getFiredFlags();
+ removeReceiver(receiver);
+ fail(String.format("disconnectInput() timeout: device=%s, state=%d (expected %d), "
+ + "flags=0x%x (expected 0x%s)", device, state,
+ BluetoothInputDevice.STATE_DISCONNECTED, firedFlags, mask));
+ }
+
+ /**
+ * Connects the PANU to a remote NAP and checks to make sure that the PANU is connected and that
+ * the correct actions were broadcast.
+ *
+ * @param adapter The BT adapter.
+ * @param device The remote device.
+ */
+ public void connectPan(BluetoothAdapter adapter, BluetoothDevice device) {
+ connectPanOrIncomingPanConnection(adapter, device, true);
+ }
+
+ /**
+ * Checks that a remote PANU connects to the local NAP correctly and that the correct actions
+ * were broadcast.
+ *
+ * @param adapter The BT adapter.
+ * @param device The remote device.
+ */
+ public void incomingPanConnection(BluetoothAdapter adapter, BluetoothDevice device) {
+ connectPanOrIncomingPanConnection(adapter, device, false);
+ }
+
+ /**
+ * Helper method used by {@link #connectPan(BluetoothAdapter, BluetoothDevice)} and
+ * {@link #incomingPanConnection(BluetoothAdapter, BluetoothDevice)} to either connect to a
+ * remote NAP or verify that a remote device connected to the local NAP.
+ *
+ * @param adapter The BT adapter.
+ * @param device The remote device.
+ * @param connect If the method should initiate the connection (is PANU)
+ */
+ private void connectPanOrIncomingPanConnection(BluetoothAdapter adapter, BluetoothDevice device,
+ boolean connect) {
+ long start = -1;
+ int mask, role;
+ String methodName;
+
+ if (connect) {
+ methodName = "connectPan()";
+ mask = (ConnectPanReceiver.STATE_CONNECTED_FLAG |
+ ConnectPanReceiver.STATE_CONNECTING_FLAG);
+ role = BluetoothPan.LOCAL_PANU_ROLE;
+ } else {
+ methodName = "incomingPanConnection()";
+ mask = ConnectPanReceiver.STATE_CONNECTED_FLAG;
+ role = BluetoothPan.LOCAL_NAP_ROLE;
+ }
+
+ if (!adapter.isEnabled()) {
+ fail(String.format("%s bluetooth not enabled: device=%s", methodName, device));
+ }
+
+ if (!adapter.getBondedDevices().contains(device)) {
+ fail(String.format("%s device not paired: device=%s", methodName, device));
+ }
+
+ BluetoothPan pan = new BluetoothPan(mContext);
+ assertNotNull(pan);
+ ConnectPanReceiver receiver = getConnectPanReceiver(device, role, mask);
+
+ int state = pan.getPanDeviceState(device);
+ switch (state) {
+ case BluetoothPan.STATE_CONNECTED:
+ removeReceiver(receiver);
+ return;
+ case BluetoothPan.STATE_CONNECTING:
+ mask = 0; // Don't check for received intents since we might have missed them.
+ break;
+ case BluetoothPan.STATE_DISCONNECTED:
+ case BluetoothPan.STATE_DISCONNECTING:
+ start = System.currentTimeMillis();
+ if (role == BluetoothPan.LOCAL_PANU_ROLE) {
+ Log.i("BT", "connect to pan");
+ assertTrue(pan.connect(device));
+ }
+ break;
+ default:
+ removeReceiver(receiver);
+ fail(String.format("%s invalid state: device=%s, state=%d", methodName, device,
+ state));
+ }
+
+ long s = System.currentTimeMillis();
+ while (System.currentTimeMillis() - s < CONNECT_DISCONNECT_PROFILE_TIMEOUT) {
+ state = pan.getPanDeviceState(device);
+ if (state == BluetoothPan.STATE_CONNECTED
+ && (receiver.getFiredFlags() & mask) == mask) {
+ long finish = receiver.getCompletedTime();
+ if (start != -1 && finish != -1) {
+ writeOutput(String.format("%s completed in %d ms: device=%s", methodName,
+ (finish - start), device));
+ } else {
+ writeOutput(String.format("%s completed: device=%s", methodName, device));
+ }
+ removeReceiver(receiver);
+ return;
+ }
+ sleep(POLL_TIME);
+ }
+
+ int firedFlags = receiver.getFiredFlags();
+ removeReceiver(receiver);
+ fail(String.format("%s timeout: device=%s, state=%d (expected %d), "
+ + "flags=0x%x (expected 0x%s)", methodName, device, state,
+ BluetoothPan.STATE_CONNECTED, firedFlags, mask));
+ }
+
+ /**
+ * Disconnects the PANU from a remote NAP and checks to make sure that the PANU is disconnected
+ * and that the correct actions were broadcast.
+ *
+ * @param adapter The BT adapter.
+ * @param device The remote device.
+ */
+ public void disconnectPan(BluetoothAdapter adapter, BluetoothDevice device) {
+ disconnectFromRemoteOrVerifyConnectNap(adapter, device, true);
+ }
+
+ /**
+ * Checks that a remote PANU disconnects from the local NAP correctly and that the correct
+ * actions were broadcast.
+ *
+ * @param adapter The BT adapter.
+ * @param device The remote device.
+ */
+ public void incomingPanDisconnection(BluetoothAdapter adapter, BluetoothDevice device) {
+ disconnectFromRemoteOrVerifyConnectNap(adapter, device, false);
+ }
+
+ /**
+ * Helper method used by {@link #disconnectPan(BluetoothAdapter, BluetoothDevice)} and
+ * {@link #incomingPanDisconnection(BluetoothAdapter, BluetoothDevice)} to either disconnect
+ * from a remote NAP or verify that a remote device disconnected from the local NAP.
+ *
+ * @param adapter The BT adapter.
+ * @param device The remote device.
+ * @param disconnect Whether the method should connect or verify.
+ */
+ private void disconnectFromRemoteOrVerifyConnectNap(BluetoothAdapter adapter,
+ BluetoothDevice device, boolean disconnect) {
+ long start = -1;
+ int mask, role;
+ String methodName;
+
+ if (disconnect) {
+ methodName = "disconnectPan()";
+ mask = (ConnectPanReceiver.STATE_DISCONNECTED_FLAG |
+ ConnectPanReceiver.STATE_DISCONNECTING_FLAG);
+ role = BluetoothPan.LOCAL_PANU_ROLE;
+ } else {
+ methodName = "incomingPanDisconnection()";
+ mask = ConnectPanReceiver.STATE_DISCONNECTED_FLAG;
+ role = BluetoothPan.LOCAL_NAP_ROLE;
+ }
+
+ if (!adapter.isEnabled()) {
+ fail(String.format("%s bluetooth not enabled: device=%s", methodName, device));
+ }
+
+ if (!adapter.getBondedDevices().contains(device)) {
+ fail(String.format("%s device not paired: device=%s", methodName, device));
+ }
+
+ BluetoothPan pan = new BluetoothPan(mContext);
+ assertNotNull(pan);
+ ConnectPanReceiver receiver = getConnectPanReceiver(device, role, mask);
+
+ int state = pan.getPanDeviceState(device);
+ switch (state) {
+ case BluetoothInputDevice.STATE_CONNECTED:
+ case BluetoothInputDevice.STATE_CONNECTING:
+ start = System.currentTimeMillis();
+ if (role == BluetoothPan.LOCAL_PANU_ROLE) {
+ assertTrue(pan.disconnect(device));
+ }
+ break;
+ case BluetoothInputDevice.STATE_DISCONNECTED:
+ removeReceiver(receiver);
+ return;
+ case BluetoothInputDevice.STATE_DISCONNECTING:
+ mask = 0; // Don't check for received intents since we might have missed them.
+ break;
+ default:
+ removeReceiver(receiver);
+ fail(String.format("%s invalid state: device=%s, state=%d", methodName, device,
+ state));
+ }
+
+ long s = System.currentTimeMillis();
+ while (System.currentTimeMillis() - s < CONNECT_DISCONNECT_PROFILE_TIMEOUT) {
+ state = pan.getPanDeviceState(device);
+ if (state == BluetoothInputDevice.STATE_DISCONNECTED
+ && (receiver.getFiredFlags() & mask) == mask) {
+ long finish = receiver.getCompletedTime();
+ if (start != -1 && finish != -1) {
+ writeOutput(String.format("%s completed in %d ms: device=%s", methodName,
+ (finish - start), device));
+ } else {
+ writeOutput(String.format("%s completed: device=%s", methodName, device));
+ }
+ removeReceiver(receiver);
+ return;
+ }
+ sleep(POLL_TIME);
+ }
+
+ int firedFlags = receiver.getFiredFlags();
+ removeReceiver(receiver);
+ fail(String.format("%s timeout: device=%s, state=%d (expected %d), "
+ + "flags=0x%x (expected 0x%s)", methodName, device, state,
+ BluetoothInputDevice.STATE_DISCONNECTED, firedFlags, mask));
+ }
+
+ /**
+ * Writes a string to the logcat and a file if a file has been specified in the constructor.
+ *
+ * @param s The string to be written.
+ */
public void writeOutput(String s) {
Log.i(mTag, s);
if (mOutputWriter == null) {
@@ -902,38 +1444,60 @@
}
}
- private BluetoothReceiver getBluetoothReceiver(int expectedFlags) {
- BluetoothReceiver receiver = new BluetoothReceiver(expectedFlags);
+ private void addReceiver(BroadcastReceiver receiver, String[] actions) {
IntentFilter filter = new IntentFilter();
- filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
- filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED);
- filter.addAction(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED);
- filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
+ for (String action: actions) {
+ filter.addAction(action);
+ }
mContext.registerReceiver(receiver, filter);
mReceivers.add(receiver);
+ }
+
+ private BluetoothReceiver getBluetoothReceiver(int expectedFlags) {
+ String[] actions = {
+ BluetoothAdapter.ACTION_DISCOVERY_FINISHED,
+ BluetoothAdapter.ACTION_DISCOVERY_STARTED,
+ BluetoothAdapter.ACTION_SCAN_MODE_CHANGED,
+ BluetoothAdapter.ACTION_STATE_CHANGED};
+ BluetoothReceiver receiver = new BluetoothReceiver(expectedFlags);
+ addReceiver(receiver, actions);
return receiver;
}
private PairReceiver getPairReceiver(BluetoothDevice device, int passkey, byte[] pin,
int expectedFlags) {
+ String[] actions = {
+ BluetoothDevice.ACTION_PAIRING_REQUEST,
+ BluetoothDevice.ACTION_BOND_STATE_CHANGED};
PairReceiver receiver = new PairReceiver(device, passkey, pin, expectedFlags);
- IntentFilter filter = new IntentFilter();
- filter.addAction(BluetoothDevice.ACTION_PAIRING_REQUEST);
- filter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
- mContext.registerReceiver(receiver, filter);
- mReceivers.add(receiver);
+ addReceiver(receiver, actions);
return receiver;
}
private ConnectProfileReceiver getConnectProfileReceiver(BluetoothDevice device, int profile,
int expectedFlags) {
+ String[] actions = {
+ BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED,
+ BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED};
ConnectProfileReceiver receiver = new ConnectProfileReceiver(device, profile,
expectedFlags);
- IntentFilter filter = new IntentFilter();
- filter.addAction(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED);
- filter.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED);
- mContext.registerReceiver(receiver, filter);
- mReceivers.add(receiver);
+ addReceiver(receiver, actions);
+ return receiver;
+ }
+
+ private ConnectInputReceiver getConnectInputReceiver(BluetoothDevice device,
+ int expectedFlags) {
+ String[] actions = {BluetoothInputDevice.ACTION_INPUT_DEVICE_STATE_CHANGED};
+ ConnectInputReceiver receiver = new ConnectInputReceiver(device, expectedFlags);
+ addReceiver(receiver, actions);
+ return receiver;
+ }
+
+ private ConnectPanReceiver getConnectPanReceiver(BluetoothDevice device, int role,
+ int expectedFlags) {
+ String[] actions = {BluetoothPan.ACTION_PAN_STATE_CHANGED};
+ ConnectPanReceiver receiver = new ConnectPanReceiver(device, role, expectedFlags);
+ addReceiver(receiver, actions);
return receiver;
}
diff --git a/docs/html/guide/practices/design/performance.jd b/docs/html/guide/practices/design/performance.jd
index 97b31cf..fe69d7d 100644
--- a/docs/html/guide/practices/design/performance.jd
+++ b/docs/html/guide/practices/design/performance.jd
@@ -8,14 +8,13 @@
<ol>
<li><a href="#intro">Introduction</a></li>
<li><a href="#optimize_judiciously">Optimize Judiciously</a></li>
- <li><a href="#object_creation">Avoid Creating Objects</a></li>
+ <li><a href="#object_creation">Avoid Creating Unnecessary Objects</a></li>
<li><a href="#myths">Performance Myths</a></li>
<li><a href="#prefer_static">Prefer Static Over Virtual</a></li>
<li><a href="#internal_get_set">Avoid Internal Getters/Setters</a></li>
<li><a href="#use_final">Use Static Final For Constants</a></li>
<li><a href="#foreach">Use Enhanced For Loop Syntax</a></li>
- <li><a href="#avoid_enums">Avoid Enums Where You Only Need Ints</a></li>
- <li><a href="#package_inner">Use Package Scope with Inner Classes</a></li>
+ <li><a href="#package_inner">Consider Package Instead of Private Access with Inner Classes</a></li>
<li><a href="#avoidfloat">Use Floating-Point Judiciously</a> </li>
<li><a href="#library">Know And Use The Libraries</a></li>
<li><a href="#native_methods">Use Native Methods Judiciously</a></li>
@@ -83,27 +82,31 @@
test on that device.</p>
<a name="object_creation"></a>
-<h2>Avoid Creating Objects</h2>
+<h2>Avoid Creating Unnecessary Objects</h2>
<p>Object creation is never free. A generational GC with per-thread allocation
pools for temporary objects can make allocation cheaper, but allocating memory
is always more expensive than not allocating memory.</p>
<p>If you allocate objects in a user interface loop, you will force a periodic
-garbage collection, creating little "hiccups" in the user experience.</p>
+garbage collection, creating little "hiccups" in the user experience. The
+concurrent collector introduced in Gingerbread helps, but unnecessary work
+should always be avoided.</p>
<p>Thus, you should avoid creating object instances you don't need to. Some
examples of things that can help:</p>
<ul>
- <li>When extracting strings from a set of input data, try
- to return a substring of the original data, instead of creating a copy.
- You will create a new String object, but it will share the char[]
- with the data.</li>
<li>If you have a method returning a string, and you know that its result
will always be appended to a StringBuffer anyway, change your signature
and implementation so that the function does the append directly,
instead of creating a short-lived temporary object.</li>
+ <li>When extracting strings from a set of input data, try
+ to return a substring of the original data, instead of creating a copy.
+ You will create a new String object, but it will share the char[]
+ with the data. (The trade-off being that if you're only using a small
+ part of the original input, you'll be keeping it all around in memory
+ anyway if you go this route.)</li>
</ul>
<p>A somewhat more radical idea is to slice up multidimensional arrays into
@@ -119,7 +122,7 @@
generally much better than a single array of custom (Foo,Bar) objects.
(The exception to this, of course, is when you're designing an API for
other code to access; in those cases, it's usually better to trade
- correct API design for a small hit in speed. But in your own internal
+ good API design for a small hit in speed. But in your own internal
code, you should try and be as efficient as possible.)</li>
</ul>
@@ -127,6 +130,7 @@
can. Fewer objects created mean less-frequent garbage collection, which has
a direct impact on user experience.</p>
+<a name="avoid_enums" id="avoid_enums"></a>
<a name="myths" id="myths"></a>
<h2>Performance Myths</h2>
@@ -265,43 +269,18 @@
<p>(See also <em>Effective Java</em> item 46.)</p>
-<a name="avoid_enums" id="avoid_enums"></a>
-<h2>Avoid Enums Where You Only Need Ints</h2>
-
-<p>Enums are very convenient, but unfortunately can be painful when size
-and speed matter. For example, this:</p>
-
-<pre>public enum Shrubbery { GROUND, CRAWLING, HANGING }</pre>
-
-<p>adds 740 bytes to your .dex file compared to the equivalent class
-with three public static final ints. On first use, the
-class initializer invokes the <init> method on objects representing each
-of the enumerated values. Each object gets its own static field, and the full
-set is stored in an array (a static field called "$VALUES"). That's a lot of
-code and data, just for three integers. Additionally, this:</p>
-
-<pre>Shrubbery shrub = Shrubbery.GROUND;</pre>
-
-<p>causes a static field lookup. If "GROUND" were a static final int,
-the compiler would treat it as a known constant and inline it.</p>
-
-<p>The flip side, of course, is that with enums you get nicer APIs and
-some compile-time value checking. So, the usual trade-off applies: you should
-by all means use enums for public APIs, but try to avoid them when performance
-matters.</p>
-
-<p>If you're using <code>Enum.ordinal</code>, that's usually a sign that you
-should be using ints instead. As a rule of thumb, if an enum doesn't have a
-constructor and doesn't define its own methods, and it's used in
-performance-critical code, you should consider <code>static final int</code>
-constants instead.</p>
-
<a name="package_inner" id="package_inner"></a>
-<h2>Use Package Scope with Inner Classes</h2>
+<h2>Consider Package Instead of Private Access with Private Inner Classes</h2>
<p>Consider the following class definition:</p>
<pre>public class Foo {
+ private class Inner {
+ void stuff() {
+ Foo.this.doStuff(Foo.this.mValue);
+ }
+ }
+
private int mValue;
public void run() {
@@ -313,24 +292,19 @@
private void doStuff(int value) {
System.out.println("Value is " + value);
}
-
- private class Inner {
- void stuff() {
- Foo.this.doStuff(Foo.this.mValue);
- }
- }
}</pre>
-<p>The key things to note here are that we define an inner class (Foo$Inner)
-that directly accesses a private method and a private instance field
-in the outer class. This is legal, and the code prints "Value is 27" as
-expected.</p>
+<p>The key things to note here are that we define a private inner class
+(<code>Foo$Inner</code>) that directly accesses a private method and a private
+instance field in the outer class. This is legal, and the code prints "Value is
+27" as expected.</p>
-<p>The problem is that the VM considers direct access to Foo's private members
-from Foo$Inner to be illegal because Foo and Foo$Inner are different classes,
-even though the Java language allows an inner class to access an outer class'
-private members. To bridge the gap, the compiler generates a couple of
-synthetic methods:</p>
+<p>The problem is that the VM considers direct access to <code>Foo</code>'s
+private members from <code>Foo$Inner</code> to be illegal because
+<code>Foo</code> and <code>Foo$Inner</code> are different classes, even though
+the Java language allows an inner class to access an outer class' private
+members. To bridge the gap, the compiler generates a couple of synthetic
+methods:</p>
<pre>/*package*/ static int Foo.access$100(Foo foo) {
return foo.mValue;
@@ -339,22 +313,19 @@
foo.doStuff(value);
}</pre>
-<p>The inner-class code calls these static methods whenever it needs to
-access the "mValue" field or invoke the "doStuff" method in the outer
-class. What this means is that the code above really boils down to a case
-where you're accessing member fields through accessor methods instead of
-directly. Earlier we talked about how accessors are slower than direct field
+<p>The inner class code calls these static methods whenever it needs to
+access the <code>mValue</code> field or invoke the <code>doStuff</code> method
+in the outer class. What this means is that the code above really boils down to
+a case where you're accessing member fields through accessor methods.
+Earlier we talked about how accessors are slower than direct field
accesses, so this is an example of a certain language idiom resulting in an
"invisible" performance hit.</p>
-<p>We can avoid this problem by declaring fields and methods accessed
-by inner classes to have package scope, rather than private scope.
-This runs faster and removes the overhead of the generated methods.
-(Unfortunately it also means the fields could be accessed directly by other
-classes in the same package, which runs counter to the standard
-practice of making all fields private. Once again, if you're
-designing a public API you might want to carefully consider using this
-optimization.)</p>
+<p>If you're using code like this in a performance hotspot, you can avoid the
+overhead by declaring fields and methods accessed by inner classes to have
+package access, rather than private access. Unfortunately this means the fields
+can be accessed directly by other classes in the same package, so you shouldn't
+use this in public API.</p>
<a name="avoidfloat" id="avoidfloat"></a>
<h2>Use Floating-Point Judiciously</h2>
diff --git a/drm/common/IDrmManagerService.cpp b/drm/common/IDrmManagerService.cpp
index 75edac6..ddbd220 100644
--- a/drm/common/IDrmManagerService.cpp
+++ b/drm/common/IDrmManagerService.cpp
@@ -382,7 +382,7 @@
}
data.writeInt32(playbackStatus);
- data.writeInt32(position);
+ data.writeInt64(position);
remote()->transact(SET_PLAYBACK_STATUS, data, &reply);
return reply.readInt32();
@@ -1111,7 +1111,7 @@
}
const status_t status
- = setPlaybackStatus(uniqueId, &handle, data.readInt32(), data.readInt32());
+ = setPlaybackStatus(uniqueId, &handle, data.readInt32(), data.readInt64());
reply->writeInt32(status);
delete handle.decryptInfo; handle.decryptInfo = NULL;
diff --git a/graphics/java/android/graphics/Region.java b/graphics/java/android/graphics/Region.java
index e540806..27ea0f0 100644
--- a/graphics/java/android/graphics/Region.java
+++ b/graphics/java/android/graphics/Region.java
@@ -287,6 +287,10 @@
region2.mNativeRegion, op.nativeInt);
}
+ public String toString() {
+ return nativeToString(mNativeRegion);
+ }
+
//////////////////////////////////////////////////////////////////////////
public static final Parcelable.Creator<Region> CREATOR
@@ -357,6 +361,8 @@
return mNativeRegion;
}
+ private static native boolean nativeEquals(int native_r1, int native_r2);
+
private static native int nativeConstructor();
private static native void nativeDestructor(int native_region);
@@ -381,5 +387,5 @@
private static native boolean nativeWriteToParcel(int native_region,
Parcel p);
- private static native boolean nativeEquals(int native_r1, int native_r2);
+ private static native String nativeToString(int native_region);
}
diff --git a/graphics/java/android/renderscript/Allocation.java b/graphics/java/android/renderscript/Allocation.java
index 1789891..74cdf80 100644
--- a/graphics/java/android/renderscript/Allocation.java
+++ b/graphics/java/android/renderscript/Allocation.java
@@ -268,22 +268,105 @@
}
}
+ /**
+ * Copy an allocation from an array. This variant is not type
+ * checked which allows an application to fill in structured
+ * data from an array.
+ *
+ * @param d the source data array
+ */
+ public void copyFromUnchecked(int[] d) {
+ mRS.validate();
+ copy1DRangeFromUnchecked(0, mType.getCount(), d);
+ }
+ /**
+ * Copy an allocation from an array. This variant is not type
+ * checked which allows an application to fill in structured
+ * data from an array.
+ *
+ * @param d the source data array
+ */
+ public void copyFromUnchecked(short[] d) {
+ mRS.validate();
+ copy1DRangeFromUnchecked(0, mType.getCount(), d);
+ }
+ /**
+ * Copy an allocation from an array. This variant is not type
+ * checked which allows an application to fill in structured
+ * data from an array.
+ *
+ * @param d the source data array
+ */
+ public void copyFromUnchecked(byte[] d) {
+ mRS.validate();
+ copy1DRangeFromUnchecked(0, mType.getCount(), d);
+ }
+ /**
+ * Copy an allocation from an array. This variant is not type
+ * checked which allows an application to fill in structured
+ * data from an array.
+ *
+ * @param d the source data array
+ */
+ public void copyFromUnchecked(float[] d) {
+ mRS.validate();
+ copy1DRangeFromUnchecked(0, mType.getCount(), d);
+ }
+
+ /**
+ * Copy an allocation from an array. This variant is type
+ * checked and will generate exceptions if the Allocation type
+ * is not a 32 bit integer type.
+ *
+ * @param d the source data array
+ */
public void copyFrom(int[] d) {
mRS.validate();
copy1DRangeFrom(0, mType.getCount(), d);
}
+
+ /**
+ * Copy an allocation from an array. This variant is type
+ * checked and will generate exceptions if the Allocation type
+ * is not a 16 bit integer type.
+ *
+ * @param d the source data array
+ */
public void copyFrom(short[] d) {
mRS.validate();
copy1DRangeFrom(0, mType.getCount(), d);
}
+
+ /**
+ * Copy an allocation from an array. This variant is type
+ * checked and will generate exceptions if the Allocation type
+ * is not a 8 bit integer type.
+ *
+ * @param d the source data array
+ */
public void copyFrom(byte[] d) {
mRS.validate();
copy1DRangeFrom(0, mType.getCount(), d);
}
+
+ /**
+ * Copy an allocation from an array. This variant is type
+ * checked and will generate exceptions if the Allocation type
+ * is not a 32 bit float type.
+ *
+ * @param d the source data array
+ */
public void copyFrom(float[] d) {
mRS.validate();
copy1DRangeFrom(0, mType.getCount(), d);
}
+
+ /**
+ * Copy an allocation from a bitmap. The height, width, and
+ * format of the bitmap must match the existing allocation.
+ *
+ * @param b the source bitmap
+ */
public void copyFrom(Bitmap b) {
mRS.validate();
validateBitmapSize(b);
@@ -369,39 +452,114 @@
mRS.nAllocationGenerateMipmaps(getID());
}
- void copy1DRangeFromUnchecked(int off, int count, int[] d) {
+ /**
+ * Copy part of an allocation from an array. This variant is
+ * not type checked which allows an application to fill in
+ * structured data from an array.
+ *
+ * @param off The offset of the first element to be copied.
+ * @param count The number of elements to be copied.
+ * @param d the source data array
+ */
+ public void copy1DRangeFromUnchecked(int off, int count, int[] d) {
int dataSize = mType.mElement.getSizeBytes() * count;
data1DChecks(off, count, d.length * 4, dataSize);
mRS.nAllocationData1D(getID(), off, 0, count, d, dataSize);
}
- void copy1DRangeFromUnchecked(int off, int count, short[] d) {
+ /**
+ * Copy part of an allocation from an array. This variant is
+ * not type checked which allows an application to fill in
+ * structured data from an array.
+ *
+ * @param off The offset of the first element to be copied.
+ * @param count The number of elements to be copied.
+ * @param d the source data array
+ */
+ public void copy1DRangeFromUnchecked(int off, int count, short[] d) {
int dataSize = mType.mElement.getSizeBytes() * count;
data1DChecks(off, count, d.length * 2, dataSize);
mRS.nAllocationData1D(getID(), off, 0, count, d, dataSize);
}
- void copy1DRangeFromUnchecked(int off, int count, byte[] d) {
+ /**
+ * Copy part of an allocation from an array. This variant is
+ * not type checked which allows an application to fill in
+ * structured data from an array.
+ *
+ * @param off The offset of the first element to be copied.
+ * @param count The number of elements to be copied.
+ * @param d the source data array
+ */
+ public void copy1DRangeFromUnchecked(int off, int count, byte[] d) {
int dataSize = mType.mElement.getSizeBytes() * count;
data1DChecks(off, count, d.length, dataSize);
mRS.nAllocationData1D(getID(), off, 0, count, d, dataSize);
}
- void copy1DRangeFromUnchecked(int off, int count, float[] d) {
+ /**
+ * Copy part of an allocation from an array. This variant is
+ * not type checked which allows an application to fill in
+ * structured data from an array.
+ *
+ * @param off The offset of the first element to be copied.
+ * @param count The number of elements to be copied.
+ * @param d the source data array
+ */
+ public void copy1DRangeFromUnchecked(int off, int count, float[] d) {
int dataSize = mType.mElement.getSizeBytes() * count;
data1DChecks(off, count, d.length * 4, dataSize);
mRS.nAllocationData1D(getID(), off, 0, count, d, dataSize);
}
+ /**
+ * Copy part of an allocation from an array. This variant is
+ * type checked and will generate exceptions if the Allocation
+ * type is not a 32 bit integer type.
+ *
+ * @param off The offset of the first element to be copied.
+ * @param count The number of elements to be copied.
+ * @param d the source data array
+ */
public void copy1DRangeFrom(int off, int count, int[] d) {
validateIsInt32();
copy1DRangeFromUnchecked(off, count, d);
}
+
+ /**
+ * Copy part of an allocation from an array. This variant is
+ * type checked and will generate exceptions if the Allocation
+ * type is not a 16 bit integer type.
+ *
+ * @param off The offset of the first element to be copied.
+ * @param count The number of elements to be copied.
+ * @param d the source data array
+ */
public void copy1DRangeFrom(int off, int count, short[] d) {
validateIsInt16();
copy1DRangeFromUnchecked(off, count, d);
}
+
+ /**
+ * Copy part of an allocation from an array. This variant is
+ * type checked and will generate exceptions if the Allocation
+ * type is not a 8 bit integer type.
+ *
+ * @param off The offset of the first element to be copied.
+ * @param count The number of elements to be copied.
+ * @param d the source data array
+ */
public void copy1DRangeFrom(int off, int count, byte[] d) {
validateIsInt8();
copy1DRangeFromUnchecked(off, count, d);
}
+
+ /**
+ * Copy part of an allocation from an array. This variant is
+ * type checked and will generate exceptions if the Allocation
+ * type is not a 32 bit float type.
+ *
+ * @param off The offset of the first element to be copied.
+ * @param count The number of elements to be copied.
+ * @param d the source data array
+ */
public void copy1DRangeFrom(int off, int count, float[] d) {
validateIsFloat32();
copy1DRangeFromUnchecked(off, count, d);
diff --git a/graphics/java/android/renderscript/RenderScript.java b/graphics/java/android/renderscript/RenderScript.java
index 28b32d5..bb9fb78 100644
--- a/graphics/java/android/renderscript/RenderScript.java
+++ b/graphics/java/android/renderscript/RenderScript.java
@@ -101,414 +101,515 @@
}
native void rsnContextDestroy(int con);
synchronized void nContextDestroy() {
+ validate();
rsnContextDestroy(mContext);
}
native void rsnContextSetSurface(int con, int w, int h, Surface sur);
synchronized void nContextSetSurface(int w, int h, Surface sur) {
+ validate();
rsnContextSetSurface(mContext, w, h, sur);
}
native void rsnContextSetPriority(int con, int p);
synchronized void nContextSetPriority(int p) {
+ validate();
rsnContextSetPriority(mContext, p);
}
native void rsnContextDump(int con, int bits);
synchronized void nContextDump(int bits) {
+ validate();
rsnContextDump(mContext, bits);
}
native void rsnContextFinish(int con);
synchronized void nContextFinish() {
+ validate();
rsnContextFinish(mContext);
}
native void rsnContextBindRootScript(int con, int script);
synchronized void nContextBindRootScript(int script) {
+ validate();
rsnContextBindRootScript(mContext, script);
}
native void rsnContextBindSampler(int con, int sampler, int slot);
synchronized void nContextBindSampler(int sampler, int slot) {
+ validate();
rsnContextBindSampler(mContext, sampler, slot);
}
native void rsnContextBindProgramStore(int con, int pfs);
synchronized void nContextBindProgramStore(int pfs) {
+ validate();
rsnContextBindProgramStore(mContext, pfs);
}
native void rsnContextBindProgramFragment(int con, int pf);
synchronized void nContextBindProgramFragment(int pf) {
+ validate();
rsnContextBindProgramFragment(mContext, pf);
}
native void rsnContextBindProgramVertex(int con, int pv);
synchronized void nContextBindProgramVertex(int pv) {
+ validate();
rsnContextBindProgramVertex(mContext, pv);
}
native void rsnContextBindProgramRaster(int con, int pr);
synchronized void nContextBindProgramRaster(int pr) {
+ validate();
rsnContextBindProgramRaster(mContext, pr);
}
native void rsnContextPause(int con);
synchronized void nContextPause() {
+ validate();
rsnContextPause(mContext);
}
native void rsnContextResume(int con);
synchronized void nContextResume() {
+ validate();
rsnContextResume(mContext);
}
native void rsnAssignName(int con, int obj, byte[] name);
synchronized void nAssignName(int obj, byte[] name) {
+ validate();
rsnAssignName(mContext, obj, name);
}
native String rsnGetName(int con, int obj);
synchronized String nGetName(int obj) {
+ validate();
return rsnGetName(mContext, obj);
}
native void rsnObjDestroy(int con, int id);
synchronized void nObjDestroy(int id) {
- rsnObjDestroy(mContext, id);
+ // There is a race condition here. The calling code may be run
+ // by the gc while teardown is occuring. This protects againts
+ // deleting dead objects.
+ if (mContext != 0) {
+ rsnObjDestroy(mContext, id);
+ }
}
native int rsnElementCreate(int con, int type, int kind, boolean norm, int vecSize);
synchronized int nElementCreate(int type, int kind, boolean norm, int vecSize) {
+ validate();
return rsnElementCreate(mContext, type, kind, norm, vecSize);
}
native int rsnElementCreate2(int con, int[] elements, String[] names, int[] arraySizes);
synchronized int nElementCreate2(int[] elements, String[] names, int[] arraySizes) {
+ validate();
return rsnElementCreate2(mContext, elements, names, arraySizes);
}
native void rsnElementGetNativeData(int con, int id, int[] elementData);
synchronized void nElementGetNativeData(int id, int[] elementData) {
+ validate();
rsnElementGetNativeData(mContext, id, elementData);
}
native void rsnElementGetSubElements(int con, int id, int[] IDs, String[] names);
synchronized void nElementGetSubElements(int id, int[] IDs, String[] names) {
+ validate();
rsnElementGetSubElements(mContext, id, IDs, names);
}
native int rsnTypeCreate(int con, int eid, int x, int y, int z, boolean mips, boolean faces);
synchronized int nTypeCreate(int eid, int x, int y, int z, boolean mips, boolean faces) {
+ validate();
return rsnTypeCreate(mContext, eid, x, y, z, mips, faces);
}
native void rsnTypeGetNativeData(int con, int id, int[] typeData);
synchronized void nTypeGetNativeData(int id, int[] typeData) {
+ validate();
rsnTypeGetNativeData(mContext, id, typeData);
}
native int rsnAllocationCreateTyped(int con, int type, int mip, int usage);
synchronized int nAllocationCreateTyped(int type, int mip, int usage) {
+ validate();
return rsnAllocationCreateTyped(mContext, type, mip, usage);
}
native int rsnAllocationCreateFromBitmap(int con, int type, int mip, Bitmap bmp, int usage);
synchronized int nAllocationCreateFromBitmap(int type, int mip, Bitmap bmp, int usage) {
+ validate();
return rsnAllocationCreateFromBitmap(mContext, type, mip, bmp, usage);
}
native int rsnAllocationCubeCreateFromBitmap(int con, int type, int mip, Bitmap bmp, int usage);
synchronized int nAllocationCubeCreateFromBitmap(int type, int mip, Bitmap bmp, int usage) {
+ validate();
return rsnAllocationCubeCreateFromBitmap(mContext, type, mip, bmp, usage);
}
native int rsnAllocationCreateBitmapRef(int con, int type, Bitmap bmp);
synchronized int nAllocationCreateBitmapRef(int type, Bitmap bmp) {
+ validate();
return rsnAllocationCreateBitmapRef(mContext, type, bmp);
}
native int rsnAllocationCreateFromAssetStream(int con, int mips, int assetStream, int usage);
synchronized int nAllocationCreateFromAssetStream(int mips, int assetStream, int usage) {
+ validate();
return rsnAllocationCreateFromAssetStream(mContext, mips, assetStream, usage);
}
native void rsnAllocationCopyToBitmap(int con, int alloc, Bitmap bmp);
synchronized void nAllocationCopyToBitmap(int alloc, Bitmap bmp) {
+ validate();
rsnAllocationCopyToBitmap(mContext, alloc, bmp);
}
native void rsnAllocationSyncAll(int con, int alloc, int src);
synchronized void nAllocationSyncAll(int alloc, int src) {
+ validate();
rsnAllocationSyncAll(mContext, alloc, src);
}
native void rsnAllocationGenerateMipmaps(int con, int alloc);
synchronized void nAllocationGenerateMipmaps(int alloc) {
+ validate();
rsnAllocationGenerateMipmaps(mContext, alloc);
}
native void rsnAllocationCopyFromBitmap(int con, int alloc, Bitmap bmp);
synchronized void nAllocationCopyFromBitmap(int alloc, Bitmap bmp) {
+ validate();
rsnAllocationCopyFromBitmap(mContext, alloc, bmp);
}
native void rsnAllocationData1D(int con, int id, int off, int mip, int count, int[] d, int sizeBytes);
synchronized void nAllocationData1D(int id, int off, int mip, int count, int[] d, int sizeBytes) {
+ validate();
rsnAllocationData1D(mContext, id, off, mip, count, d, sizeBytes);
}
native void rsnAllocationData1D(int con, int id, int off, int mip, int count, short[] d, int sizeBytes);
synchronized void nAllocationData1D(int id, int off, int mip, int count, short[] d, int sizeBytes) {
+ validate();
rsnAllocationData1D(mContext, id, off, mip, count, d, sizeBytes);
}
native void rsnAllocationData1D(int con, int id, int off, int mip, int count, byte[] d, int sizeBytes);
synchronized void nAllocationData1D(int id, int off, int mip, int count, byte[] d, int sizeBytes) {
+ validate();
rsnAllocationData1D(mContext, id, off, mip, count, d, sizeBytes);
}
native void rsnAllocationData1D(int con, int id, int off, int mip, int count, float[] d, int sizeBytes);
synchronized void nAllocationData1D(int id, int off, int mip, int count, float[] d, int sizeBytes) {
+ validate();
rsnAllocationData1D(mContext, id, off, mip, count, d, sizeBytes);
}
native void rsnAllocationElementData1D(int con, int id, int xoff, int mip, int compIdx, byte[] d, int sizeBytes);
synchronized void nAllocationElementData1D(int id, int xoff, int mip, int compIdx, byte[] d, int sizeBytes) {
+ validate();
rsnAllocationElementData1D(mContext, id, xoff, mip, compIdx, d, sizeBytes);
}
native void rsnAllocationData2D(int con, int id, int xoff, int yoff, int mip, int face, int w, int h, byte[] d, int sizeBytes);
synchronized void nAllocationData2D(int id, int xoff, int yoff, int mip, int face, int w, int h, byte[] d, int sizeBytes) {
+ validate();
rsnAllocationData2D(mContext, id, xoff, yoff, mip, face, w, h, d, sizeBytes);
}
native void rsnAllocationData2D(int con, int id, int xoff, int yoff, int mip, int face, int w, int h, short[] d, int sizeBytes);
synchronized void nAllocationData2D(int id, int xoff, int yoff, int mip, int face, int w, int h, short[] d, int sizeBytes) {
+ validate();
rsnAllocationData2D(mContext, id, xoff, yoff, mip, face, w, h, d, sizeBytes);
}
native void rsnAllocationData2D(int con, int id, int xoff, int yoff, int mip, int face, int w, int h, int[] d, int sizeBytes);
synchronized void nAllocationData2D(int id, int xoff, int yoff, int mip, int face, int w, int h, int[] d, int sizeBytes) {
+ validate();
rsnAllocationData2D(mContext, id, xoff, yoff, mip, face, w, h, d, sizeBytes);
}
native void rsnAllocationData2D(int con, int id, int xoff, int yoff, int mip, int face, int w, int h, float[] d, int sizeBytes);
synchronized void nAllocationData2D(int id, int xoff, int yoff, int mip, int face, int w, int h, float[] d, int sizeBytes) {
+ validate();
rsnAllocationData2D(mContext, id, xoff, yoff, mip, face, w, h, d, sizeBytes);
}
native void rsnAllocationData2D(int con, int id, int xoff, int yoff, int mip, int face, Bitmap b);
synchronized void nAllocationData2D(int id, int xoff, int yoff, int mip, int face, Bitmap b) {
+ validate();
rsnAllocationData2D(mContext, id, xoff, yoff, mip, face, b);
}
native void rsnAllocationRead(int con, int id, byte[] d);
synchronized void nAllocationRead(int id, byte[] d) {
+ validate();
rsnAllocationRead(mContext, id, d);
}
native void rsnAllocationRead(int con, int id, short[] d);
synchronized void nAllocationRead(int id, short[] d) {
+ validate();
rsnAllocationRead(mContext, id, d);
}
native void rsnAllocationRead(int con, int id, int[] d);
synchronized void nAllocationRead(int id, int[] d) {
+ validate();
rsnAllocationRead(mContext, id, d);
}
native void rsnAllocationRead(int con, int id, float[] d);
synchronized void nAllocationRead(int id, float[] d) {
+ validate();
rsnAllocationRead(mContext, id, d);
}
native int rsnAllocationGetType(int con, int id);
synchronized int nAllocationGetType(int id) {
+ validate();
return rsnAllocationGetType(mContext, id);
}
native void rsnAllocationResize1D(int con, int id, int dimX);
synchronized void nAllocationResize1D(int id, int dimX) {
+ validate();
rsnAllocationResize1D(mContext, id, dimX);
}
native void rsnAllocationResize2D(int con, int id, int dimX, int dimY);
synchronized void nAllocationResize2D(int id, int dimX, int dimY) {
+ validate();
rsnAllocationResize2D(mContext, id, dimX, dimY);
}
native int rsnFileA3DCreateFromAssetStream(int con, int assetStream);
synchronized int nFileA3DCreateFromAssetStream(int assetStream) {
+ validate();
return rsnFileA3DCreateFromAssetStream(mContext, assetStream);
}
native int rsnFileA3DCreateFromFile(int con, String path);
synchronized int nFileA3DCreateFromFile(String path) {
+ validate();
return rsnFileA3DCreateFromFile(mContext, path);
}
native int rsnFileA3DCreateFromAsset(int con, AssetManager mgr, String path);
synchronized int nFileA3DCreateFromAsset(AssetManager mgr, String path) {
+ validate();
return rsnFileA3DCreateFromAsset(mContext, mgr, path);
}
native int rsnFileA3DGetNumIndexEntries(int con, int fileA3D);
synchronized int nFileA3DGetNumIndexEntries(int fileA3D) {
+ validate();
return rsnFileA3DGetNumIndexEntries(mContext, fileA3D);
}
native void rsnFileA3DGetIndexEntries(int con, int fileA3D, int numEntries, int[] IDs, String[] names);
synchronized void nFileA3DGetIndexEntries(int fileA3D, int numEntries, int[] IDs, String[] names) {
+ validate();
rsnFileA3DGetIndexEntries(mContext, fileA3D, numEntries, IDs, names);
}
native int rsnFileA3DGetEntryByIndex(int con, int fileA3D, int index);
synchronized int nFileA3DGetEntryByIndex(int fileA3D, int index) {
+ validate();
return rsnFileA3DGetEntryByIndex(mContext, fileA3D, index);
}
native int rsnFontCreateFromFile(int con, String fileName, float size, int dpi);
synchronized int nFontCreateFromFile(String fileName, float size, int dpi) {
+ validate();
return rsnFontCreateFromFile(mContext, fileName, size, dpi);
}
native int rsnFontCreateFromAssetStream(int con, String name, float size, int dpi, int assetStream);
synchronized int nFontCreateFromAssetStream(String name, float size, int dpi, int assetStream) {
+ validate();
return rsnFontCreateFromAssetStream(mContext, name, size, dpi, assetStream);
}
native int rsnFontCreateFromAsset(int con, AssetManager mgr, String path, float size, int dpi);
synchronized int nFontCreateFromAsset(AssetManager mgr, String path, float size, int dpi) {
+ validate();
return rsnFontCreateFromAsset(mContext, mgr, path, size, dpi);
}
native void rsnScriptBindAllocation(int con, int script, int alloc, int slot);
synchronized void nScriptBindAllocation(int script, int alloc, int slot) {
+ validate();
rsnScriptBindAllocation(mContext, script, alloc, slot);
}
native void rsnScriptSetTimeZone(int con, int script, byte[] timeZone);
synchronized void nScriptSetTimeZone(int script, byte[] timeZone) {
+ validate();
rsnScriptSetTimeZone(mContext, script, timeZone);
}
native void rsnScriptInvoke(int con, int id, int slot);
synchronized void nScriptInvoke(int id, int slot) {
+ validate();
rsnScriptInvoke(mContext, id, slot);
}
native void rsnScriptInvokeV(int con, int id, int slot, byte[] params);
synchronized void nScriptInvokeV(int id, int slot, byte[] params) {
+ validate();
rsnScriptInvokeV(mContext, id, slot, params);
}
native void rsnScriptSetVarI(int con, int id, int slot, int val);
synchronized void nScriptSetVarI(int id, int slot, int val) {
+ validate();
rsnScriptSetVarI(mContext, id, slot, val);
}
native void rsnScriptSetVarJ(int con, int id, int slot, long val);
synchronized void nScriptSetVarJ(int id, int slot, long val) {
+ validate();
rsnScriptSetVarJ(mContext, id, slot, val);
}
native void rsnScriptSetVarF(int con, int id, int slot, float val);
synchronized void nScriptSetVarF(int id, int slot, float val) {
+ validate();
rsnScriptSetVarF(mContext, id, slot, val);
}
native void rsnScriptSetVarD(int con, int id, int slot, double val);
synchronized void nScriptSetVarD(int id, int slot, double val) {
+ validate();
rsnScriptSetVarD(mContext, id, slot, val);
}
native void rsnScriptSetVarV(int con, int id, int slot, byte[] val);
synchronized void nScriptSetVarV(int id, int slot, byte[] val) {
+ validate();
rsnScriptSetVarV(mContext, id, slot, val);
}
native void rsnScriptSetVarObj(int con, int id, int slot, int val);
synchronized void nScriptSetVarObj(int id, int slot, int val) {
+ validate();
rsnScriptSetVarObj(mContext, id, slot, val);
}
native void rsnScriptCBegin(int con);
synchronized void nScriptCBegin() {
+ validate();
rsnScriptCBegin(mContext);
}
native void rsnScriptCSetScript(int con, byte[] script, int offset, int length);
synchronized void nScriptCSetScript(byte[] script, int offset, int length) {
+ validate();
rsnScriptCSetScript(mContext, script, offset, length);
}
native int rsnScriptCCreate(int con, String packageName, String resName, String cacheDir);
synchronized int nScriptCCreate(String packageName, String resName, String cacheDir) {
+ validate();
return rsnScriptCCreate(mContext, packageName, resName, cacheDir);
}
native void rsnSamplerBegin(int con);
synchronized void nSamplerBegin() {
+ validate();
rsnSamplerBegin(mContext);
}
native void rsnSamplerSet(int con, int param, int value);
synchronized void nSamplerSet(int param, int value) {
+ validate();
rsnSamplerSet(mContext, param, value);
}
native void rsnSamplerSet2(int con, int param, float value);
synchronized void nSamplerSet2(int param, float value) {
+ validate();
rsnSamplerSet2(mContext, param, value);
}
native int rsnSamplerCreate(int con);
synchronized int nSamplerCreate() {
+ validate();
return rsnSamplerCreate(mContext);
}
native void rsnProgramStoreBegin(int con, int in, int out);
synchronized void nProgramStoreBegin(int in, int out) {
+ validate();
rsnProgramStoreBegin(mContext, in, out);
}
native void rsnProgramStoreDepthFunc(int con, int func);
synchronized void nProgramStoreDepthFunc(int func) {
+ validate();
rsnProgramStoreDepthFunc(mContext, func);
}
native void rsnProgramStoreDepthMask(int con, boolean enable);
synchronized void nProgramStoreDepthMask(boolean enable) {
+ validate();
rsnProgramStoreDepthMask(mContext, enable);
}
native void rsnProgramStoreColorMask(int con, boolean r, boolean g, boolean b, boolean a);
synchronized void nProgramStoreColorMask(boolean r, boolean g, boolean b, boolean a) {
+ validate();
rsnProgramStoreColorMask(mContext, r, g, b, a);
}
native void rsnProgramStoreBlendFunc(int con, int src, int dst);
synchronized void nProgramStoreBlendFunc(int src, int dst) {
+ validate();
rsnProgramStoreBlendFunc(mContext, src, dst);
}
native void rsnProgramStoreDither(int con, boolean enable);
synchronized void nProgramStoreDither(boolean enable) {
+ validate();
rsnProgramStoreDither(mContext, enable);
}
native int rsnProgramStoreCreate(int con);
synchronized int nProgramStoreCreate() {
+ validate();
return rsnProgramStoreCreate(mContext);
}
native int rsnProgramRasterCreate(int con, boolean pointSmooth, boolean lineSmooth, boolean pointSprite);
synchronized int nProgramRasterCreate(boolean pointSmooth, boolean lineSmooth, boolean pointSprite) {
+ validate();
return rsnProgramRasterCreate(mContext, pointSmooth, lineSmooth, pointSprite);
}
native void rsnProgramRasterSetLineWidth(int con, int pr, float v);
synchronized void nProgramRasterSetLineWidth(int pr, float v) {
+ validate();
rsnProgramRasterSetLineWidth(mContext, pr, v);
}
native void rsnProgramRasterSetCullMode(int con, int pr, int mode);
synchronized void nProgramRasterSetCullMode(int pr, int mode) {
+ validate();
rsnProgramRasterSetCullMode(mContext, pr, mode);
}
native void rsnProgramBindConstants(int con, int pv, int slot, int mID);
synchronized void nProgramBindConstants(int pv, int slot, int mID) {
+ validate();
rsnProgramBindConstants(mContext, pv, slot, mID);
}
native void rsnProgramBindTexture(int con, int vpf, int slot, int a);
synchronized void nProgramBindTexture(int vpf, int slot, int a) {
+ validate();
rsnProgramBindTexture(mContext, vpf, slot, a);
}
native void rsnProgramBindSampler(int con, int vpf, int slot, int s);
synchronized void nProgramBindSampler(int vpf, int slot, int s) {
+ validate();
rsnProgramBindSampler(mContext, vpf, slot, s);
}
native int rsnProgramFragmentCreate(int con, String shader, int[] params);
synchronized int nProgramFragmentCreate(String shader, int[] params) {
+ validate();
return rsnProgramFragmentCreate(mContext, shader, params);
}
native int rsnProgramVertexCreate(int con, String shader, int[] params);
synchronized int nProgramVertexCreate(String shader, int[] params) {
+ validate();
return rsnProgramVertexCreate(mContext, shader, params);
}
native int rsnMeshCreate(int con, int vtxCount, int indexCount);
synchronized int nMeshCreate(int vtxCount, int indexCount) {
+ validate();
return rsnMeshCreate(mContext, vtxCount, indexCount);
}
native void rsnMeshBindVertex(int con, int id, int alloc, int slot);
synchronized void nMeshBindVertex(int id, int alloc, int slot) {
+ validate();
rsnMeshBindVertex(mContext, id, alloc, slot);
}
native void rsnMeshBindIndex(int con, int id, int alloc, int prim, int slot);
synchronized void nMeshBindIndex(int id, int alloc, int prim, int slot) {
+ validate();
rsnMeshBindIndex(mContext, id, alloc, prim, slot);
}
native void rsnMeshInitVertexAttribs(int con, int id);
synchronized void nMeshInitVertexAttribs(int id) {
+ validate();
rsnMeshInitVertexAttribs(mContext, id);
}
native int rsnMeshGetVertexBufferCount(int con, int id);
synchronized int nMeshGetVertexBufferCount(int id) {
+ validate();
return rsnMeshGetVertexBufferCount(mContext, id);
}
native int rsnMeshGetIndexCount(int con, int id);
synchronized int nMeshGetIndexCount(int id) {
+ validate();
return rsnMeshGetIndexCount(mContext, id);
}
native void rsnMeshGetVertices(int con, int id, int[] vtxIds, int vtxIdCount);
synchronized void nMeshGetVertices(int id, int[] vtxIds, int vtxIdCount) {
+ validate();
rsnMeshGetVertices(mContext, id, vtxIds, vtxIdCount);
}
native void rsnMeshGetIndices(int con, int id, int[] idxIds, int[] primitives, int vtxIdCount);
synchronized void nMeshGetIndices(int id, int[] idxIds, int[] primitives, int vtxIdCount) {
+ validate();
rsnMeshGetIndices(mContext, id, idxIds, primitives, vtxIdCount);
}
diff --git a/graphics/java/android/renderscript/ScriptC.java b/graphics/java/android/renderscript/ScriptC.java
index ff8f093..9445283 100644
--- a/graphics/java/android/renderscript/ScriptC.java
+++ b/graphics/java/android/renderscript/ScriptC.java
@@ -56,6 +56,9 @@
protected ScriptC(RenderScript rs, Resources resources, int resourceID) {
super(0, rs);
int id = internalCreate(rs, resources, resourceID);
+ if (id == 0) {
+ throw new RSRuntimeException("Loading of ScriptC script failed.");
+ }
setID(id);
}
diff --git a/graphics/jni/android_renderscript_RenderScript.cpp b/graphics/jni/android_renderscript_RenderScript.cpp
index 35db786..f86343a 100644
--- a/graphics/jni/android_renderscript_RenderScript.cpp
+++ b/graphics/jni/android_renderscript_RenderScript.cpp
@@ -991,7 +991,7 @@
jint *paramPtr = _env->GetIntArrayElements(params, NULL);
jint paramLen = _env->GetArrayLength(params);
- LOG_API("nProgramFragmentCreate, con(%p), shaderLen(%i), paramLen(%i)", con, shaderLen, paramLen);
+ LOG_API("nProgramFragmentCreate, con(%p), paramLen(%i)", con, paramLen);
jint ret = (jint)rsProgramFragmentCreate(con, shaderUTF.c_str(), shaderUTF.length(), (uint32_t *)paramPtr, paramLen);
_env->ReleaseIntArrayElements(params, paramPtr, JNI_ABORT);
@@ -1008,7 +1008,7 @@
jint *paramPtr = _env->GetIntArrayElements(params, NULL);
jint paramLen = _env->GetArrayLength(params);
- LOG_API("nProgramVertexCreate, con(%p), shaderLen(%i), paramLen(%i)", con, shaderLen, paramLen);
+ LOG_API("nProgramVertexCreate, con(%p), paramLen(%i)", con, paramLen);
jint ret = (jint)rsProgramVertexCreate(con, shaderUTF.c_str(), shaderUTF.length(), (uint32_t *)paramPtr, paramLen);
_env->ReleaseIntArrayElements(params, paramPtr, JNI_ABORT);
diff --git a/include/media/stagefright/MetaData.h b/include/media/stagefright/MetaData.h
index 5170a2c..18fd90e 100644
--- a/include/media/stagefright/MetaData.h
+++ b/include/media/stagefright/MetaData.h
@@ -30,8 +30,10 @@
// The following keys map to int32_t data unless indicated otherwise.
enum {
kKeyMIMEType = 'mime', // cstring
- kKeyWidth = 'widt', // int32_t
- kKeyHeight = 'heig', // int32_t
+ kKeyWidth = 'widt', // int32_t, image pixel
+ kKeyHeight = 'heig', // int32_t, image pixel
+ kKeyDisplayWidth = 'dWid', // int32_t, display/presentation
+ kKeyDisplayHeight = 'dHgt', // int32_t, display/presentation
// a rectangle, if absent assumed to be (0, 0, width - 1, height - 1)
kKeyCropRect = 'crop',
diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp
index c080501..c43e40d 100644
--- a/libs/hwui/FontRenderer.cpp
+++ b/libs/hwui/FontRenderer.cpp
@@ -298,8 +298,10 @@
// FontRenderer
///////////////////////////////////////////////////////////////////////////////
+static bool sLogFontRendererCreate = true;
+
FontRenderer::FontRenderer() {
- LOGD("Creating FontRenderer");
+ if (sLogFontRendererCreate) LOGD("Creating FontRenderer");
mGammaTable = NULL;
mInitialized = false;
@@ -317,18 +319,24 @@
char property[PROPERTY_VALUE_MAX];
if (property_get(PROPERTY_TEXT_CACHE_WIDTH, property, NULL) > 0) {
- LOGD(" Setting text cache width to %s pixels", property);
+ if (sLogFontRendererCreate) LOGD(" Setting text cache width to %s pixels", property);
mCacheWidth = atoi(property);
} else {
- LOGD(" Using default text cache width of %i pixels", mCacheWidth);
+ if (sLogFontRendererCreate) {
+ LOGD(" Using default text cache width of %i pixels", mCacheWidth);
+ }
}
if (property_get(PROPERTY_TEXT_CACHE_HEIGHT, property, NULL) > 0) {
- LOGD(" Setting text cache width to %s pixels", property);
+ if (sLogFontRendererCreate) LOGD(" Setting text cache width to %s pixels", property);
mCacheHeight = atoi(property);
} else {
- LOGD(" Using default text cache height of %i pixels", mCacheHeight);
+ if (sLogFontRendererCreate) {
+ LOGD(" Using default text cache height of %i pixels", mCacheHeight);
+ }
}
+
+ sLogFontRendererCreate = false;
}
FontRenderer::~FontRenderer() {
diff --git a/libs/hwui/LayerRenderer.cpp b/libs/hwui/LayerRenderer.cpp
index e6bea78..a167429 100644
--- a/libs/hwui/LayerRenderer.cpp
+++ b/libs/hwui/LayerRenderer.cpp
@@ -29,7 +29,6 @@
void LayerRenderer::prepare(bool opaque) {
LAYER_RENDERER_LOGD("Rendering into layer, fbo = %d", mLayer->fbo);
- glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint*) &mPreviousFbo);
glBindFramebuffer(GL_FRAMEBUFFER, mLayer->fbo);
OpenGLRenderer::prepare(opaque);
@@ -37,11 +36,17 @@
void LayerRenderer::finish() {
OpenGLRenderer::finish();
- glBindFramebuffer(GL_FRAMEBUFFER, mPreviousFbo);
generateMesh();
LAYER_RENDERER_LOGD("Finished rendering into layer, fbo = %d", mLayer->mFbo);
+
+ // No need to unbind our FBO, this will be taken care of by the caller
+ // who will invoke OpenGLRenderer::resume()
+}
+
+GLint LayerRenderer::getTargetFbo() {
+ return mLayer->fbo;
}
///////////////////////////////////////////////////////////////////////////////
diff --git a/libs/hwui/LayerRenderer.h b/libs/hwui/LayerRenderer.h
index f2fb898..1e39847 100644
--- a/libs/hwui/LayerRenderer.h
+++ b/libs/hwui/LayerRenderer.h
@@ -51,6 +51,7 @@
bool hasLayer();
Region* getRegion();
+ GLint getTargetFbo();
static Layer* createLayer(uint32_t width, uint32_t height, bool isOpaque = false);
static bool resizeLayer(Layer* layer, uint32_t width, uint32_t height);
@@ -61,8 +62,6 @@
void generateMesh();
Layer* mLayer;
- GLuint mPreviousFbo;
-
}; // class LayerRenderer
}; // namespace uirenderer
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 2067acc1..6477eb0 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -200,7 +200,7 @@
glDisable(GL_DITHER);
- glBindFramebuffer(GL_FRAMEBUFFER, 0);
+ glBindFramebuffer(GL_FRAMEBUFFER, getTargetFbo());
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
mCaches.blend = true;
@@ -430,18 +430,18 @@
} else {
// Copy the framebuffer into the layer
glBindTexture(GL_TEXTURE_2D, layer->texture);
-
- if (layer->empty) {
- glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, bounds.left,
- snapshot->height - bounds.bottom, layer->width, layer->height, 0);
- layer->empty = false;
- } else {
- glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, bounds.left,
- snapshot->height - bounds.bottom, bounds.getWidth(), bounds.getHeight());
+ if (!bounds.isEmpty()) {
+ if (layer->empty) {
+ glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, bounds.left,
+ snapshot->height - bounds.bottom, layer->width, layer->height, 0);
+ layer->empty = false;
+ } else {
+ glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, bounds.left,
+ snapshot->height - bounds.bottom, bounds.getWidth(), bounds.getHeight());
+ }
+ // Enqueue the buffer coordinates to clear the corresponding region later
+ mLayers.push(new Rect(bounds));
}
-
- // Enqueue the buffer coordinates to clear the corresponding region later
- mLayers.push(new Rect(bounds));
}
return true;
@@ -565,8 +565,10 @@
resetColorFilter();
}
} else {
- dirtyLayer(rect.left, rect.top, rect.right, rect.bottom);
- composeLayerRect(layer, rect, true);
+ if (!rect.isEmpty()) {
+ dirtyLayer(rect.left, rect.top, rect.right, rect.bottom);
+ composeLayerRect(layer, rect, true);
+ }
}
if (fboLayer) {
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index 272c5c2..4150ddc 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -145,14 +145,27 @@
return mSnapshot;
}
+ /**
+ * Returns the region of the current layer.
+ */
virtual Region* getRegion() {
return mSnapshot->region;
}
+ /**
+ * Indicates whether rendering is currently targeted at a layer.
+ */
virtual bool hasLayer() {
return (mSnapshot->flags & Snapshot::kFlagFboTarget) && mSnapshot->region;
}
+ /**
+ * Returns the name of the FBO this renderer is rendering into.
+ */
+ virtual GLint getTargetFbo() {
+ return 0;
+ }
+
private:
/**
* Saves the current state of the renderer as a new snapshot.
diff --git a/libs/hwui/Patch.cpp b/libs/hwui/Patch.cpp
index 3f0036a..11eb953 100644
--- a/libs/hwui/Patch.cpp
+++ b/libs/hwui/Patch.cpp
@@ -177,8 +177,10 @@
previousStepY = stepY;
}
- generateRow(vertex, y1, bottom - top, v1, 1.0f, stretchX, right - left,
- bitmapWidth, quadCount);
+ if (previousStepY != bitmapHeight) {
+ generateRow(vertex, y1, bottom - top, v1, 1.0f, stretchX, right - left,
+ bitmapWidth, quadCount);
+ }
if (verticesCount > 0) {
Caches::getInstance().bindMeshBuffer(meshBuffer);
@@ -225,7 +227,9 @@
previousStepX = stepX;
}
- generateQuad(vertex, x1, y1, width, y2, u1, v1, 1.0f, v2, quadCount);
+ if (previousStepX != bitmapWidth) {
+ generateQuad(vertex, x1, y1, width, y2, u1, v1, 1.0f, v2, quadCount);
+ }
}
void Patch::generateQuad(TextureVertex*& vertex, float x1, float y1, float x2, float y2,
diff --git a/libs/rs/java/tests/src/com/android/rs/test/RSTestCore.java b/libs/rs/java/tests/src/com/android/rs/test/RSTestCore.java
index fc3a065..541bf22 100644
--- a/libs/rs/java/tests/src/com/android/rs/test/RSTestCore.java
+++ b/libs/rs/java/tests/src/com/android/rs/test/RSTestCore.java
@@ -68,6 +68,7 @@
unitTests.add(new UT_rsdebug(this, mRes, mCtx));
unitTests.add(new UT_rstime(this, mRes, mCtx));
unitTests.add(new UT_rstypes(this, mRes, mCtx));
+ unitTests.add(new UT_math(this, mRes, mCtx));
unitTests.add(new UT_fp_mad(this, mRes, mCtx));
/*
unitTests.add(new UnitTest(null, "<Pass>", 1));
diff --git a/libs/rs/java/tests/src/com/android/rs/test/UT_math.java b/libs/rs/java/tests/src/com/android/rs/test/UT_math.java
new file mode 100644
index 0000000..bf133be
--- /dev/null
+++ b/libs/rs/java/tests/src/com/android/rs/test/UT_math.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.rs.test;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.renderscript.*;
+
+public class UT_math extends UnitTest {
+ private Resources mRes;
+
+ protected UT_math(RSTestCore rstc, Resources res, Context ctx) {
+ super(rstc, "Math", ctx);
+ mRes = res;
+ }
+
+ public void run() {
+ RenderScript pRS = RenderScript.create(mCtx);
+ ScriptC_math s = new ScriptC_math(pRS, mRes, R.raw.math);
+ pRS.setMessageHandler(mRsMessage);
+ s.invoke_math_test(0, 0);
+ pRS.finish();
+ waitForMessage();
+ pRS.destroy();
+ }
+}
diff --git a/libs/rs/java/tests/src/com/android/rs/test/fp_mad.rs b/libs/rs/java/tests/src/com/android/rs/test/fp_mad.rs
index 4133fda..b02f85d 100644
--- a/libs/rs/java/tests/src/com/android/rs/test/fp_mad.rs
+++ b/libs/rs/java/tests/src/com/android/rs/test/fp_mad.rs
@@ -102,7 +102,8 @@
start();
// Do ~100 M ops
- for (int ct=0; ct < 1000 * 100; ct++) {
+ int ct;
+ for (ct=0; ct < 1000 * 100; ct++) {
for (int i=0; i < (1000); i++) {
data_f1[i] = clamp(data_f1[i], -1.f, 1.f);
}
@@ -129,7 +130,8 @@
float total = 0;
// Do ~100 M ops
- for (int ct=0; ct < 1000 * 100 /4; ct++) {
+ int ct;
+ for (ct=0; ct < 1000 * 100 /4; ct++) {
for (int i=0; i < (1000); i++) {
data_f4[i] = clamp(data_f4[i], -1.f, 1.f);
}
@@ -140,7 +142,8 @@
}
void fp_mad_test(uint32_t index, int test_num) {
- for (int x=0; x < 1025; x++) {
+ int x;
+ for (x=0; x < 1025; x++) {
data_f1[x] = (x & 0xf) * 0.1f;
data_f4[x].x = (x & 0xf) * 0.1f;
data_f4[x].y = (x & 0xf0) * 0.1f;
diff --git a/libs/rs/java/tests/src/com/android/rs/test/math.rs b/libs/rs/java/tests/src/com/android/rs/test/math.rs
new file mode 100644
index 0000000..5b1ad15
--- /dev/null
+++ b/libs/rs/java/tests/src/com/android/rs/test/math.rs
@@ -0,0 +1,65 @@
+#include "shared.rsh"
+
+// Testing math library
+
+volatile float f1;
+volatile float2 f2;
+volatile float3 f3;
+volatile float4 f4;
+
+#define TEST_F(fnc, var) \
+ rsDebug("Testing " #fnc, 0); \
+ var##1 = fnc(var##1); \
+ var##2 = fnc(var##2); \
+ var##3 = fnc(var##3); \
+ var##4 = fnc(var##4);
+
+#define TEST_FP(fnc, var) \
+ rsDebug("Testing " #fnc, 0); \
+ var##1 = fnc(var##1, (float*) &f1); \
+ var##2 = fnc(var##2, (float2*) &f2); \
+ var##3 = fnc(var##3, (float3*) &f3); \
+ var##4 = fnc(var##4, (float4*) &f4);
+
+#define TEST_F2(fnc, var) \
+ rsDebug("Testing " #fnc, 0); \
+ var##1 = fnc(var##1, var##1); \
+ var##2 = fnc(var##2, var##2); \
+ var##3 = fnc(var##3, var##3); \
+ var##4 = fnc(var##4, var##4);
+
+static bool test_math(uint32_t index) {
+ bool failed = false;
+ start();
+
+ TEST_F(cos, f);
+ TEST_FP(modf, f);
+ TEST_F2(pow, f);
+ TEST_F(sin, f);
+ TEST_F(sqrt, f);
+
+
+ float time = end(index);
+
+ if (failed) {
+ rsDebug("test_math FAILED", time);
+ }
+ else {
+ rsDebug("test_math PASSED", time);
+ }
+
+ return failed;
+}
+
+void math_test(uint32_t index, int test_num) {
+ bool failed = false;
+ failed |= test_math(index);
+
+ if (failed) {
+ rsSendToClientBlocking(RS_MSG_TEST_FAILED);
+ }
+ else {
+ rsSendToClientBlocking(RS_MSG_TEST_PASSED);
+ }
+}
+
diff --git a/libs/rs/rsContext.cpp b/libs/rs/rsContext.cpp
index 2e0c491..98f30ae 100644
--- a/libs/rs/rsContext.cpp
+++ b/libs/rs/rsContext.cpp
@@ -253,7 +253,11 @@
LOGV("%p, deinitEGL", this);
if (mEGL.mContext != EGL_NO_CONTEXT) {
- eglMakeCurrent(mEGL.mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, mEGL.mContext);
+ eglMakeCurrent(mEGL.mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+ eglDestroySurface(mEGL.mDisplay, mEGL.mSurfaceDefault);
+ if (mEGL.mSurface != EGL_NO_SURFACE) {
+ eglDestroySurface(mEGL.mDisplay, mEGL.mSurface);
+ }
eglDestroyContext(mEGL.mDisplay, mEGL.mContext);
checkEglError("eglDestroyContext");
}
diff --git a/libs/rs/rsLocklessFifo.cpp b/libs/rs/rsLocklessFifo.cpp
index 804c767..eb2af1c 100644
--- a/libs/rs/rsLocklessFifo.cpp
+++ b/libs/rs/rsLocklessFifo.cpp
@@ -210,3 +210,19 @@
void LocklessCommandFifo::dumpState(const char *s) const {
LOGV("%s %p put %p, get %p, buf %p, end %p", s, this, mPut, mGet, mBuffer, mEnd);
}
+
+void LocklessCommandFifo::printDebugData() const {
+ dumpState("printing fifo debug");
+ const uint32_t *pptr = (const uint32_t *)mGet;
+ pptr -= 8 * 4;
+ if (mGet < mBuffer) {
+ pptr = (const uint32_t *)mBuffer;
+ }
+
+
+ for (int ct=0; ct < 16; ct++) {
+ LOGV("fifo %p = 0x%08x 0x%08x 0x%08x 0x%08x", pptr, pptr[0], pptr[1], pptr[2], pptr[3]);
+ pptr += 4;
+ }
+
+}
diff --git a/libs/rs/rsLocklessFifo.h b/libs/rs/rsLocklessFifo.h
index c963963..eabdc3e 100644
--- a/libs/rs/rsLocklessFifo.h
+++ b/libs/rs/rsLocklessFifo.h
@@ -35,6 +35,8 @@
bool init(uint32_t size);
void shutdown();
+ void printDebugData() const;
+
LocklessCommandFifo();
~LocklessCommandFifo();
diff --git a/libs/rs/rsScriptC.cpp b/libs/rs/rsScriptC.cpp
index 9f730bf..1fceb66 100644
--- a/libs/rs/rsScriptC.cpp
+++ b/libs/rs/rsScriptC.cpp
@@ -467,7 +467,7 @@
extern unsigned rs_runtime_lib_bc_size;
#endif
-void ScriptCState::runCompiler(Context *rsc,
+bool ScriptCState::runCompiler(Context *rsc,
ScriptC *s,
const char *resName,
const char *cacheDir) {
@@ -482,7 +482,7 @@
s->mEnviroment.mScriptText,
s->mEnviroment.mScriptTextLength, 0) != 0) {
LOGE("bcc: FAILS to read bitcode");
- // Handle Fatal Error
+ return false;
}
#if 1
@@ -493,14 +493,14 @@
/*"1" means skip buffer here, and let libbcc decide*/,
0) != 0) {
LOGE("bcc: FAILS to link bitcode");
- // Handle Fatal Error
+ return false;
}
#endif
char *cachePath = genCacheFileName(cacheDir, resName, ".oBCC");
if (bccPrepareExecutable(s->mBccScript, cachePath, 0) != 0) {
LOGE("bcc: FAILS to prepare executable");
- // Handle Fatal Error
+ return false;
}
free(cachePath);
@@ -547,7 +547,7 @@
continue;
}
LOGE("Invalid version pragma value: %s\n", values[i]);
- // Handle Fatal Error
+ return false;
}
if (!strcmp(keys[i], "stateVertex")) {
@@ -559,7 +559,7 @@
continue;
}
LOGE("Unrecognized value %s passed to stateVertex", values[i]);
- // Handle Fatal Error
+ return false;
}
if (!strcmp(keys[i], "stateRaster")) {
@@ -571,7 +571,7 @@
continue;
}
LOGE("Unrecognized value %s passed to stateRaster", values[i]);
- // Handle Fatal Error
+ return false;
}
if (!strcmp(keys[i], "stateFragment")) {
@@ -583,7 +583,7 @@
continue;
}
LOGE("Unrecognized value %s passed to stateFragment", values[i]);
- // Handle Fatal Error
+ return false;
}
if (!strcmp(keys[i], "stateStore")) {
@@ -595,9 +595,10 @@
continue;
}
LOGE("Unrecognized value %s passed to stateStore", values[i]);
- // Handle Fatal Error
+ return false;
}
}
+ return true;
}
namespace android {
@@ -630,7 +631,11 @@
ss->mScript.clear();
s->incUserRef();
- ss->runCompiler(rsc, s.get(), resName, cacheDir);
+ if (!ss->runCompiler(rsc, s.get(), resName, cacheDir)) {
+ // Error during compile, destroy s and return null.
+ s->zeroUserRef();
+ return NULL;
+ }
ss->clear(rsc);
return s.get();
}
diff --git a/libs/rs/rsScriptC.h b/libs/rs/rsScriptC.h
index 483481e8..612e38a 100644
--- a/libs/rs/rsScriptC.h
+++ b/libs/rs/rsScriptC.h
@@ -81,7 +81,7 @@
void init(Context *rsc);
void clear(Context *rsc);
- void runCompiler(Context *rsc, ScriptC *s, const char *resName, const char *cacheDir);
+ bool runCompiler(Context *rsc, ScriptC *s, const char *resName, const char *cacheDir);
struct SymbolTable_t {
const char * mName;
diff --git a/libs/rs/rsScriptC_Lib.cpp b/libs/rs/rsScriptC_Lib.cpp
index 0b21669..f550d98 100644
--- a/libs/rs/rsScriptC_Lib.cpp
+++ b/libs/rs/rsScriptC_Lib.cpp
@@ -226,51 +226,51 @@
}
static void SC_debugF(const char *s, float f) {
- LOGE("%s %f, 0x%08x", s, f, *((int *) (&f)));
+ LOGD("%s %f, 0x%08x", s, f, *((int *) (&f)));
}
static void SC_debugFv2(const char *s, float f1, float f2) {
- LOGE("%s {%f, %f}", s, f1, f2);
+ LOGD("%s {%f, %f}", s, f1, f2);
}
static void SC_debugFv3(const char *s, float f1, float f2, float f3) {
- LOGE("%s {%f, %f, %f}", s, f1, f2, f3);
+ LOGD("%s {%f, %f, %f}", s, f1, f2, f3);
}
static void SC_debugFv4(const char *s, float f1, float f2, float f3, float f4) {
- LOGE("%s {%f, %f, %f, %f}", s, f1, f2, f3, f4);
+ LOGD("%s {%f, %f, %f, %f}", s, f1, f2, f3, f4);
}
static void SC_debugD(const char *s, double d) {
- LOGE("%s %f, 0x%08llx", s, d, *((long long *) (&d)));
+ LOGD("%s %f, 0x%08llx", s, d, *((long long *) (&d)));
}
static void SC_debugFM4v4(const char *s, const float *f) {
- LOGE("%s {%f, %f, %f, %f", s, f[0], f[4], f[8], f[12]);
- LOGE("%s %f, %f, %f, %f", s, f[1], f[5], f[9], f[13]);
- LOGE("%s %f, %f, %f, %f", s, f[2], f[6], f[10], f[14]);
- LOGE("%s %f, %f, %f, %f}", s, f[3], f[7], f[11], f[15]);
+ LOGD("%s {%f, %f, %f, %f", s, f[0], f[4], f[8], f[12]);
+ LOGD("%s %f, %f, %f, %f", s, f[1], f[5], f[9], f[13]);
+ LOGD("%s %f, %f, %f, %f", s, f[2], f[6], f[10], f[14]);
+ LOGD("%s %f, %f, %f, %f}", s, f[3], f[7], f[11], f[15]);
}
static void SC_debugFM3v3(const char *s, const float *f) {
- LOGE("%s {%f, %f, %f", s, f[0], f[3], f[6]);
- LOGE("%s %f, %f, %f", s, f[1], f[4], f[7]);
- LOGE("%s %f, %f, %f}",s, f[2], f[5], f[8]);
+ LOGD("%s {%f, %f, %f", s, f[0], f[3], f[6]);
+ LOGD("%s %f, %f, %f", s, f[1], f[4], f[7]);
+ LOGD("%s %f, %f, %f}",s, f[2], f[5], f[8]);
}
static void SC_debugFM2v2(const char *s, const float *f) {
- LOGE("%s {%f, %f", s, f[0], f[2]);
- LOGE("%s %f, %f}",s, f[1], f[3]);
+ LOGD("%s {%f, %f", s, f[0], f[2]);
+ LOGD("%s %f, %f}",s, f[1], f[3]);
}
static void SC_debugI32(const char *s, int32_t i) {
- LOGE("%s %i 0x%x", s, i, i);
+ LOGD("%s %i 0x%x", s, i, i);
}
static void SC_debugU32(const char *s, uint32_t i) {
- LOGE("%s %u 0x%x", s, i, i);
+ LOGD("%s %u 0x%x", s, i, i);
}
static void SC_debugLL64(const char *s, long long ll) {
- LOGE("%s %lld 0x%llx", s, ll, ll);
+ LOGD("%s %lld 0x%llx", s, ll, ll);
}
static void SC_debugULL64(const char *s, unsigned long long ll) {
- LOGE("%s %llu 0x%llx", s, ll, ll);
+ LOGD("%s %llu 0x%llx", s, ll, ll);
}
static void SC_debugP(const char *s, const void *p) {
- LOGE("%s %p", s, p);
+ LOGD("%s %p", s, p);
}
static uint32_t SC_toClient2(int cmdID, void *data, int len) {
diff --git a/libs/rs/rsScriptC_LibCL.cpp b/libs/rs/rsScriptC_LibCL.cpp
index 6c0e164..28c558d 100644
--- a/libs/rs/rsScriptC_LibCL.cpp
+++ b/libs/rs/rsScriptC_LibCL.cpp
@@ -221,7 +221,7 @@
{ "_Z5log1pf", (void *)&log1pf, true },
//{ "logb", (void *)&, true },
//{ "mad", (void *)&, true },
- { "modf", (void *)&modff, true },
+ { "_Z4modffPf", (void *)&modff, true },
//{ "nan", (void *)&, true },
{ "_Z9nextafterff", (void *)&nextafterf, true },
{ "_Z3powff", (void *)&powf, true },
diff --git a/libs/rs/rsThreadIO.cpp b/libs/rs/rsThreadIO.cpp
index 001ac55..6cf07de7 100644
--- a/libs/rs/rsThreadIO.cpp
+++ b/libs/rs/rsThreadIO.cpp
@@ -56,6 +56,7 @@
if (cmdID >= (sizeof(gPlaybackFuncs) / sizeof(void *))) {
rsAssert(cmdID < (sizeof(gPlaybackFuncs) / sizeof(void *)));
LOGE("playCoreCommands error con %p, cmd %i", con, cmdID);
+ mToCore.printDebugData();
}
gPlaybackFuncs[cmdID](con, data);
mToCore.next();
diff --git a/libs/rs/scriptc/rs_cl.rsh b/libs/rs/scriptc/rs_cl.rsh
index b9bb1f7..ab8270f40 100644
--- a/libs/rs/scriptc/rs_cl.rsh
+++ b/libs/rs/scriptc/rs_cl.rsh
@@ -1,20 +1,23 @@
#ifndef __RS_CL_RSH__
#define __RS_CL_RSH__
-#define M_PI 3.14159265358979323846264338327950288f /* pi */
-
+#ifdef BCC_PREPARE_BC
+#define _RS_STATIC extern
+#else
+#define _RS_STATIC static
+#endif
// Conversions
#define CVT_FUNC_2(typeout, typein) \
-static typeout##2 __attribute__((overloadable)) convert_##typeout##2(typein##2 v) { \
+_RS_STATIC typeout##2 __attribute__((overloadable)) convert_##typeout##2(typein##2 v) { \
typeout##2 r = {(typeout)v.x, (typeout)v.y}; \
return r; \
} \
-static typeout##3 __attribute__((overloadable)) convert_##typeout##3(typein##3 v) { \
+_RS_STATIC typeout##3 __attribute__((overloadable)) convert_##typeout##3(typein##3 v) { \
typeout##3 r = {(typeout)v.x, (typeout)v.y, (typeout)v.z}; \
return r; \
} \
-static typeout##4 __attribute__((overloadable)) convert_##typeout##4(typein##4 v) { \
+_RS_STATIC typeout##4 __attribute__((overloadable)) convert_##typeout##4(typein##4 v) { \
typeout##4 r = {(typeout)v.x, (typeout)v.y, (typeout)v.z, (typeout)v.w}; \
return r; \
}
@@ -40,20 +43,20 @@
// Float ops, 6.11.2
#define DEF_FUNC_1(fnc) \
-static float2 __attribute__((overloadable)) fnc(float2 v) { \
+_RS_STATIC float2 __attribute__((overloadable)) fnc(float2 v) { \
float2 r; \
r.x = fnc(v.x); \
r.y = fnc(v.y); \
return r; \
} \
-static float3 __attribute__((overloadable)) fnc(float3 v) { \
+_RS_STATIC float3 __attribute__((overloadable)) fnc(float3 v) { \
float3 r; \
r.x = fnc(v.x); \
r.y = fnc(v.y); \
r.z = fnc(v.z); \
return r; \
} \
-static float4 __attribute__((overloadable)) fnc(float4 v) { \
+_RS_STATIC float4 __attribute__((overloadable)) fnc(float4 v) { \
float4 r; \
r.x = fnc(v.x); \
r.y = fnc(v.y); \
@@ -63,20 +66,20 @@
}
#define DEF_FUNC_1_RI(fnc) \
-static int2 __attribute__((overloadable)) fnc(float2 v) { \
+_RS_STATIC int2 __attribute__((overloadable)) fnc(float2 v) { \
int2 r; \
r.x = fnc(v.x); \
r.y = fnc(v.y); \
return r; \
} \
-static int3 __attribute__((overloadable)) fnc(float3 v) { \
+_RS_STATIC int3 __attribute__((overloadable)) fnc(float3 v) { \
int3 r; \
r.x = fnc(v.x); \
r.y = fnc(v.y); \
r.z = fnc(v.z); \
return r; \
} \
-static int4 __attribute__((overloadable)) fnc(float4 v) { \
+_RS_STATIC int4 __attribute__((overloadable)) fnc(float4 v) { \
int4 r; \
r.x = fnc(v.x); \
r.y = fnc(v.y); \
@@ -86,43 +89,43 @@
}
#define DEF_FUNC_2(fnc) \
-static float2 __attribute__((overloadable)) fnc(float2 v1, float2 v2) { \
+_RS_STATIC float2 __attribute__((overloadable)) fnc(float2 v1, float2 v2) { \
float2 r; \
r.x = fnc(v1.x, v2.x); \
r.y = fnc(v1.y, v2.y); \
return r; \
} \
-static float3 __attribute__((overloadable)) fnc(float3 v1, float3 v2) { \
+_RS_STATIC float3 __attribute__((overloadable)) fnc(float3 v1, float3 v2) { \
float3 r; \
r.x = fnc(v1.x, v2.x); \
r.y = fnc(v1.y, v2.y); \
r.z = fnc(v1.z, v2.z); \
return r; \
} \
-static float4 __attribute__((overloadable)) fnc(float4 v1, float4 v2) { \
+_RS_STATIC float4 __attribute__((overloadable)) fnc(float4 v1, float4 v2) { \
float4 r; \
r.x = fnc(v1.x, v2.x); \
r.y = fnc(v1.y, v2.y); \
r.z = fnc(v1.z, v2.z); \
- r.w = fnc(v1.w, v2.z); \
+ r.w = fnc(v1.w, v2.w); \
return r; \
}
#define DEF_FUNC_2F(fnc) \
-static float2 __attribute__((overloadable)) fnc(float2 v1, float v2) { \
+_RS_STATIC float2 __attribute__((overloadable)) fnc(float2 v1, float v2) { \
float2 r; \
r.x = fnc(v1.x, v2); \
r.y = fnc(v1.y, v2); \
return r; \
} \
-static float3 __attribute__((overloadable)) fnc(float3 v1, float v2) { \
+_RS_STATIC float3 __attribute__((overloadable)) fnc(float3 v1, float v2) { \
float3 r; \
r.x = fnc(v1.x, v2); \
r.y = fnc(v1.y, v2); \
r.z = fnc(v1.z, v2); \
return r; \
} \
-static float4 __attribute__((overloadable)) fnc(float4 v1, float v2) { \
+_RS_STATIC float4 __attribute__((overloadable)) fnc(float4 v1, float v2) { \
float4 r; \
r.x = fnc(v1.x, v2); \
r.y = fnc(v1.y, v2); \
@@ -131,6 +134,40 @@
return r; \
}
+#define DEF_FUNC_2P(fnc) \
+_RS_STATIC float2 __attribute__((overloadable)) fnc(float2 v1, float2 *v2) { \
+ float2 r; \
+ float q; \
+ r.x = fnc(v1.x, &q); \
+ v2->x = q; \
+ r.y = fnc(v1.y, &q); \
+ v2->y = q; \
+ return r; \
+} \
+_RS_STATIC float3 __attribute__((overloadable)) fnc(float3 v1, float3 *v2) { \
+ float3 r; \
+ float q; \
+ r.x = fnc(v1.x, &q); \
+ v2->x = q; \
+ r.y = fnc(v1.y, &q); \
+ v2->y = q; \
+ r.z = fnc(v1.z, &q); \
+ v2->z = q; \
+ return r; \
+} \
+_RS_STATIC float4 __attribute__((overloadable)) fnc(float4 v1, float4 *v2) { \
+ float4 r; \
+ float q; \
+ r.x = fnc(v1.x, &q); \
+ v2->x = q; \
+ r.y = fnc(v1.y, &q); \
+ v2->y = q; \
+ r.z = fnc(v1.z, &q); \
+ v2->z = q; \
+ r.w = fnc(v1.w, &q); \
+ v2->w = q; \
+ return r; \
+}
extern float __attribute__((overloadable)) acos(float);
DEF_FUNC_1(acos)
@@ -138,7 +175,7 @@
extern float __attribute__((overloadable)) acosh(float);
DEF_FUNC_1(acosh)
-static float __attribute__((overloadable)) acospi(float v) {
+_RS_STATIC float __attribute__((overloadable)) acospi(float v) {
return acos(v) / M_PI;
}
DEF_FUNC_1(acospi)
@@ -149,7 +186,7 @@
extern float __attribute__((overloadable)) asinh(float);
DEF_FUNC_1(asinh)
-static float __attribute__((overloadable)) asinpi(float v) {
+_RS_STATIC float __attribute__((overloadable)) asinpi(float v) {
return asin(v) / M_PI;
}
DEF_FUNC_1(asinpi)
@@ -163,12 +200,12 @@
extern float __attribute__((overloadable)) atanh(float);
DEF_FUNC_1(atanh)
-static float __attribute__((overloadable)) atanpi(float v) {
+_RS_STATIC float __attribute__((overloadable)) atanpi(float v) {
return atan(v) / M_PI;
}
DEF_FUNC_1(atanpi)
-static float __attribute__((overloadable)) atan2pi(float y, float x) {
+_RS_STATIC float __attribute__((overloadable)) atan2pi(float y, float x) {
return atan2(y, x) / M_PI;
}
DEF_FUNC_2(atan2pi)
@@ -188,7 +225,7 @@
extern float __attribute__((overloadable)) cosh(float);
DEF_FUNC_1(cosh)
-static float __attribute__((overloadable)) cospi(float v) {
+_RS_STATIC float __attribute__((overloadable)) cospi(float v) {
return cos(v * M_PI);
}
DEF_FUNC_1(cospi)
@@ -206,7 +243,7 @@
DEF_FUNC_1(exp2)
extern float __attribute__((overloadable)) pow(float, float);
-static float __attribute__((overloadable)) exp10(float v) {
+_RS_STATIC float __attribute__((overloadable)) exp10(float v) {
return pow(10.f, v);
}
DEF_FUNC_1(exp10)
@@ -239,12 +276,12 @@
extern float __attribute__((overloadable)) fmod(float, float);
DEF_FUNC_2(fmod)
-static float __attribute__((overloadable)) fract(float v, float *iptr) {
+_RS_STATIC float __attribute__((overloadable)) fract(float v, float *iptr) {
int i = (int)floor(v);
iptr[0] = i;
return fmin(v - i, 0x1.fffffep-1f);
}
-static float2 __attribute__((overloadable)) fract(float2 v, float2 *iptr) {
+_RS_STATIC float2 __attribute__((overloadable)) fract(float2 v, float2 *iptr) {
float t[2];
float2 r;
r.x = fract(v.x, &t[0]);
@@ -253,7 +290,7 @@
iptr[1] = t[1];
return r;
}
-static float3 __attribute__((overloadable)) fract(float3 v, float3 *iptr) {
+_RS_STATIC float3 __attribute__((overloadable)) fract(float3 v, float3 *iptr) {
float t[3];
float3 r;
r.x = fract(v.x, &t[0]);
@@ -264,7 +301,7 @@
iptr[2] = t[2];
return r;
}
-static float4 __attribute__((overloadable)) fract(float4 v, float4 *iptr) {
+_RS_STATIC float4 __attribute__((overloadable)) fract(float4 v, float4 *iptr) {
float t[4];
float4 r;
r.x = fract(v.x, &t[0]);
@@ -311,7 +348,7 @@
extern float __attribute__((overloadable)) log10(float);
DEF_FUNC_1(log10)
-static float __attribute__((overloadable)) log2(float v) {
+_RS_STATIC float __attribute__((overloadable)) log2(float v) {
return log10(v) / log10(2.f);
}
DEF_FUNC_1(log2)
@@ -328,9 +365,7 @@
extern float4 __attribute__((overloadable)) mad(float4, float4, float4);
extern float __attribute__((overloadable)) modf(float, float *);
-extern float2 __attribute__((overloadable)) modf(float2, float2 *);
-extern float3 __attribute__((overloadable)) modf(float3, float3 *);
-extern float4 __attribute__((overloadable)) modf(float4, float4 *);
+DEF_FUNC_2P(modf);
//extern float __attribute__((overloadable)) nan(uint);
@@ -339,29 +374,29 @@
DEF_FUNC_2(pow)
-static float __attribute__((overloadable)) pown(float v, int p) {
+_RS_STATIC float __attribute__((overloadable)) pown(float v, int p) {
return pow(v, (float)p);
}
-static float2 __attribute__((overloadable)) pown(float2 v, int2 p) {
+_RS_STATIC float2 __attribute__((overloadable)) pown(float2 v, int2 p) {
return pow(v, (float2)p);
}
-static float3 __attribute__((overloadable)) pown(float3 v, int3 p) {
+_RS_STATIC float3 __attribute__((overloadable)) pown(float3 v, int3 p) {
return pow(v, (float3)p);
}
-static float4 __attribute__((overloadable)) pown(float4 v, int4 p) {
+_RS_STATIC float4 __attribute__((overloadable)) pown(float4 v, int4 p) {
return pow(v, (float4)p);
}
-static float __attribute__((overloadable)) powr(float v, float p) {
+_RS_STATIC float __attribute__((overloadable)) powr(float v, float p) {
return pow(v, p);
}
-static float2 __attribute__((overloadable)) powr(float2 v, float2 p) {
+_RS_STATIC float2 __attribute__((overloadable)) powr(float2 v, float2 p) {
return pow(v, p);
}
-static float3 __attribute__((overloadable)) powr(float3 v, float3 p) {
+_RS_STATIC float3 __attribute__((overloadable)) powr(float3 v, float3 p) {
return pow(v, p);
}
-static float4 __attribute__((overloadable)) powr(float4 v, float4 p) {
+_RS_STATIC float4 __attribute__((overloadable)) powr(float4 v, float4 p) {
return pow(v, p);
}
@@ -376,18 +411,18 @@
extern float __attribute__((overloadable)) rint(float);
DEF_FUNC_1(rint)
-static float __attribute__((overloadable)) rootn(float v, int r) {
+_RS_STATIC float __attribute__((overloadable)) rootn(float v, int r) {
return pow(v, 1.f / r);
}
-static float2 __attribute__((overloadable)) rootn(float2 v, int2 r) {
+_RS_STATIC float2 __attribute__((overloadable)) rootn(float2 v, int2 r) {
float2 t = {1.f / r.x, 1.f / r.y};
return pow(v, t);
}
-static float3 __attribute__((overloadable)) rootn(float3 v, int3 r) {
+_RS_STATIC float3 __attribute__((overloadable)) rootn(float3 v, int3 r) {
float3 t = {1.f / r.x, 1.f / r.y, 1.f / r.z};
return pow(v, t);
}
-static float4 __attribute__((overloadable)) rootn(float4 v, int4 r) {
+_RS_STATIC float4 __attribute__((overloadable)) rootn(float4 v, int4 r) {
float4 t = {1.f / r.x, 1.f / r.y, 1.f / r.z, 1.f / r.w};
return pow(v, t);
}
@@ -396,7 +431,7 @@
DEF_FUNC_1(round)
extern float __attribute__((overloadable)) sqrt(float);
-static float __attribute__((overloadable)) rsqrt(float v) {
+_RS_STATIC float __attribute__((overloadable)) rsqrt(float v) {
return 1.f / sqrt(v);
}
DEF_FUNC_1(rsqrt)
@@ -404,19 +439,19 @@
extern float __attribute__((overloadable)) sin(float);
DEF_FUNC_1(sin)
-static float __attribute__((overloadable)) sincos(float v, float *cosptr) {
+_RS_STATIC float __attribute__((overloadable)) sincos(float v, float *cosptr) {
*cosptr = cos(v);
return sin(v);
}
-static float2 __attribute__((overloadable)) sincos(float2 v, float2 *cosptr) {
+_RS_STATIC float2 __attribute__((overloadable)) sincos(float2 v, float2 *cosptr) {
*cosptr = cos(v);
return sin(v);
}
-static float3 __attribute__((overloadable)) sincos(float3 v, float3 *cosptr) {
+_RS_STATIC float3 __attribute__((overloadable)) sincos(float3 v, float3 *cosptr) {
*cosptr = cos(v);
return sin(v);
}
-static float4 __attribute__((overloadable)) sincos(float4 v, float4 *cosptr) {
+_RS_STATIC float4 __attribute__((overloadable)) sincos(float4 v, float4 *cosptr) {
*cosptr = cos(v);
return sin(v);
}
@@ -424,7 +459,7 @@
extern float __attribute__((overloadable)) sinh(float);
DEF_FUNC_1(sinh)
-static float __attribute__((overloadable)) sinpi(float v) {
+_RS_STATIC float __attribute__((overloadable)) sinpi(float v) {
return sin(v * M_PI);
}
DEF_FUNC_1(sinpi)
@@ -437,7 +472,7 @@
extern float __attribute__((overloadable)) tanh(float);
DEF_FUNC_1(tanh)
-static float __attribute__((overloadable)) tanpi(float v) {
+_RS_STATIC float __attribute__((overloadable)) tanpi(float v) {
return tan(v * M_PI);
}
DEF_FUNC_1(tanpi)
@@ -452,20 +487,20 @@
#define DEF_RIFUNC_1(typeout, typein, fnc) \
extern typeout __attribute__((overloadable)) fnc(typein); \
-static typeout##2 __attribute__((overloadable)) fnc(typein##2 v) { \
+_RS_STATIC typeout##2 __attribute__((overloadable)) fnc(typein##2 v) { \
typeout##2 r; \
r.x = fnc(v.x); \
r.y = fnc(v.y); \
return r; \
} \
-static typeout##3 __attribute__((overloadable)) fnc(typein##3 v) { \
+_RS_STATIC typeout##3 __attribute__((overloadable)) fnc(typein##3 v) { \
typeout##3 r; \
r.x = fnc(v.x); \
r.y = fnc(v.y); \
r.z = fnc(v.z); \
return r; \
} \
-static typeout##4 __attribute__((overloadable)) fnc(typein##4 v) { \
+_RS_STATIC typeout##4 __attribute__((overloadable)) fnc(typein##4 v) { \
typeout##4 r; \
r.x = fnc(v.x); \
r.y = fnc(v.y); \
@@ -488,23 +523,23 @@
DEF_RIFUNC_1(int, int, fnc)
#define DEF_RIFUNC_2(type, fnc, body) \
-static type __attribute__((overloadable)) fnc(type v1, type v2) { \
+_RS_STATIC type __attribute__((overloadable)) fnc(type v1, type v2) { \
return body; \
} \
-static type##2 __attribute__((overloadable)) fnc(type##2 v1, type##2 v2) { \
+_RS_STATIC type##2 __attribute__((overloadable)) fnc(type##2 v1, type##2 v2) { \
type##2 r; \
r.x = fnc(v1.x, v2.x); \
r.y = fnc(v1.y, v2.y); \
return r; \
} \
-static type##3 __attribute__((overloadable)) fnc(type##3 v1, type##3 v2) { \
+_RS_STATIC type##3 __attribute__((overloadable)) fnc(type##3 v1, type##3 v2) { \
type##3 r; \
r.x = fnc(v1.x, v2.x); \
r.y = fnc(v1.y, v2.y); \
r.z = fnc(v1.z, v2.z); \
return r; \
} \
-static type##4 __attribute__((overloadable)) fnc(type##4 v1, type##4 v2) { \
+_RS_STATIC type##4 __attribute__((overloadable)) fnc(type##4 v1, type##4 v2) { \
type##4 r; \
r.x = fnc(v1.x, v2.x); \
r.y = fnc(v1.y, v2.y); \
@@ -533,23 +568,23 @@
// 6.11.4
-static float __attribute__((overloadable)) clamp(float amount, float low, float high) {
+_RS_STATIC float __attribute__((overloadable)) clamp(float amount, float low, float high) {
return amount < low ? low : (amount > high ? high : amount);
}
-static float2 __attribute__((overloadable)) clamp(float2 amount, float2 low, float2 high) {
+_RS_STATIC float2 __attribute__((overloadable)) clamp(float2 amount, float2 low, float2 high) {
float2 r;
r.x = amount.x < low.x ? low.x : (amount.x > high.x ? high.x : amount.x);
r.y = amount.y < low.y ? low.y : (amount.y > high.y ? high.y : amount.y);
return r;
}
-static float3 __attribute__((overloadable)) clamp(float3 amount, float3 low, float3 high) {
+_RS_STATIC float3 __attribute__((overloadable)) clamp(float3 amount, float3 low, float3 high) {
float3 r;
r.x = amount.x < low.x ? low.x : (amount.x > high.x ? high.x : amount.x);
r.y = amount.y < low.y ? low.y : (amount.y > high.y ? high.y : amount.y);
r.z = amount.z < low.z ? low.z : (amount.z > high.z ? high.z : amount.z);
return r;
}
-static float4 __attribute__((overloadable)) clamp(float4 amount, float4 low, float4 high) {
+_RS_STATIC float4 __attribute__((overloadable)) clamp(float4 amount, float4 low, float4 high) {
float4 r;
r.x = amount.x < low.x ? low.x : (amount.x > high.x ? high.x : amount.x);
r.y = amount.y < low.y ? low.y : (amount.y > high.y ? high.y : amount.y);
@@ -557,20 +592,20 @@
r.w = amount.w < low.w ? low.w : (amount.w > high.w ? high.w : amount.w);
return r;
}
-static float2 __attribute__((overloadable)) clamp(float2 amount, float low, float high) {
+_RS_STATIC float2 __attribute__((overloadable)) clamp(float2 amount, float low, float high) {
float2 r;
r.x = amount.x < low ? low : (amount.x > high ? high : amount.x);
r.y = amount.y < low ? low : (amount.y > high ? high : amount.y);
return r;
}
-static float3 __attribute__((overloadable)) clamp(float3 amount, float low, float high) {
+_RS_STATIC float3 __attribute__((overloadable)) clamp(float3 amount, float low, float high) {
float3 r;
r.x = amount.x < low ? low : (amount.x > high ? high : amount.x);
r.y = amount.y < low ? low : (amount.y > high ? high : amount.y);
r.z = amount.z < low ? low : (amount.z > high ? high : amount.z);
return r;
}
-static float4 __attribute__((overloadable)) clamp(float4 amount, float low, float high) {
+_RS_STATIC float4 __attribute__((overloadable)) clamp(float4 amount, float low, float high) {
float4 r;
r.x = amount.x < low ? low : (amount.x > high ? high : amount.x);
r.y = amount.y < low ? low : (amount.y > high ? high : amount.y);
@@ -579,55 +614,55 @@
return r;
}
-static float __attribute__((overloadable)) degrees(float radians) {
+_RS_STATIC float __attribute__((overloadable)) degrees(float radians) {
return radians * (180.f / M_PI);
}
DEF_FUNC_1(degrees)
-static float __attribute__((overloadable)) mix(float start, float stop, float amount) {
+_RS_STATIC float __attribute__((overloadable)) mix(float start, float stop, float amount) {
return start + (stop - start) * amount;
}
-static float2 __attribute__((overloadable)) mix(float2 start, float2 stop, float2 amount) {
+_RS_STATIC float2 __attribute__((overloadable)) mix(float2 start, float2 stop, float2 amount) {
return start + (stop - start) * amount;
}
-static float3 __attribute__((overloadable)) mix(float3 start, float3 stop, float3 amount) {
+_RS_STATIC float3 __attribute__((overloadable)) mix(float3 start, float3 stop, float3 amount) {
return start + (stop - start) * amount;
}
-static float4 __attribute__((overloadable)) mix(float4 start, float4 stop, float4 amount) {
+_RS_STATIC float4 __attribute__((overloadable)) mix(float4 start, float4 stop, float4 amount) {
return start + (stop - start) * amount;
}
-static float2 __attribute__((overloadable)) mix(float2 start, float2 stop, float amount) {
+_RS_STATIC float2 __attribute__((overloadable)) mix(float2 start, float2 stop, float amount) {
return start + (stop - start) * amount;
}
-static float3 __attribute__((overloadable)) mix(float3 start, float3 stop, float amount) {
+_RS_STATIC float3 __attribute__((overloadable)) mix(float3 start, float3 stop, float amount) {
return start + (stop - start) * amount;
}
-static float4 __attribute__((overloadable)) mix(float4 start, float4 stop, float amount) {
+_RS_STATIC float4 __attribute__((overloadable)) mix(float4 start, float4 stop, float amount) {
return start + (stop - start) * amount;
}
-static float __attribute__((overloadable)) radians(float degrees) {
+_RS_STATIC float __attribute__((overloadable)) radians(float degrees) {
return degrees * (M_PI / 180.f);
}
DEF_FUNC_1(radians)
-static float __attribute__((overloadable)) step(float edge, float v) {
+_RS_STATIC float __attribute__((overloadable)) step(float edge, float v) {
return (v < edge) ? 0.f : 1.f;
}
-static float2 __attribute__((overloadable)) step(float2 edge, float2 v) {
+_RS_STATIC float2 __attribute__((overloadable)) step(float2 edge, float2 v) {
float2 r;
r.x = (v.x < edge.x) ? 0.f : 1.f;
r.y = (v.y < edge.y) ? 0.f : 1.f;
return r;
}
-static float3 __attribute__((overloadable)) step(float3 edge, float3 v) {
+_RS_STATIC float3 __attribute__((overloadable)) step(float3 edge, float3 v) {
float3 r;
r.x = (v.x < edge.x) ? 0.f : 1.f;
r.y = (v.y < edge.y) ? 0.f : 1.f;
r.z = (v.z < edge.z) ? 0.f : 1.f;
return r;
}
-static float4 __attribute__((overloadable)) step(float4 edge, float4 v) {
+_RS_STATIC float4 __attribute__((overloadable)) step(float4 edge, float4 v) {
float4 r;
r.x = (v.x < edge.x) ? 0.f : 1.f;
r.y = (v.y < edge.y) ? 0.f : 1.f;
@@ -635,20 +670,20 @@
r.w = (v.w < edge.w) ? 0.f : 1.f;
return r;
}
-static float2 __attribute__((overloadable)) step(float2 edge, float v) {
+_RS_STATIC float2 __attribute__((overloadable)) step(float2 edge, float v) {
float2 r;
r.x = (v < edge.x) ? 0.f : 1.f;
r.y = (v < edge.y) ? 0.f : 1.f;
return r;
}
-static float3 __attribute__((overloadable)) step(float3 edge, float v) {
+_RS_STATIC float3 __attribute__((overloadable)) step(float3 edge, float v) {
float3 r;
r.x = (v < edge.x) ? 0.f : 1.f;
r.y = (v < edge.y) ? 0.f : 1.f;
r.z = (v < edge.z) ? 0.f : 1.f;
return r;
}
-static float4 __attribute__((overloadable)) step(float4 edge, float v) {
+_RS_STATIC float4 __attribute__((overloadable)) step(float4 edge, float v) {
float4 r;
r.x = (v < edge.x) ? 0.f : 1.f;
r.y = (v < edge.y) ? 0.f : 1.f;
@@ -665,7 +700,7 @@
extern float3 __attribute__((overloadable)) smoothstep(float, float, float3);
extern float4 __attribute__((overloadable)) smoothstep(float, float, float4);
-static float __attribute__((overloadable)) sign(float v) {
+_RS_STATIC float __attribute__((overloadable)) sign(float v) {
if (v > 0) return 1.f;
if (v < 0) return -1.f;
return v;
@@ -673,7 +708,7 @@
DEF_FUNC_1(sign)
// 6.11.5
-static float3 __attribute__((overloadable)) cross(float3 lhs, float3 rhs) {
+_RS_STATIC float3 __attribute__((overloadable)) cross(float3 lhs, float3 rhs) {
float3 r;
r.x = lhs.y * rhs.z - lhs.z * rhs.y;
r.y = lhs.z * rhs.x - lhs.x * rhs.z;
@@ -681,7 +716,7 @@
return r;
}
-static float4 __attribute__((overloadable)) cross(float4 lhs, float4 rhs) {
+_RS_STATIC float4 __attribute__((overloadable)) cross(float4 lhs, float4 rhs) {
float4 r;
r.x = lhs.y * rhs.z - lhs.z * rhs.y;
r.y = lhs.z * rhs.x - lhs.x * rhs.z;
@@ -690,55 +725,55 @@
return r;
}
-static float __attribute__((overloadable)) dot(float lhs, float rhs) {
+_RS_STATIC float __attribute__((overloadable)) dot(float lhs, float rhs) {
return lhs * rhs;
}
-static float __attribute__((overloadable)) dot(float2 lhs, float2 rhs) {
+_RS_STATIC float __attribute__((overloadable)) dot(float2 lhs, float2 rhs) {
return lhs.x*rhs.x + lhs.y*rhs.y;
}
-static float __attribute__((overloadable)) dot(float3 lhs, float3 rhs) {
+_RS_STATIC float __attribute__((overloadable)) dot(float3 lhs, float3 rhs) {
return lhs.x*rhs.x + lhs.y*rhs.y + lhs.z*rhs.z;
}
-static float __attribute__((overloadable)) dot(float4 lhs, float4 rhs) {
+_RS_STATIC float __attribute__((overloadable)) dot(float4 lhs, float4 rhs) {
return lhs.x*rhs.x + lhs.y*rhs.y + lhs.z*rhs.z + lhs.w*rhs.w;
}
-static float __attribute__((overloadable)) length(float v) {
+_RS_STATIC float __attribute__((overloadable)) length(float v) {
return v;
}
-static float __attribute__((overloadable)) length(float2 v) {
+_RS_STATIC float __attribute__((overloadable)) length(float2 v) {
return sqrt(v.x*v.x + v.y*v.y);
}
-static float __attribute__((overloadable)) length(float3 v) {
+_RS_STATIC float __attribute__((overloadable)) length(float3 v) {
return sqrt(v.x*v.x + v.y*v.y + v.z*v.z);
}
-static float __attribute__((overloadable)) length(float4 v) {
+_RS_STATIC float __attribute__((overloadable)) length(float4 v) {
return sqrt(v.x*v.x + v.y*v.y + v.z*v.z + v.w*v.w);
}
-static float __attribute__((overloadable)) distance(float lhs, float rhs) {
+_RS_STATIC float __attribute__((overloadable)) distance(float lhs, float rhs) {
return length(lhs - rhs);
}
-static float __attribute__((overloadable)) distance(float2 lhs, float2 rhs) {
+_RS_STATIC float __attribute__((overloadable)) distance(float2 lhs, float2 rhs) {
return length(lhs - rhs);
}
-static float __attribute__((overloadable)) distance(float3 lhs, float3 rhs) {
+_RS_STATIC float __attribute__((overloadable)) distance(float3 lhs, float3 rhs) {
return length(lhs - rhs);
}
-static float __attribute__((overloadable)) distance(float4 lhs, float4 rhs) {
+_RS_STATIC float __attribute__((overloadable)) distance(float4 lhs, float4 rhs) {
return length(lhs - rhs);
}
-static float __attribute__((overloadable)) normalize(float v) {
+_RS_STATIC float __attribute__((overloadable)) normalize(float v) {
return 1.f;
}
-static float2 __attribute__((overloadable)) normalize(float2 v) {
+_RS_STATIC float2 __attribute__((overloadable)) normalize(float2 v) {
return v / length(v);
}
-static float3 __attribute__((overloadable)) normalize(float3 v) {
+_RS_STATIC float3 __attribute__((overloadable)) normalize(float3 v) {
return v / length(v);
}
-static float4 __attribute__((overloadable)) normalize(float4 v) {
+_RS_STATIC float4 __attribute__((overloadable)) normalize(float4 v) {
return v / length(v);
}
@@ -753,5 +788,6 @@
#undef DEF_IFUNC_1
#undef DEF_RIFUNC_2
#undef DEF_IFUNC_2
+#undef _RS_STATIC
#endif
diff --git a/libs/rs/scriptc/rs_core.rsh b/libs/rs/scriptc/rs_core.rsh
index 16482c1..f3e0ab0 100644
--- a/libs/rs/scriptc/rs_core.rsh
+++ b/libs/rs/scriptc/rs_core.rsh
@@ -1,6 +1,12 @@
#ifndef __RS_CORE_RSH__
#define __RS_CORE_RSH__
+#ifdef BCC_PREPARE_BC
+#define _RS_STATIC extern
+#else
+#define _RS_STATIC static
+#endif
+
// Debugging, print to the LOG a description string and a value.
extern void __attribute__((overloadable))
rsDebug(const char *, float);
@@ -35,17 +41,17 @@
#define RS_DEBUG(a) rsDebug(#a, a)
#define RS_DEBUG_MARKER rsDebug(__FILE__, __LINE__)
-static void __attribute__((overloadable)) rsDebug(const char *s, float2 v) {
+_RS_STATIC void __attribute__((overloadable)) rsDebug(const char *s, float2 v) {
rsDebug(s, v.x, v.y);
}
-static void __attribute__((overloadable)) rsDebug(const char *s, float3 v) {
+_RS_STATIC void __attribute__((overloadable)) rsDebug(const char *s, float3 v) {
rsDebug(s, v.x, v.y, v.z);
}
-static void __attribute__((overloadable)) rsDebug(const char *s, float4 v) {
+_RS_STATIC void __attribute__((overloadable)) rsDebug(const char *s, float4 v) {
rsDebug(s, v.x, v.y, v.z, v.w);
}
-static uchar4 __attribute__((overloadable)) rsPackColorTo8888(float r, float g, float b)
+_RS_STATIC uchar4 __attribute__((overloadable)) rsPackColorTo8888(float r, float g, float b)
{
uchar4 c;
c.x = (uchar)(r * 255.f);
@@ -55,7 +61,7 @@
return c;
}
-static uchar4 __attribute__((overloadable)) rsPackColorTo8888(float r, float g, float b, float a)
+_RS_STATIC uchar4 __attribute__((overloadable)) rsPackColorTo8888(float r, float g, float b, float a)
{
uchar4 c;
c.x = (uchar)(r * 255.f);
@@ -65,21 +71,21 @@
return c;
}
-static uchar4 __attribute__((overloadable)) rsPackColorTo8888(float3 color)
+_RS_STATIC uchar4 __attribute__((overloadable)) rsPackColorTo8888(float3 color)
{
color *= 255.f;
uchar4 c = {color.x, color.y, color.z, 255};
return c;
}
-static uchar4 __attribute__((overloadable)) rsPackColorTo8888(float4 color)
+_RS_STATIC uchar4 __attribute__((overloadable)) rsPackColorTo8888(float4 color)
{
color *= 255.f;
uchar4 c = {color.x, color.y, color.z, color.w};
return c;
}
-static float4 rsUnpackColor8888(uchar4 c)
+_RS_STATIC float4 rsUnpackColor8888(uchar4 c)
{
float4 ret = (float4)0.0039156862745f;
ret *= convert_float4(c);
@@ -95,37 +101,37 @@
// Matrix ops
/////////////////////////////////////////////////////
-static void __attribute__((overloadable))
+_RS_STATIC void __attribute__((overloadable))
rsMatrixSet(rs_matrix4x4 *m, uint32_t row, uint32_t col, float v) {
m->m[row * 4 + col] = v;
}
-static float __attribute__((overloadable))
+_RS_STATIC float __attribute__((overloadable))
rsMatrixGet(const rs_matrix4x4 *m, uint32_t row, uint32_t col) {
return m->m[row * 4 + col];
}
-static void __attribute__((overloadable))
+_RS_STATIC void __attribute__((overloadable))
rsMatrixSet(rs_matrix3x3 *m, uint32_t row, uint32_t col, float v) {
m->m[row * 3 + col] = v;
}
-static float __attribute__((overloadable))
+_RS_STATIC float __attribute__((overloadable))
rsMatrixGet(const rs_matrix3x3 *m, uint32_t row, uint32_t col) {
return m->m[row * 3 + col];
}
-static void __attribute__((overloadable))
+_RS_STATIC void __attribute__((overloadable))
rsMatrixSet(rs_matrix2x2 *m, uint32_t row, uint32_t col, float v) {
m->m[row * 2 + col] = v;
}
-static float __attribute__((overloadable))
+_RS_STATIC float __attribute__((overloadable))
rsMatrixGet(const rs_matrix2x2 *m, uint32_t row, uint32_t col) {
return m->m[row * 2 + col];
}
-static void __attribute__((overloadable))
+_RS_STATIC void __attribute__((overloadable))
rsMatrixLoadIdentity(rs_matrix4x4 *m) {
m->m[0] = 1.f;
m->m[1] = 0.f;
@@ -145,7 +151,7 @@
m->m[15] = 1.f;
}
-static void __attribute__((overloadable))
+_RS_STATIC void __attribute__((overloadable))
rsMatrixLoadIdentity(rs_matrix3x3 *m) {
m->m[0] = 1.f;
m->m[1] = 0.f;
@@ -158,7 +164,7 @@
m->m[8] = 1.f;
}
-static void __attribute__((overloadable))
+_RS_STATIC void __attribute__((overloadable))
rsMatrixLoadIdentity(rs_matrix2x2 *m) {
m->m[0] = 1.f;
m->m[1] = 0.f;
@@ -166,7 +172,7 @@
m->m[3] = 1.f;
}
-static void __attribute__((overloadable))
+_RS_STATIC void __attribute__((overloadable))
rsMatrixLoad(rs_matrix4x4 *m, const float *v) {
m->m[0] = v[0];
m->m[1] = v[1];
@@ -186,7 +192,7 @@
m->m[15] = v[15];
}
-static void __attribute__((overloadable))
+_RS_STATIC void __attribute__((overloadable))
rsMatrixLoad(rs_matrix3x3 *m, const float *v) {
m->m[0] = v[0];
m->m[1] = v[1];
@@ -199,7 +205,7 @@
m->m[8] = v[8];
}
-static void __attribute__((overloadable))
+_RS_STATIC void __attribute__((overloadable))
rsMatrixLoad(rs_matrix2x2 *m, const float *v) {
m->m[0] = v[0];
m->m[1] = v[1];
@@ -207,7 +213,7 @@
m->m[3] = v[3];
}
-static void __attribute__((overloadable))
+_RS_STATIC void __attribute__((overloadable))
rsMatrixLoad(rs_matrix4x4 *m, const rs_matrix4x4 *v) {
m->m[0] = v->m[0];
m->m[1] = v->m[1];
@@ -227,7 +233,7 @@
m->m[15] = v->m[15];
}
-static void __attribute__((overloadable))
+_RS_STATIC void __attribute__((overloadable))
rsMatrixLoad(rs_matrix4x4 *m, const rs_matrix3x3 *v) {
m->m[0] = v->m[0];
m->m[1] = v->m[1];
@@ -247,7 +253,7 @@
m->m[15] = 1.f;
}
-static void __attribute__((overloadable))
+_RS_STATIC void __attribute__((overloadable))
rsMatrixLoad(rs_matrix4x4 *m, const rs_matrix2x2 *v) {
m->m[0] = v->m[0];
m->m[1] = v->m[1];
@@ -267,7 +273,7 @@
m->m[15] = 1.f;
}
-static void __attribute__((overloadable))
+_RS_STATIC void __attribute__((overloadable))
rsMatrixLoad(rs_matrix3x3 *m, const rs_matrix3x3 *v) {
m->m[0] = v->m[0];
m->m[1] = v->m[1];
@@ -280,7 +286,7 @@
m->m[8] = v->m[8];
}
-static void __attribute__((overloadable))
+_RS_STATIC void __attribute__((overloadable))
rsMatrixLoad(rs_matrix2x2 *m, const rs_matrix2x2 *v) {
m->m[0] = v->m[0];
m->m[1] = v->m[1];
@@ -288,7 +294,7 @@
m->m[3] = v->m[3];
}
-static void __attribute__((overloadable))
+_RS_STATIC void __attribute__((overloadable))
rsMatrixLoadRotate(rs_matrix4x4 *m, float rot, float x, float y, float z) {
float c, s;
m->m[3] = 0;
@@ -327,7 +333,7 @@
m->m[10] = z*z*nc + c;
}
-static void __attribute__((overloadable))
+_RS_STATIC void __attribute__((overloadable))
rsMatrixLoadScale(rs_matrix4x4 *m, float x, float y, float z) {
rsMatrixLoadIdentity(m);
m->m[0] = x;
@@ -335,7 +341,7 @@
m->m[10] = z;
}
-static void __attribute__((overloadable))
+_RS_STATIC void __attribute__((overloadable))
rsMatrixLoadTranslate(rs_matrix4x4 *m, float x, float y, float z) {
rsMatrixLoadIdentity(m);
m->m[12] = x;
@@ -343,7 +349,7 @@
m->m[14] = z;
}
-static void __attribute__((overloadable))
+_RS_STATIC void __attribute__((overloadable))
rsMatrixLoadMultiply(rs_matrix4x4 *m, const rs_matrix4x4 *lhs, const rs_matrix4x4 *rhs) {
for (int i=0 ; i<4 ; i++) {
float ri0 = 0;
@@ -364,14 +370,14 @@
}
}
-static void __attribute__((overloadable))
+_RS_STATIC void __attribute__((overloadable))
rsMatrixMultiply(rs_matrix4x4 *m, const rs_matrix4x4 *rhs) {
rs_matrix4x4 mt;
rsMatrixLoadMultiply(&mt, m, rhs);
rsMatrixLoad(m, &mt);
}
-static void __attribute__((overloadable))
+_RS_STATIC void __attribute__((overloadable))
rsMatrixLoadMultiply(rs_matrix3x3 *m, const rs_matrix3x3 *lhs, const rs_matrix3x3 *rhs) {
for (int i=0 ; i<3 ; i++) {
float ri0 = 0;
@@ -389,14 +395,14 @@
}
}
-static void __attribute__((overloadable))
+_RS_STATIC void __attribute__((overloadable))
rsMatrixMultiply(rs_matrix3x3 *m, const rs_matrix3x3 *rhs) {
rs_matrix3x3 mt;
rsMatrixLoadMultiply(&mt, m, rhs);
rsMatrixLoad(m, &mt);
}
-static void __attribute__((overloadable))
+_RS_STATIC void __attribute__((overloadable))
rsMatrixLoadMultiply(rs_matrix2x2 *m, const rs_matrix2x2 *lhs, const rs_matrix2x2 *rhs) {
for (int i=0 ; i<2 ; i++) {
float ri0 = 0;
@@ -411,35 +417,35 @@
}
}
-static void __attribute__((overloadable))
+_RS_STATIC void __attribute__((overloadable))
rsMatrixMultiply(rs_matrix2x2 *m, const rs_matrix2x2 *rhs) {
rs_matrix2x2 mt;
rsMatrixLoadMultiply(&mt, m, rhs);
rsMatrixLoad(m, &mt);
}
-static void __attribute__((overloadable))
+_RS_STATIC void __attribute__((overloadable))
rsMatrixRotate(rs_matrix4x4 *m, float rot, float x, float y, float z) {
rs_matrix4x4 m1;
rsMatrixLoadRotate(&m1, rot, x, y, z);
rsMatrixMultiply(m, &m1);
}
-static void __attribute__((overloadable))
+_RS_STATIC void __attribute__((overloadable))
rsMatrixScale(rs_matrix4x4 *m, float x, float y, float z) {
rs_matrix4x4 m1;
rsMatrixLoadScale(&m1, x, y, z);
rsMatrixMultiply(m, &m1);
}
-static void __attribute__((overloadable))
+_RS_STATIC void __attribute__((overloadable))
rsMatrixTranslate(rs_matrix4x4 *m, float x, float y, float z) {
rs_matrix4x4 m1;
rsMatrixLoadTranslate(&m1, x, y, z);
rsMatrixMultiply(m, &m1);
}
-static void __attribute__((overloadable))
+_RS_STATIC void __attribute__((overloadable))
rsMatrixLoadOrtho(rs_matrix4x4 *m, float left, float right, float bottom, float top, float near, float far) {
rsMatrixLoadIdentity(m);
m->m[0] = 2.f / (right - left);
@@ -450,7 +456,7 @@
m->m[14]= -(far + near) / (far - near);
}
-static void __attribute__((overloadable))
+_RS_STATIC void __attribute__((overloadable))
rsMatrixLoadFrustum(rs_matrix4x4 *m, float left, float right, float bottom, float top, float near, float far) {
rsMatrixLoadIdentity(m);
m->m[0] = 2.f * near / (right - left);
@@ -463,7 +469,7 @@
m->m[15]= 0.f;
}
-static void __attribute__((overloadable))
+_RS_STATIC void __attribute__((overloadable))
rsMatrixLoadPerspective(rs_matrix4x4* m, float fovy, float aspect, float near, float far) {
float top = near * tan((float) (fovy * M_PI / 360.0f));
float bottom = -top;
@@ -472,7 +478,7 @@
rsMatrixLoadFrustum(m, left, right, bottom, top, near, far);
}
-static float4 __attribute__((overloadable))
+_RS_STATIC float4 __attribute__((overloadable))
rsMatrixMultiply(rs_matrix4x4 *m, float4 in) {
float4 ret;
ret.x = (m->m[0] * in.x) + (m->m[4] * in.y) + (m->m[8] * in.z) + (m->m[12] * in.w);
@@ -482,7 +488,7 @@
return ret;
}
-static float4 __attribute__((overloadable))
+_RS_STATIC float4 __attribute__((overloadable))
rsMatrixMultiply(rs_matrix4x4 *m, float3 in) {
float4 ret;
ret.x = (m->m[0] * in.x) + (m->m[4] * in.y) + (m->m[8] * in.z) + m->m[12];
@@ -492,7 +498,7 @@
return ret;
}
-static float4 __attribute__((overloadable))
+_RS_STATIC float4 __attribute__((overloadable))
rsMatrixMultiply(rs_matrix4x4 *m, float2 in) {
float4 ret;
ret.x = (m->m[0] * in.x) + (m->m[4] * in.y) + m->m[12];
@@ -502,7 +508,7 @@
return ret;
}
-static float3 __attribute__((overloadable))
+_RS_STATIC float3 __attribute__((overloadable))
rsMatrixMultiply(rs_matrix3x3 *m, float3 in) {
float3 ret;
ret.x = (m->m[0] * in.x) + (m->m[3] * in.y) + (m->m[6] * in.z);
@@ -511,7 +517,7 @@
return ret;
}
-static float3 __attribute__((overloadable))
+_RS_STATIC float3 __attribute__((overloadable))
rsMatrixMultiply(rs_matrix3x3 *m, float2 in) {
float3 ret;
ret.x = (m->m[0] * in.x) + (m->m[3] * in.y);
@@ -520,7 +526,7 @@
return ret;
}
-static float2 __attribute__((overloadable))
+_RS_STATIC float2 __attribute__((overloadable))
rsMatrixMultiply(rs_matrix2x2 *m, float2 in) {
float2 ret;
ret.x = (m->m[0] * in.x) + (m->m[2] * in.y);
@@ -529,7 +535,7 @@
}
// Returns true if the matrix was successfully inversed
-static bool __attribute__((overloadable))
+_RS_STATIC bool __attribute__((overloadable))
rsMatrixInverse(rs_matrix4x4 *m) {
rs_matrix4x4 result;
@@ -571,7 +577,7 @@
}
// Returns true if the matrix was successfully inversed
-static bool __attribute__((overloadable))
+_RS_STATIC bool __attribute__((overloadable))
rsMatrixInverseTranspose(rs_matrix4x4 *m) {
rs_matrix4x4 result;
@@ -612,7 +618,7 @@
return true;
}
-static void __attribute__((overloadable))
+_RS_STATIC void __attribute__((overloadable))
rsMatrixTranspose(rs_matrix4x4 *m) {
int i, j;
float temp;
@@ -625,7 +631,7 @@
}
}
-static void __attribute__((overloadable))
+_RS_STATIC void __attribute__((overloadable))
rsMatrixTranspose(rs_matrix3x3 *m) {
int i, j;
float temp;
@@ -638,7 +644,7 @@
}
}
-static void __attribute__((overloadable))
+_RS_STATIC void __attribute__((overloadable))
rsMatrixTranspose(rs_matrix2x2 *m) {
float temp = m->m[1];
m->m[1] = m->m[2];
@@ -649,7 +655,7 @@
// quaternion ops
/////////////////////////////////////////////////////
-static void __attribute__((overloadable))
+_RS_STATIC void __attribute__((overloadable))
rsQuaternionSet(rs_quaternion *q, float w, float x, float y, float z) {
q->w = w;
q->x = x;
@@ -657,7 +663,7 @@
q->z = z;
}
-static void __attribute__((overloadable))
+_RS_STATIC void __attribute__((overloadable))
rsQuaternionSet(rs_quaternion *q, const rs_quaternion *rhs) {
q->w = rhs->w;
q->x = rhs->x;
@@ -665,7 +671,7 @@
q->z = rhs->z;
}
-static void __attribute__((overloadable))
+_RS_STATIC void __attribute__((overloadable))
rsQuaternionMultiply(rs_quaternion *q, float s) {
q->w *= s;
q->x *= s;
@@ -673,7 +679,7 @@
q->z *= s;
}
-static void __attribute__((overloadable))
+_RS_STATIC void __attribute__((overloadable))
rsQuaternionMultiply(rs_quaternion *q, const rs_quaternion *rhs) {
q->w = -q->x*rhs->x - q->y*rhs->y - q->z*rhs->z + q->w*rhs->w;
q->x = q->x*rhs->w + q->y*rhs->z - q->z*rhs->y + q->w*rhs->x;
@@ -681,7 +687,7 @@
q->z = q->x*rhs->y - q->y*rhs->x + q->z*rhs->w + q->w*rhs->z;
}
-static void
+_RS_STATIC void
rsQuaternionAdd(rs_quaternion *q, const rs_quaternion *rhs) {
q->w *= rhs->w;
q->x *= rhs->x;
@@ -689,7 +695,7 @@
q->z *= rhs->z;
}
-static void
+_RS_STATIC void
rsQuaternionLoadRotateUnit(rs_quaternion *q, float rot, float x, float y, float z) {
rot *= (float)(M_PI / 180.0f) * 0.5f;
float c = cos(rot);
@@ -701,7 +707,7 @@
q->z = z * s;
}
-static void
+_RS_STATIC void
rsQuaternionLoadRotate(rs_quaternion *q, float rot, float x, float y, float z) {
const float len = x*x + y*y + z*z;
if (len != 1) {
@@ -713,19 +719,19 @@
rsQuaternionLoadRotateUnit(q, rot, x, y, z);
}
-static void
+_RS_STATIC void
rsQuaternionConjugate(rs_quaternion *q) {
q->x = -q->x;
q->y = -q->y;
q->z = -q->z;
}
-static float
+_RS_STATIC float
rsQuaternionDot(const rs_quaternion *q0, const rs_quaternion *q1) {
return q0->w*q1->w + q0->x*q1->x + q0->y*q1->y + q0->z*q1->z;
}
-static void
+_RS_STATIC void
rsQuaternionNormalize(rs_quaternion *q) {
const float len = rsQuaternionDot(q, q);
if (len != 1) {
@@ -734,7 +740,7 @@
}
}
-static void
+_RS_STATIC void
rsQuaternionSlerp(rs_quaternion *q, const rs_quaternion *q0, const rs_quaternion *q1, float t) {
if (t <= 0.0f) {
rsQuaternionSet(q, q0);
@@ -776,7 +782,7 @@
tempq0.y*scale + tempq1.y*invScale, tempq0.z*scale + tempq1.z*invScale);
}
-static void rsQuaternionGetMatrixUnit(rs_matrix4x4 *m, const rs_quaternion *q) {
+_RS_STATIC void rsQuaternionGetMatrixUnit(rs_matrix4x4 *m, const rs_quaternion *q) {
float x2 = 2.0f * q->x * q->x;
float y2 = 2.0f * q->y * q->y;
float z2 = 2.0f * q->z * q->z;
@@ -811,7 +817,7 @@
/////////////////////////////////////////////////////
// utility funcs
/////////////////////////////////////////////////////
-__inline__ static void __attribute__((overloadable, always_inline))
+__inline__ _RS_STATIC void __attribute__((overloadable, always_inline))
rsExtractFrustumPlanes(const rs_matrix4x4 *modelViewProj,
float4 *left, float4 *right,
float4 *top, float4 *bottom,
@@ -861,7 +867,7 @@
*far /= len;
}
-__inline__ static bool __attribute__((overloadable, always_inline))
+__inline__ _RS_STATIC bool __attribute__((overloadable, always_inline))
rsIsSphereInFrustum(float4 *sphere,
float4 *left, float4 *right,
float4 *top, float4 *bottom,
@@ -899,26 +905,26 @@
// int ops
/////////////////////////////////////////////////////
-__inline__ static uint __attribute__((overloadable, always_inline)) rsClamp(uint amount, uint low, uint high) {
+__inline__ _RS_STATIC uint __attribute__((overloadable, always_inline)) rsClamp(uint amount, uint low, uint high) {
return amount < low ? low : (amount > high ? high : amount);
}
-__inline__ static int __attribute__((overloadable, always_inline)) rsClamp(int amount, int low, int high) {
+__inline__ _RS_STATIC int __attribute__((overloadable, always_inline)) rsClamp(int amount, int low, int high) {
return amount < low ? low : (amount > high ? high : amount);
}
-__inline__ static ushort __attribute__((overloadable, always_inline)) rsClamp(ushort amount, ushort low, ushort high) {
+__inline__ _RS_STATIC ushort __attribute__((overloadable, always_inline)) rsClamp(ushort amount, ushort low, ushort high) {
return amount < low ? low : (amount > high ? high : amount);
}
-__inline__ static short __attribute__((overloadable, always_inline)) rsClamp(short amount, short low, short high) {
+__inline__ _RS_STATIC short __attribute__((overloadable, always_inline)) rsClamp(short amount, short low, short high) {
return amount < low ? low : (amount > high ? high : amount);
}
-__inline__ static uchar __attribute__((overloadable, always_inline)) rsClamp(uchar amount, uchar low, uchar high) {
+__inline__ _RS_STATIC uchar __attribute__((overloadable, always_inline)) rsClamp(uchar amount, uchar low, uchar high) {
return amount < low ? low : (amount > high ? high : amount);
}
-__inline__ static char __attribute__((overloadable, always_inline)) rsClamp(char amount, char low, char high) {
+__inline__ _RS_STATIC char __attribute__((overloadable, always_inline)) rsClamp(char amount, char low, char high) {
return amount < low ? low : (amount > high ? high : amount);
}
-
+#undef _RS_STATIC
#endif
diff --git a/libs/rs/scriptc/rs_types.rsh b/libs/rs/scriptc/rs_types.rsh
index 212eb83..a010096 100644
--- a/libs/rs/scriptc/rs_types.rsh
+++ b/libs/rs/scriptc/rs_types.rsh
@@ -1,6 +1,9 @@
#ifndef __RS_TYPES_RSH__
#define __RS_TYPES_RSH__
+#define M_PI 3.14159265358979323846264338327950288f /* pi */
+
+#include "stdbool.h"
typedef char int8_t;
typedef short int16_t;
typedef int int32_t;
diff --git a/libs/surfaceflinger_client/SharedBufferStack.cpp b/libs/surfaceflinger_client/SharedBufferStack.cpp
index 3b2ef84..af11f97 100644
--- a/libs/surfaceflinger_client/SharedBufferStack.cpp
+++ b/libs/surfaceflinger_client/SharedBufferStack.cpp
@@ -261,8 +261,7 @@
// NOTE: if stack.head is messed up, we could crash the client
// or cause some drawing artifacts. This is okay, as long as it is
// limited to the client.
- return (buf != stack.index[stack.head] ||
- (stack.queued > 0 && stack.inUse != buf));
+ return (buf != stack.index[stack.head]);
}
SharedBufferServer::BuffersAvailableCondition::BuffersAvailableCondition(
diff --git a/libs/ui/GraphicBufferAllocator.cpp b/libs/ui/GraphicBufferAllocator.cpp
index ce84683..33ef1fc 100644
--- a/libs/ui/GraphicBufferAllocator.cpp
+++ b/libs/ui/GraphicBufferAllocator.cpp
@@ -61,7 +61,7 @@
const size_t c = list.size();
for (size_t i=0 ; i<c ; i++) {
const alloc_rec_t& rec(list.valueAt(i));
- snprintf(buffer, SIZE, "%10p: %7.2f KiB | %4u (%4u) x %4u | %2d | 0x%08x\n",
+ snprintf(buffer, SIZE, "%10p: %7.2f KiB | %4u (%4u) x %4u | %8X | 0x%08x\n",
list.keyAt(i), rec.size/1024.0f,
rec.w, rec.s, rec.h, rec.format, rec.usage);
result.append(buffer);
diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java
index 10c9a9a..33c6385 100644
--- a/media/java/android/media/MediaScanner.java
+++ b/media/java/android/media/MediaScanner.java
@@ -1462,22 +1462,29 @@
if (lastSlash < 0) throw new IllegalArgumentException("bad path " + path);
Uri uri, membersUri;
long rowId = entry.mRowId;
- if (rowId == 0) {
- // Create a new playlist
- int lastDot = path.lastIndexOf('.');
- String name = (lastDot < 0 ? path.substring(lastSlash + 1) : path.substring(lastSlash + 1, lastDot));
- values.put(MediaStore.Audio.Playlists.NAME, name);
+ // make sure we have a name
+ String name = values.getAsString(MediaStore.Audio.Playlists.NAME);
+ if (name == null) {
+ name = values.getAsString(MediaStore.MediaColumns.TITLE);
+ if (name == null) {
+ // extract name from file name
+ int lastDot = path.lastIndexOf('.');
+ name = (lastDot < 0 ? path.substring(lastSlash + 1)
+ : path.substring(lastSlash + 1, lastDot));
+ }
+ }
+
+ values.put(MediaStore.Audio.Playlists.NAME, name);
+ values.put(MediaStore.Audio.Playlists.DATE_MODIFIED, entry.mLastModified);
+
+ if (rowId == 0) {
values.put(MediaStore.Audio.Playlists.DATA, path);
- values.put(MediaStore.Audio.Playlists.DATE_MODIFIED, entry.mLastModified);
uri = mMediaProvider.insert(mPlaylistsUri, values);
rowId = ContentUris.parseId(uri);
membersUri = Uri.withAppendedPath(uri, Playlists.Members.CONTENT_DIRECTORY);
} else {
uri = ContentUris.withAppendedId(mPlaylistsUri, rowId);
-
- // update lastModified value of existing playlist
- values.put(MediaStore.Audio.Playlists.DATE_MODIFIED, entry.mLastModified);
mMediaProvider.update(uri, values, null, null);
// delete members of existing playlist
diff --git a/media/java/android/media/videoeditor/MediaImageItem.java b/media/java/android/media/videoeditor/MediaImageItem.java
index b03588f..1c02878 100755
--- a/media/java/android/media/videoeditor/MediaImageItem.java
+++ b/media/java/android/media/videoeditor/MediaImageItem.java
@@ -93,29 +93,28 @@
*
* @throws IOException
*/
- public MediaImageItem(VideoEditor editor, String mediaItemId,
- String filename, long durationMs,
- int renderingMode) throws IOException {
+ public MediaImageItem(VideoEditor editor, String mediaItemId, String filename, long durationMs,
+ int renderingMode) throws IOException {
super(editor, mediaItemId, filename, renderingMode);
mMANativeHelper = ((VideoEditorImpl)editor).getNativeContext();
mVideoEditor = ((VideoEditorImpl)editor);
try {
- final Properties properties =
- mMANativeHelper.getMediaProperties(filename);
+ final Properties properties = mMANativeHelper.getMediaProperties(filename);
switch (mMANativeHelper.getFileType(properties.fileType)) {
case MediaProperties.FILE_JPEG:
+ case MediaProperties.FILE_PNG: {
break;
- case MediaProperties.FILE_PNG:
- break;
+ }
- default:
- throw new IllegalArgumentException("Unsupported Input File Type");
+ default: {
+ throw new IllegalArgumentException("Unsupported Input File Type");
+ }
}
} catch (Exception e) {
- throw new IllegalArgumentException("Unsupported file or file not found");
+ throw new IllegalArgumentException("Unsupported file or file not found: " + filename);
}
/**
@@ -130,13 +129,13 @@
mDurationMs = durationMs;
mDecodedFilename = String.format(mMANativeHelper.getProjectPath() +
"/" + "decoded" + getId()+ ".rgb");
- final FileOutputStream fl = new FileOutputStream(mDecodedFilename);
- final DataOutputStream dos = new DataOutputStream(fl);
+
try {
mAspectRatio = mMANativeHelper.getAspectRatio(mWidth, mHeight);
} catch(IllegalArgumentException e) {
throw new IllegalArgumentException ("Null width and height");
}
+
mGeneratedClipHeight = 0;
mGeneratedClipWidth = 0;
@@ -146,9 +145,12 @@
*/
final Pair<Integer, Integer>[] resolutions =
MediaProperties.getSupportedResolutions(mAspectRatio);
+
/**
* Get the highest resolution
*/
+ final FileOutputStream fl = new FileOutputStream(mDecodedFilename);
+ final DataOutputStream dos = new DataOutputStream(fl);
final Pair<Integer, Integer> maxResolution = resolutions[resolutions.length - 1];
if (mHeight > maxResolution.second) {
/**
@@ -171,16 +173,16 @@
int mNewHeight = 0;
if ((mScaledWidth % 2 ) != 0) {
mNewWidth = mScaledWidth - 1;
- }
- else {
+ } else {
mNewWidth = mScaledWidth;
}
+
if ((mScaledHeight % 2 ) != 0) {
mNewHeight = mScaledHeight - 1;
- }
- else {
+ } else {
mNewHeight = mScaledHeight;
}
+
final int [] framingBuffer = new int[mNewWidth];
final ByteBuffer byteBuffer = ByteBuffer.allocate(framingBuffer.length * 4);
IntBuffer intBuffer;
@@ -195,6 +197,7 @@
dos.write(array);
tmp += 1;
}
+
mScaledWidth = mNewWidth;
mScaledHeight = mNewHeight;
scaledImage.recycle();
@@ -204,10 +207,11 @@
+ "/" + "scaled" + getId()+ ".JPG");
if (!((new File(mScaledFilename)).exists())) {
super.mRegenerateClip = true;
- FileOutputStream f1 = new FileOutputStream(mScaledFilename);
+ final FileOutputStream f1 = new FileOutputStream(mScaledFilename);
scaledImage.compress(Bitmap.CompressFormat.JPEG, 50,f1);
f1.close();
}
+
mScaledWidth = scaledImage.getWidth();
mScaledHeight = scaledImage.getHeight();
@@ -215,17 +219,17 @@
int mNewheight = 0;
if ((mScaledWidth % 2 ) != 0) {
mNewWidth = mScaledWidth - 1;
- }
- else {
+ } else {
mNewWidth = mScaledWidth;
}
+
if ((mScaledHeight % 2 ) != 0) {
mNewheight = mScaledHeight - 1;
- }
- else {
+ } else {
mNewheight = mScaledHeight;
}
- Bitmap imageBitmap = BitmapFactory.decodeFile(mScaledFilename);
+
+ final Bitmap imageBitmap = BitmapFactory.decodeFile(mScaledFilename);
final int [] framingBuffer = new int[mNewWidth];
ByteBuffer byteBuffer = ByteBuffer.allocate(framingBuffer.length * 4);
IntBuffer intBuffer;
@@ -240,10 +244,12 @@
dos.write(array);
tmp += 1;
}
+
mScaledWidth = mNewWidth;
mScaledHeight = mNewheight;
imageBitmap.recycle();
}
+
fl.close();
System.gc();
}
@@ -286,7 +292,7 @@
/**
* @return The file name of image which is decoded and stored
- * in rgb format
+ * in RGB format
*/
String getDecodedImageFileName() {
return mDecodedFilename;
@@ -447,7 +453,7 @@
* Check if the effect overlaps with the end transition
*/
if (effect.getStartTime() + effect.getDuration() >
- mDurationMs - transitionDurationMs) {
+ mDurationMs - transitionDurationMs) {
mEndTransition.invalidate();
break;
}
@@ -464,7 +470,7 @@
* Check if the overlay overlaps with the end transition
*/
if (overlay.getStartTime() + overlay.getDuration() >
- mDurationMs - transitionDurationMs) {
+ mDurationMs - transitionDurationMs) {
mEndTransition.invalidate();
break;
}
@@ -648,23 +654,24 @@
for (int i = 0; i < thumbnailCount; i++) {
thumbnailArray[i] = thumbnail;
}
+
return thumbnailArray;
-
-
- }
- else {
+ } else {
if (startMs > endMs) {
throw new IllegalArgumentException("Start time is greater than end time");
}
+
if (endMs > mDurationMs) {
throw new IllegalArgumentException("End time is greater than file duration");
}
+
if (startMs == endMs) {
Bitmap[] bitmap = new Bitmap[1];
bitmap[0] = mMANativeHelper.getPixels(getGeneratedImageClip(),
width, height,startMs);
return bitmap;
}
+
return mMANativeHelper.getPixelsList(getGeneratedImageClip(), width,
height,startMs,endMs,thumbnailCount);
}
@@ -704,31 +711,51 @@
*/
if (mBeginTransition != null) {
final long transitionDurationMs = mBeginTransition.getDuration();
+ final boolean oldOverlap = isOverlapping(oldStartTimeMs, oldDurationMs, 0,
+ transitionDurationMs);
+ final boolean newOverlap = isOverlapping(newStartTimeMs, newDurationMs, 0,
+ transitionDurationMs);
/**
- * If the start time has changed and if the old or the new item
- * overlaps with the begin transition, invalidate the transition.
+ * Invalidate transition if:
+ *
+ * 1. New item overlaps the transition, the old one did not
+ * 2. New item does not overlap the transition, the old one did
+ * 3. New and old item overlap the transition if begin or end
+ * time changed
*/
- if (((oldStartTimeMs != newStartTimeMs)
- || (oldDurationMs != newDurationMs) )&&
- (isOverlapping(oldStartTimeMs, oldDurationMs, 0, transitionDurationMs) ||
- isOverlapping(newStartTimeMs, newDurationMs, 0,
- transitionDurationMs))) {
+ if (newOverlap != oldOverlap) { // Overlap has changed
mBeginTransition.invalidate();
+ } else if (newOverlap) { // Both old and new overlap
+ if ((oldStartTimeMs != newStartTimeMs) ||
+ !(oldStartTimeMs + oldDurationMs > transitionDurationMs &&
+ newStartTimeMs + newDurationMs > transitionDurationMs)) {
+ mBeginTransition.invalidate();
+ }
}
}
if (mEndTransition != null) {
final long transitionDurationMs = mEndTransition.getDuration();
+ final boolean oldOverlap = isOverlapping(oldStartTimeMs, oldDurationMs,
+ mDurationMs - transitionDurationMs, transitionDurationMs);
+ final boolean newOverlap = isOverlapping(newStartTimeMs, newDurationMs,
+ mDurationMs - transitionDurationMs, transitionDurationMs);
/**
- * If the start time + duration has changed and if the old or the new
- * item overlaps the end transition, invalidate the transition
+ * Invalidate transition if:
+ *
+ * 1. New item overlaps the transition, the old one did not
+ * 2. New item does not overlap the transition, the old one did
+ * 3. New and old item overlap the transition if begin or end
+ * time changed
*/
- if (oldStartTimeMs + oldDurationMs != newStartTimeMs + newDurationMs &&
- (isOverlapping(oldStartTimeMs, oldDurationMs,
- mDurationMs - transitionDurationMs, transitionDurationMs) ||
- isOverlapping(newStartTimeMs, newDurationMs,
- mDurationMs - transitionDurationMs, transitionDurationMs))) {
+ if (newOverlap != oldOverlap) { // Overlap has changed
mEndTransition.invalidate();
+ } else if (newOverlap) { // Both old and new overlap
+ if ((oldStartTimeMs + oldDurationMs != newStartTimeMs + newDurationMs) ||
+ ((oldStartTimeMs > mDurationMs - transitionDurationMs) ||
+ newStartTimeMs > mDurationMs - transitionDurationMs)) {
+ mEndTransition.invalidate();
+ }
}
}
}
@@ -743,10 +770,12 @@
setGeneratedImageClip(null);
setRegenerateClip(true);
}
+
if (mScaledFilename != null) {
new File(mScaledFilename).delete();
mScaledFilename = null;
}
+
if (mDecodedFilename != null) {
new File(mDecodedFilename).delete();
mDecodedFilename = null;
diff --git a/media/java/android/media/videoeditor/MediaVideoItem.java b/media/java/android/media/videoeditor/MediaVideoItem.java
index 772b360..2981b41 100755
--- a/media/java/android/media/videoeditor/MediaVideoItem.java
+++ b/media/java/android/media/videoeditor/MediaVideoItem.java
@@ -78,12 +78,9 @@
*
* @throws IOException if the file cannot be opened for reading
*/
- public MediaVideoItem(VideoEditor editor, String mediaItemId,
- String filename,
- int renderingMode)
- throws IOException {
- this(editor, mediaItemId, filename, renderingMode, 0, END_OF_FILE,
- 100, false, null);
+ public MediaVideoItem(VideoEditor editor, String mediaItemId, String filename,
+ int renderingMode) throws IOException {
+ this(editor, mediaItemId, filename, renderingMode, 0, END_OF_FILE, 100, false, null);
}
/**
@@ -105,20 +102,22 @@
* @throws IOException if the file cannot be opened for reading
*/
MediaVideoItem(VideoEditor editor, String mediaItemId, String filename,
- int renderingMode,
- long beginMs, long endMs, int volumePercent, boolean muted,
+ int renderingMode, long beginMs, long endMs, int volumePercent, boolean muted,
String audioWaveformFilename) throws IOException {
super(editor, mediaItemId, filename, renderingMode);
+
if (editor instanceof VideoEditorImpl) {
mMANativeHelper = ((VideoEditorImpl)editor).getNativeContext();
mVideoEditor = ((VideoEditorImpl)editor);
}
- Properties properties = null;
+
+ final Properties properties;
try {
properties = mMANativeHelper.getMediaProperties(filename);
} catch ( Exception e) {
- throw new IllegalArgumentException("Unsupported file or file not found");
+ throw new IllegalArgumentException("Unsupported file or file not found: " + filename);
}
+
switch (mMANativeHelper.getFileType(properties.fileType)) {
case MediaProperties.FILE_3GP:
break;
@@ -163,8 +162,7 @@
mMuted = muted;
mAudioWaveformFilename = audioWaveformFilename;
if (audioWaveformFilename != null) {
- mWaveformData =
- new SoftReference<WaveformData>(
+ mWaveformData = new SoftReference<WaveformData>(
new WaveformData(audioWaveformFilename));
} else {
mWaveformData = null;
@@ -190,9 +188,11 @@
if (beginMs > mDurationMs) {
throw new IllegalArgumentException("setExtractBoundaries: Invalid start time");
}
+
if (endMs > mDurationMs) {
throw new IllegalArgumentException("setExtractBoundaries: Invalid end time");
}
+
if ((endMs != -1) && (beginMs >= endMs) ) {
throw new IllegalArgumentException("setExtractBoundaries: Start time is greater than end time");
}
@@ -255,18 +255,18 @@
*/
@Override
public Bitmap getThumbnail(int width, int height, long timeMs) {
- if (timeMs > mDurationMs)
- {
+ if (timeMs > mDurationMs) {
throw new IllegalArgumentException("Time Exceeds duration");
}
- if (timeMs < 0)
- {
+
+ if (timeMs < 0) {
throw new IllegalArgumentException("Invalid Time duration");
}
- if ((width <=0) || (height <= 0))
- {
+
+ if ((width <=0) || (height <= 0)) {
throw new IllegalArgumentException("Invalid Dimensions");
}
+
return mMANativeHelper.getPixels(super.getFilename(),
width, height,timeMs);
}
@@ -280,18 +280,21 @@
if (startMs > endMs) {
throw new IllegalArgumentException("Start time is greater than end time");
}
+
if (endMs > mDurationMs) {
throw new IllegalArgumentException("End time is greater than file duration");
}
+
if ((height <= 0) || (width <= 0)) {
throw new IllegalArgumentException("Invalid dimension");
}
+
if (startMs == endMs) {
- Bitmap[] bitmap = new Bitmap[1];
- bitmap[0] = mMANativeHelper.getPixels(super.getFilename(),
- width, height,startMs);
+ final Bitmap[] bitmap = new Bitmap[1];
+ bitmap[0] = mMANativeHelper.getPixels(super.getFilename(), width, height,startMs);
return bitmap;
}
+
return mMANativeHelper.getPixelsList(super.getFilename(), width,
height,startMs,endMs,thumbnailCount);
}
@@ -324,40 +327,58 @@
* {@inheritDoc}
*/
@Override
- void invalidateTransitions(long oldStartTimeMs, long oldDurationMs,
- long newStartTimeMs,
+ void invalidateTransitions(long oldStartTimeMs, long oldDurationMs, long newStartTimeMs,
long newDurationMs) {
/**
* Check if the item overlaps with the beginning and end transitions
*/
if (mBeginTransition != null) {
final long transitionDurationMs = mBeginTransition.getDuration();
+ final boolean oldOverlap = isOverlapping(oldStartTimeMs, oldDurationMs,
+ mBeginBoundaryTimeMs, transitionDurationMs);
+ final boolean newOverlap = isOverlapping(newStartTimeMs, newDurationMs,
+ mBeginBoundaryTimeMs, transitionDurationMs);
/**
- * If the start time has changed and if the old or the new item
- * overlaps with the begin transition, invalidate the transition.
+ * Invalidate transition if:
+ *
+ * 1. New item overlaps the transition, the old one did not
+ * 2. New item does not overlap the transition, the old one did
+ * 3. New and old item overlap the transition if begin or end
+ * time changed
*/
- if (((oldStartTimeMs != newStartTimeMs)
- || (oldDurationMs != newDurationMs) )&&
- (isOverlapping(oldStartTimeMs, oldDurationMs,
- mBeginBoundaryTimeMs, transitionDurationMs) ||
- isOverlapping(newStartTimeMs, newDurationMs,
- mBeginBoundaryTimeMs, transitionDurationMs))) {
+ if (newOverlap != oldOverlap) { // Overlap has changed
mBeginTransition.invalidate();
+ } else if (newOverlap) { // Both old and new overlap
+ if ((oldStartTimeMs != newStartTimeMs) ||
+ !(oldStartTimeMs + oldDurationMs > transitionDurationMs &&
+ newStartTimeMs + newDurationMs > transitionDurationMs)) {
+ mBeginTransition.invalidate();
+ }
}
}
if (mEndTransition != null) {
final long transitionDurationMs = mEndTransition.getDuration();
+ final boolean oldOverlap = isOverlapping(oldStartTimeMs, oldDurationMs,
+ mEndBoundaryTimeMs - transitionDurationMs, transitionDurationMs);
+ final boolean newOverlap = isOverlapping(newStartTimeMs, newDurationMs,
+ mEndBoundaryTimeMs - transitionDurationMs, transitionDurationMs);
/**
- * If the start time + duration has changed and if the old or the new
- * item overlaps the end transition, invalidate the transition
+ * Invalidate transition if:
+ *
+ * 1. New item overlaps the transition, the old one did not
+ * 2. New item does not overlap the transition, the old one did
+ * 3. New and old item overlap the transition if begin or end
+ * time changed
*/
- if (oldStartTimeMs + oldDurationMs != newStartTimeMs + newDurationMs &&
- (isOverlapping(oldStartTimeMs, oldDurationMs,
- mEndBoundaryTimeMs - transitionDurationMs, transitionDurationMs) ||
- isOverlapping(newStartTimeMs, newDurationMs,
- mEndBoundaryTimeMs - transitionDurationMs, transitionDurationMs))) {
+ if (newOverlap != oldOverlap) { // Overlap has changed
mEndTransition.invalidate();
+ } else if (newOverlap) { // Both old and new overlap
+ if ((oldStartTimeMs + oldDurationMs != newStartTimeMs + newDurationMs) ||
+ ((oldStartTimeMs > mEndBoundaryTimeMs - transitionDurationMs) ||
+ newStartTimeMs > mEndBoundaryTimeMs - transitionDurationMs)) {
+ mEndTransition.invalidate();
+ }
}
}
}
@@ -434,7 +455,7 @@
throw new IllegalArgumentException("requested time not correct");
}
- Surface surface = surfaceHolder.getSurface();
+ final Surface surface = surfaceHolder.getSurface();
if (surface == null) {
throw new RuntimeException("Surface could not be retrieved from Surface holder");
}
@@ -442,8 +463,7 @@
if (mFilename != null) {
return mMANativeHelper.renderMediaItemPreviewFrame(surface,
mFilename,timeMs,mWidth,mHeight);
- }
- else {
+ } else {
return 0;
}
}
@@ -462,7 +482,7 @@
* Audio track
*/
public void extractAudioWaveform(ExtractAudioWaveformProgressListener listener)
- throws IOException {
+ throws IOException {
int frameDuration = 0;
int sampleCount = 0;
final String projectPath = mMANativeHelper.getProjectPath();
@@ -481,19 +501,17 @@
* Logic to get frame duration = (no. of frames per sample * 1000)/
* sampling frequency
*/
- if ( mMANativeHelper.getAudioCodecType(mAudioType) ==
+ if (mMANativeHelper.getAudioCodecType(mAudioType) ==
MediaProperties.ACODEC_AMRNB ) {
frameDuration = (MediaProperties.SAMPLES_PER_FRAME_AMRNB*1000)/
MediaProperties.DEFAULT_SAMPLING_FREQUENCY;
sampleCount = MediaProperties.SAMPLES_PER_FRAME_AMRNB;
- }
- else if ( mMANativeHelper.getAudioCodecType(mAudioType) ==
+ } else if (mMANativeHelper.getAudioCodecType(mAudioType) ==
MediaProperties.ACODEC_AMRWB ) {
frameDuration = (MediaProperties.SAMPLES_PER_FRAME_AMRWB * 1000)/
MediaProperties.DEFAULT_SAMPLING_FREQUENCY;
sampleCount = MediaProperties.SAMPLES_PER_FRAME_AMRWB;
- }
- else if ( mMANativeHelper.getAudioCodecType(mAudioType) ==
+ } else if (mMANativeHelper.getAudioCodecType(mAudioType) ==
MediaProperties.ACODEC_AAC_LC ) {
frameDuration = (MediaProperties.SAMPLES_PER_FRAME_AAC * 1000)/
MediaProperties.DEFAULT_SAMPLING_FREQUENCY;
@@ -682,5 +700,4 @@
return clipSettings;
}
-
}
diff --git a/media/jni/android_mtp_MtpServer.cpp b/media/jni/android_mtp_MtpServer.cpp
index 241f18a..8908e67 100644
--- a/media/jni/android_mtp_MtpServer.cpp
+++ b/media/jni/android_mtp_MtpServer.cpp
@@ -62,6 +62,7 @@
String8 mStoragePath;
uint64_t mReserveSpace;
jobject mJavaServer;
+ bool mDone;
int mFd;
public:
@@ -72,6 +73,7 @@
mStoragePath(storagePath),
mReserveSpace(reserveSpace),
mJavaServer(javaServer),
+ mDone(false),
mFd(-1)
{
}
@@ -94,27 +96,33 @@
virtual bool threadLoop() {
sMutex.lock();
- mFd = open("/dev/mtp_usb", O_RDWR);
- printf("open returned %d\n", mFd);
- if (mFd < 0) {
- LOGE("could not open MTP driver\n");
+
+ while (!mDone) {
+ mFd = open("/dev/mtp_usb", O_RDWR);
+ printf("open returned %d\n", mFd);
+ if (mFd < 0) {
+ LOGE("could not open MTP driver\n");
+ sMutex.unlock();
+ return false;
+ }
+
+ mServer = new MtpServer(mFd, mDatabase, AID_MEDIA_RW, 0664, 0775);
+ mServer->addStorage(mStoragePath, mReserveSpace);
+
sMutex.unlock();
- return false;
+
+ LOGD("MtpThread mServer->run");
+ mServer->run();
+ sleep(1);
+
+ sMutex.lock();
+
+ close(mFd);
+ mFd = -1;
+ delete mServer;
+ mServer = NULL;
}
- mServer = new MtpServer(mFd, mDatabase, AID_MEDIA_RW, 0664, 0775);
- mServer->addStorage(mStoragePath, mReserveSpace);
- sMutex.unlock();
-
- LOGD("MtpThread mServer->run");
- mServer->run();
-
- sMutex.lock();
- close(mFd);
- mFd = -1;
- delete mServer;
- mServer = NULL;
-
JNIEnv* env = AndroidRuntime::getJNIEnv();
env->SetIntField(mJavaServer, field_context, 0);
env->DeleteGlobalRef(mJavaServer);
@@ -124,6 +132,12 @@
return false;
}
+ void stop() {
+ sMutex.lock();
+ mDone = true;
+ sMutex.unlock();
+ }
+
void sendObjectAdded(MtpObjectHandle handle) {
sMutex.lock();
if (mServer)
@@ -181,6 +195,9 @@
{
#ifdef HAVE_ANDROID_OS
LOGD("stop\n");
+ MtpThread *thread = (MtpThread *)env->GetIntField(thiz, field_context);
+ if (thread)
+ thread->stop();
#endif
}
@@ -212,7 +229,7 @@
MtpThread *thread = (MtpThread *)env->GetIntField(thiz, field_context);
if (thread)
thread->setPtpMode(usePtp);
- #endif
+#endif
}
// ----------------------------------------------------------------------------
diff --git a/media/jni/mediaeditor/Android.mk b/media/jni/mediaeditor/Android.mk
index 27c41be..0a01fb2 100755
--- a/media/jni/mediaeditor/Android.mk
+++ b/media/jni/mediaeditor/Android.mk
@@ -85,6 +85,6 @@
# to add this library to the prelink map and set this to true.
LOCAL_PRELINK_MODULE := false
-LOCAL_MODULE_TAGS := eng development
+LOCAL_MODULE_TAGS := optional
include $(BUILD_SHARED_LIBRARY)
diff --git a/media/jni/mediaeditor/VideoEditorLogging.h b/media/jni/mediaeditor/VideoEditorLogging.h
index ca8c047..c13f6ff 100755
--- a/media/jni/mediaeditor/VideoEditorLogging.h
+++ b/media/jni/mediaeditor/VideoEditorLogging.h
@@ -21,12 +21,13 @@
#define VIDEOEDIT_LOG_INDENTATION (3)
+#define VIDEOEDIT_LOG_ERROR __android_log_print
+#define VIDEOEDIT_LOG_EXCEPTION __android_log_print
+
#ifdef VIDEOEDIT_LOGGING_ENABLED
#define VIDEOEDIT_LOG_ALLOCATION __android_log_print
#define VIDEOEDIT_LOG_API __android_log_print
-#define VIDEOEDIT_LOG_ERROR __android_log_print
-#define VIDEOEDIT_LOG_EXCEPTION __android_log_print
#define VIDEOEDIT_LOG_FUNCTION __android_log_print
#define VIDEOEDIT_LOG_RESULT(x,y, ...) LOGI(y, __VA_ARGS__ )
#define VIDEOEDIT_LOG_SETTING __android_log_print
@@ -40,8 +41,6 @@
#define VIDEOEDIT_LOG_ALLOCATION (void)
#define VIDEOEDIT_LOG_API (void)
-#define VIDEOEDIT_LOG_ERROR (void)
-#define VIDEOEDIT_LOG_EXCEPTION (void)
#define VIDEOEDIT_LOG_FUNCTION (void)
#define VIDEOEDIT_LOG_RESULT (void)
#define VIDEOEDIT_LOG_SETTING (void)
diff --git a/media/jni/mediaeditor/VideoEditorMain.cpp b/media/jni/mediaeditor/VideoEditorMain.cpp
index e66e4b9..643f698 100755
--- a/media/jni/mediaeditor/VideoEditorMain.cpp
+++ b/media/jni/mediaeditor/VideoEditorMain.cpp
@@ -437,7 +437,7 @@
VideoEditor_renderPreviewFrameStr frameStr;
M4OSA_Context tnContext = M4OSA_NULL;
const char* pMessage = NULL;
- M4VIFI_ImagePlane *yuvPlane;
+ M4VIFI_ImagePlane *yuvPlane = NULL;
VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO,
"VIDEO_EDITOR", "surfaceWidth = %d",surfaceWidth);
@@ -1179,7 +1179,7 @@
}
/** Remove the alpha channel */
- for (int i = 0, j = 0; i < frameSize_argb; i++) {
+ for (size_t i = 0, j = 0; i < frameSize_argb; i++) {
if ((i % 4) == 0) continue;
pFramingCtx->FramingRgb->pac_data[j] = pTmpData[i];
j++;
@@ -2729,7 +2729,7 @@
} M4AM_Buffer;
-M4OSA_UInt8 logLookUp[256]{
+M4OSA_UInt8 logLookUp[256] = {
0,120,137,146,154,159,163,167,171,173,176,178,181,182,184,186,188,189,190,192,193,
194,195,196,198,199,199,200,201,202,203,204,205,205,206,207,207,208,209,209,210,
211,211,212,212,213,213,214,215,215,216,216,216,217,217,218,218,219,219,220,220,
@@ -2788,7 +2788,7 @@
err = M4OSA_fileReadOpen (&inputFileHandle, pInputFileURL, M4OSA_kFileRead);
if (inputFileHandle == M4OSA_NULL) {
VIDEOEDIT_LOG_ERROR(ANDROID_LOG_INFO, "VIDEO_EDITOR",
- "M4MA_generateAudioGraphFile: Cannot open input file 0x%x", err);
+ "M4MA_generateAudioGraphFile: Cannot open input file 0x%lx", err);
return err;
}
@@ -2822,7 +2822,7 @@
bufferIn.m_bufferSize = samplesCountInBytes*sizeof(M4OSA_UInt16);
} else {
VIDEOEDIT_LOG_ERROR(ANDROID_LOG_INFO, "VIDEO_EDITOR",
- "M4MA_generateAudioGraphFile: Malloc failed for bufferIn.m_dataAddress 0x%x",\
+ "M4MA_generateAudioGraphFile: Malloc failed for bufferIn.m_dataAddress 0x%lx",
M4ERR_ALLOC);
return M4ERR_ALLOC;
}
@@ -2862,7 +2862,7 @@
if (err != M4NO_ERROR) {
// if out value of bytes-read is 0, break
if ( numBytesToRead == 0) {
- VIDEOEDIT_LOG_ERROR(ANDROID_LOG_INFO, "VIDEO_EDITOR", "numBytesToRead 0x%x",\
+ VIDEOEDIT_LOG_ERROR(ANDROID_LOG_INFO, "VIDEO_EDITOR", "numBytesToRead 0x%lx",
numBytesToRead);
break; /* stop if file is empty or EOF */
}
@@ -2914,7 +2914,7 @@
} while (numBytesToRead != 0);
- VIDEOEDIT_LOG_ERROR(ANDROID_LOG_INFO, "VIDEO_EDITOR", "loop 0x%x", volumeValuesCount);
+ VIDEOEDIT_LOG_ERROR(ANDROID_LOG_INFO, "VIDEO_EDITOR", "loop 0x%lx", volumeValuesCount);
/* if some error occured in fwrite */
if (numBytesToRead != 0) {
diff --git a/media/libmedia/IOMX.cpp b/media/libmedia/IOMX.cpp
index 9ce6738..af67175 100644
--- a/media/libmedia/IOMX.cpp
+++ b/media/libmedia/IOMX.cpp
@@ -5,6 +5,7 @@
#include <binder/IMemory.h>
#include <binder/Parcel.h>
#include <media/IOMX.h>
+#include <media/stagefright/foundation/ADebug.h>
#include <surfaceflinger/ISurface.h>
#include <surfaceflinger/Surface.h>
@@ -449,74 +450,8 @@
}
case GET_PARAMETER:
- {
- CHECK_INTERFACE(IOMX, data, reply);
-
- node_id node = (void*)data.readIntPtr();
- OMX_INDEXTYPE index = static_cast<OMX_INDEXTYPE>(data.readInt32());
-
- size_t size = data.readInt32();
-
- // XXX I am not happy with this but Parcel::readInplace didn't work.
- void *params = malloc(size);
- data.read(params, size);
-
- status_t err = getParameter(node, index, params, size);
-
- reply->writeInt32(err);
-
- if (err == OK) {
- reply->write(params, size);
- }
-
- free(params);
- params = NULL;
-
- return NO_ERROR;
- }
-
case SET_PARAMETER:
- {
- CHECK_INTERFACE(IOMX, data, reply);
-
- node_id node = (void*)data.readIntPtr();
- OMX_INDEXTYPE index = static_cast<OMX_INDEXTYPE>(data.readInt32());
-
- size_t size = data.readInt32();
- void *params = const_cast<void *>(data.readInplace(size));
-
- reply->writeInt32(setParameter(node, index, params, size));
-
- return NO_ERROR;
- }
-
case GET_CONFIG:
- {
- CHECK_INTERFACE(IOMX, data, reply);
-
- node_id node = (void*)data.readIntPtr();
- OMX_INDEXTYPE index = static_cast<OMX_INDEXTYPE>(data.readInt32());
-
- size_t size = data.readInt32();
-
- // XXX I am not happy with this but Parcel::readInplace didn't work.
- void *params = malloc(size);
- data.read(params, size);
-
- status_t err = getConfig(node, index, params, size);
-
- reply->writeInt32(err);
-
- if (err == OK) {
- reply->write(params, size);
- }
-
- free(params);
- params = NULL;
-
- return NO_ERROR;
- }
-
case SET_CONFIG:
{
CHECK_INTERFACE(IOMX, data, reply);
@@ -525,9 +460,36 @@
OMX_INDEXTYPE index = static_cast<OMX_INDEXTYPE>(data.readInt32());
size_t size = data.readInt32();
- void *params = const_cast<void *>(data.readInplace(size));
- reply->writeInt32(setConfig(node, index, params, size));
+ void *params = malloc(size);
+ data.read(params, size);
+
+ status_t err;
+ switch (code) {
+ case GET_PARAMETER:
+ err = getParameter(node, index, params, size);
+ break;
+ case SET_PARAMETER:
+ err = setParameter(node, index, params, size);
+ break;
+ case GET_CONFIG:
+ err = getConfig(node, index, params, size);
+ break;
+ case SET_CONFIG:
+ err = setConfig(node, index, params, size);
+ break;
+ default:
+ TRESPASS();
+ }
+
+ reply->writeInt32(err);
+
+ if ((code == GET_PARAMETER || code == GET_CONFIG) && err == OK) {
+ reply->write(params, size);
+ }
+
+ free(params);
+ params = NULL;
return NO_ERROR;
}
diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp
index 54e515a..153b2a6 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.cpp
+++ b/media/libmediaplayerservice/StagefrightRecorder.cpp
@@ -1229,25 +1229,13 @@
}
if (mVideoEncoderLevel != -1) {
enc_meta->setInt32(kKeyVideoLevel, mVideoEncoderLevel);
- } else if (mCaptureTimeLapse) {
- // Check if we are using high resolution and/or high bitrate and
- // set appropriate level for the software AVCEncoder.
- if ((width * height >= 921600) // 720p
- || (videoBitRate >= 20000000)) {
- enc_meta->setInt32(kKeyVideoLevel, OMX_VIDEO_AVCLevel5);
- }
}
OMXClient client;
CHECK_EQ(client.connect(), OK);
- // Use software codec for time lapse
uint32_t encoder_flags = 0;
- if (mCaptureTimeLapse) {
- // Do not use software encoder for timelapse for now
- // It is _very_ slow and the preview appears sluggish
- //encoder_flags |= OMXCodec::kPreferSoftwareCodecs;
- } else if (mIsMetaDataStoredInVideoBuffers) {
+ if (mIsMetaDataStoredInVideoBuffers) {
encoder_flags |= OMXCodec::kHardwareCodecsOnly;
encoder_flags |= OMXCodec::kStoreMetaDataInVideoBuffers;
}
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index 49d05ed..11ac56c 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -58,6 +58,8 @@
static int64_t kLowWaterMarkUs = 2000000ll; // 2secs
static int64_t kHighWaterMarkUs = 10000000ll; // 10secs
+static const size_t kLowWaterMarkBytes = 40000;
+static const size_t kHighWaterMarkBytes = 200000;
struct AwesomeEvent : public TimedEventQueue::Event {
AwesomeEvent(
@@ -165,6 +167,8 @@
mTimeSource(NULL),
mVideoRendererIsPreview(false),
mAudioPlayer(NULL),
+ mDisplayWidth(0),
+ mDisplayHeight(0),
mFlags(0),
mExtractorFlags(0),
mVideoBuffer(NULL),
@@ -329,6 +333,18 @@
if (!haveVideo && !strncasecmp(mime, "video/", 6)) {
setVideoSource(extractor->getTrack(i));
haveVideo = true;
+
+ // Set the presentation/display size
+ int32_t displayWidth, displayHeight;
+ bool success = meta->findInt32(kKeyDisplayWidth, &displayWidth);
+ if (success) {
+ success = meta->findInt32(kKeyDisplayHeight, &displayHeight);
+ }
+ if (success) {
+ mDisplayWidth = displayWidth;
+ mDisplayHeight = displayHeight;
+ }
+
} else if (!haveAudio && !strncasecmp(mime, "audio/", 6)) {
setAudioSource(extractor->getTrack(i));
haveAudio = true;
@@ -370,6 +386,8 @@
void AwesomePlayer::reset_l() {
LOGI("reset_l");
+ mDisplayWidth = 0;
+ mDisplayHeight = 0;
if (mDecryptHandle != NULL) {
mDrmManagerClient->setPlaybackStatus(mDecryptHandle,
@@ -594,9 +612,6 @@
// We don't know the bitrate of the stream, use absolute size
// limits to maintain the cache.
- const size_t kLowWaterMarkBytes = 40000;
- const size_t kHighWaterMarkBytes = 200000;
-
if ((mFlags & PLAYING) && !eos
&& (cachedDataRemaining < kLowWaterMarkBytes)) {
LOGI("cache is running low (< %d) , pausing.",
@@ -862,6 +877,12 @@
int32_t usableWidth = cropRight - cropLeft + 1;
int32_t usableHeight = cropBottom - cropTop + 1;
+ if (mDisplayWidth != 0) {
+ usableWidth = mDisplayWidth;
+ }
+ if (mDisplayHeight != 0) {
+ usableHeight = mDisplayHeight;
+ }
int32_t rotationDegrees;
if (!mVideoTrack->getFormat()->findInt32(
@@ -1513,6 +1534,34 @@
mConnectingDataSource.clear();
dataSource = mCachedSource;
+
+ // We're going to prefill the cache before trying to instantiate
+ // the extractor below, as the latter is an operation that otherwise
+ // could block on the datasource for a significant amount of time.
+ // During that time we'd be unable to abort the preparation phase
+ // without this prefill.
+
+ mLock.unlock();
+
+ for (;;) {
+ status_t finalStatus;
+ size_t cachedDataRemaining =
+ mCachedSource->approxDataRemaining(&finalStatus);
+
+ if (finalStatus != OK || cachedDataRemaining >= kHighWaterMarkBytes
+ || (mFlags & PREPARE_CANCELLED)) {
+ break;
+ }
+
+ usleep(200000);
+ }
+
+ mLock.lock();
+
+ if (mFlags & PREPARE_CANCELLED) {
+ LOGI("Prepare cancelled while waiting for initial cache fill.");
+ return UNKNOWN_ERROR;
+ }
} else if (!strncasecmp(mUri.string(), "httplive://", 11)) {
String8 uri("http://");
uri.append(mUri.string() + 11);
diff --git a/media/libstagefright/CameraSourceTimeLapse.cpp b/media/libstagefright/CameraSourceTimeLapse.cpp
index 31b6ec9..b58b9d8 100644
--- a/media/libstagefright/CameraSourceTimeLapse.cpp
+++ b/media/libstagefright/CameraSourceTimeLapse.cpp
@@ -66,7 +66,7 @@
int32_t videoFrameRate,
const sp<Surface>& surface,
int64_t timeBetweenTimeLapseFrameCaptureUs)
- : CameraSource(camera, cameraId, videoSize, videoFrameRate, surface, false),
+ : CameraSource(camera, cameraId, videoSize, videoFrameRate, surface, true),
mTimeBetweenTimeLapseFrameCaptureUs(timeBetweenTimeLapseFrameCaptureUs),
mTimeBetweenTimeLapseVideoFramesUs(1E6/videoFrameRate),
mLastTimeLapseFrameRealTimestampUs(0),
diff --git a/media/libstagefright/HTTPStream.cpp b/media/libstagefright/HTTPStream.cpp
index e7f00aa..057868c 100644
--- a/media/libstagefright/HTTPStream.cpp
+++ b/media/libstagefright/HTTPStream.cpp
@@ -25,13 +25,14 @@
#include <arpa/inet.h>
#include <ctype.h>
#include <errno.h>
+#include <fcntl.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
-#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/foundation/ADebug.h>
namespace android {
@@ -47,6 +48,82 @@
disconnect();
}
+static bool MakeSocketBlocking(int s, bool blocking) {
+ // Make socket non-blocking.
+ int flags = fcntl(s, F_GETFL, 0);
+ if (flags == -1) {
+ return false;
+ }
+
+ if (blocking) {
+ flags &= ~O_NONBLOCK;
+ } else {
+ flags |= O_NONBLOCK;
+ }
+
+ return fcntl(s, F_SETFL, flags) != -1;
+}
+
+static status_t MyConnect(
+ int s, const struct sockaddr *addr, socklen_t addrlen) {
+ status_t result = UNKNOWN_ERROR;
+
+ MakeSocketBlocking(s, false);
+
+ if (connect(s, addr, addrlen) == 0) {
+ result = OK;
+ } else if (errno != EINPROGRESS) {
+ result = -errno;
+ } else {
+ for (;;) {
+ fd_set rs, ws;
+ FD_ZERO(&rs);
+ FD_ZERO(&ws);
+ FD_SET(s, &rs);
+ FD_SET(s, &ws);
+
+ struct timeval tv;
+ tv.tv_sec = 0;
+ tv.tv_usec = 100000ll;
+
+ int nfds = ::select(s + 1, &rs, &ws, NULL, &tv);
+
+ if (nfds < 0) {
+ if (errno == EINTR) {
+ continue;
+ }
+
+ result = -errno;
+ break;
+ }
+
+ if (FD_ISSET(s, &ws) && !FD_ISSET(s, &rs)) {
+ result = OK;
+ break;
+ }
+
+ if (FD_ISSET(s, &rs) || FD_ISSET(s, &ws)) {
+ // Get the pending error.
+ int error = 0;
+ socklen_t errorLen = sizeof(error);
+ if (getsockopt(s, SOL_SOCKET, SO_ERROR, &error, &errorLen) == -1) {
+ // Couldn't get the real error, so report why not.
+ result = -errno;
+ } else {
+ result = -error;
+ }
+ break;
+ }
+
+ // Timeout expired. Try again.
+ }
+ }
+
+ MakeSocketBlocking(s, true);
+
+ return result;
+}
+
status_t HTTPStream::connect(const char *server, int port) {
Mutex::Autolock autoLock(mLock);
@@ -82,7 +159,7 @@
addr.sin_addr.s_addr = *(in_addr_t *)ent->h_addr;
memset(addr.sin_zero, 0, sizeof(addr.sin_zero));
- int res = ::connect(s, (const struct sockaddr *)&addr, sizeof(addr));
+ status_t res = MyConnect(s, (const struct sockaddr *)&addr, sizeof(addr));
mLock.lock();
@@ -90,12 +167,12 @@
return UNKNOWN_ERROR;
}
- if (res < 0) {
+ if (res != OK) {
close(mSocket);
mSocket = -1;
mState = READY;
- return UNKNOWN_ERROR;
+ return res;
}
mState = CONNECTED;
diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
index bafa243..e6e98aa 100644
--- a/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/MPEG4Extractor.cpp
@@ -1040,8 +1040,23 @@
// have a 4 byte header (0x00 0x00 0x00 0x01) after conversion,
// and thus will grow by 2 bytes per fragment.
mLastTrack->meta->setInt32(kKeyMaxInputSize, max_size + 10 * 2);
-
*offset += chunk_size;
+
+ // Calculate average frame rate.
+ const char *mime;
+ CHECK(mLastTrack->meta->findCString(kKeyMIMEType, &mime));
+ if (!strncasecmp("video/", mime, 6)) {
+ size_t nSamples = mLastTrack->sampleTable->countSamples();
+ int64_t durationUs;
+ if (mLastTrack->meta->findInt64(kKeyDuration, &durationUs)) {
+ if (durationUs > 0) {
+ int32_t frameRate = (nSamples * 1000000LL +
+ (durationUs >> 1)) / durationUs;
+ mLastTrack->meta->setInt32(kKeyFrameRate, frameRate);
+ }
+ }
+ }
+
break;
}
@@ -1321,10 +1336,12 @@
mLastTrack->meta->setInt32(kKeyRotation, rotationDegrees);
}
-#if 0
+ // Handle presentation display size, which could be different
+ // from the image size indicated by kKeyWidth and kKeyHeight.
uint32_t width = U32_AT(&buffer[dynSize + 52]);
uint32_t height = U32_AT(&buffer[dynSize + 56]);
-#endif
+ mLastTrack->meta->setInt32(kKeyDisplayWidth, width >> 16);
+ mLastTrack->meta->setInt32(kKeyDisplayHeight, height >> 16);
return OK;
}
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index 06c4c98..a47ee3a 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -590,6 +590,7 @@
status_t err = OK;
int64_t maxDurationUs = 0;
+ int64_t minDurationUs = 0x7fffffffffffffffLL;
for (List<Track *>::iterator it = mTracks.begin();
it != mTracks.end(); ++it) {
status_t status = (*it)->stop();
@@ -601,6 +602,14 @@
if (durationUs > maxDurationUs) {
maxDurationUs = durationUs;
}
+ if (durationUs < minDurationUs) {
+ minDurationUs = durationUs;
+ }
+ }
+
+ if (mTracks.size() > 1) {
+ LOGD("Duration from tracks range is [%lld, %lld] us",
+ minDurationUs, maxDurationUs);
}
stopWriterThread();
diff --git a/media/libstagefright/NuCachedSource2.cpp b/media/libstagefright/NuCachedSource2.cpp
index 20f1655..741aa1c 100644
--- a/media/libstagefright/NuCachedSource2.cpp
+++ b/media/libstagefright/NuCachedSource2.cpp
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+//#define LOG_NDEBUG 0
#define LOG_TAG "NuCachedSource2"
#include <utils/Log.h>
@@ -487,4 +488,5 @@
String8 NuCachedSource2::getUri() {
return mSource->getUri();
}
+
} // namespace android
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index e516cb4..d842f65 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -2233,7 +2233,11 @@
enablePortAsync(portIndex);
status_t err = allocateBuffersOnPort(portIndex);
- CHECK_EQ(err, (status_t)OK);
+
+ if (err != OK) {
+ CODEC_LOGE("allocateBuffersOnPort failed (err = %d)", err);
+ setState(ERROR);
+ }
}
break;
}
diff --git a/media/libstagefright/httplive/LiveSession.cpp b/media/libstagefright/httplive/LiveSession.cpp
index 5979be6..f20a4cb 100644
--- a/media/libstagefright/httplive/LiveSession.cpp
+++ b/media/libstagefright/httplive/LiveSession.cpp
@@ -438,8 +438,7 @@
if (mSeqNumber < firstSeqNumberInPlaylist
|| mSeqNumber > lastSeqNumberInPlaylist) {
- if (mSeqNumber < firstSeqNumberInPlaylist
- && mPrevBandwidthIndex != (ssize_t)bandwidthIndex) {
+ if (mPrevBandwidthIndex != (ssize_t)bandwidthIndex) {
// Go back to the previous bandwidth.
LOGI("new bandwidth does not have the sequence number "
@@ -493,8 +492,14 @@
CHECK(buffer != NULL);
- CHECK_EQ((status_t)OK,
- decryptBuffer(mSeqNumber - firstSeqNumberInPlaylist, buffer));
+ err = decryptBuffer(mSeqNumber - firstSeqNumberInPlaylist, buffer);
+
+ if (err != OK) {
+ LOGE("decryptBuffer failed w/ error %d", err);
+
+ mDataSource->queueEOS(err);
+ return;
+ }
if (buffer->size() == 0 || buffer->data()[0] != 0x47) {
// Not a transport stream???
diff --git a/media/libstagefright/include/AwesomePlayer.h b/media/libstagefright/include/AwesomePlayer.h
index fe008569..41ef181 100644
--- a/media/libstagefright/include/AwesomePlayer.h
+++ b/media/libstagefright/include/AwesomePlayer.h
@@ -150,6 +150,9 @@
AudioPlayer *mAudioPlayer;
int64_t mDurationUs;
+ int32_t mDisplayWidth;
+ int32_t mDisplayHeight;
+
uint32_t mFlags;
uint32_t mExtractorFlags;
uint32_t mSinceLastDropped;
diff --git a/opengl/java/android/opengl/GLSurfaceView.java b/opengl/java/android/opengl/GLSurfaceView.java
index 4099c4c..32d1a23 100644
--- a/opengl/java/android/opengl/GLSurfaceView.java
+++ b/opengl/java/android/opengl/GLSurfaceView.java
@@ -272,7 +272,6 @@
}
/**
- * @hide
* Control whether the EGL context is preserved when the GLSurfaceView is paused and
* resumed.
* <p>
@@ -295,7 +294,6 @@
}
/**
- * @hide
* @return true if the EGL context will be preserved when paused
*/
public boolean getPreserveEGLContextOnPause() {
diff --git a/packages/SystemUI/res/layout-xlarge/status_bar.xml b/packages/SystemUI/res/layout-xlarge/status_bar.xml
index 0533b6f..852b729 100644
--- a/packages/SystemUI/res/layout-xlarge/status_bar.xml
+++ b/packages/SystemUI/res/layout-xlarge/status_bar.xml
@@ -78,15 +78,14 @@
</LinearLayout>
<!-- fake space bar zone -->
- <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/fake_space_bar"
+ <com.android.systemui.statusbar.policy.EventHole android:id="@+id/fake_space_bar"
android:layout_height="match_parent"
- android:layout_width="match_parent"
+ android:layout_width="0dp"
android:paddingLeft="8dip"
android:paddingRight="8dip"
android:layout_toRightOf="@+id/navigationArea"
android:layout_toLeftOf="@+id/notificationArea"
android:visibility="gone"
- systemui:keyCode="62"
/>
</RelativeLayout>
</FrameLayout>
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/EventHole.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/EventHole.java
new file mode 100644
index 0000000..47e758c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/EventHole.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2008 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.systemui.statusbar.policy;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Region;
+import android.graphics.drawable.AnimationDrawable;
+import android.graphics.drawable.Drawable;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.os.ServiceManager;
+import android.util.AttributeSet;
+import android.util.Slog;
+import android.view.HapticFeedbackConstants;
+import android.view.IWindowManager;
+import android.view.InputDevice;
+import android.view.KeyCharacterMap;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewConfiguration;
+import android.view.ViewTreeObserver;
+import android.widget.RemoteViews.RemoteView;
+
+import com.android.systemui.R;
+
+public class EventHole extends View implements ViewTreeObserver.OnComputeInternalInsetsListener {
+ private static final String TAG = "StatusBar.EventHole";
+
+ private boolean mWindowVis;
+ private int[] mLoc = new int[2];
+
+ public EventHole(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public EventHole(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs);
+ }
+
+ @Override
+ protected void onWindowVisibilityChanged(int visibility) {
+ super.onWindowVisibilityChanged(visibility);
+ mWindowVis = visibility == View.VISIBLE;
+ }
+
+ @Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ getViewTreeObserver().addOnComputeInternalInsetsListener(this);
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ getViewTreeObserver().removeOnComputeInternalInsetsListener(this);
+ }
+
+ public void onComputeInternalInsets(ViewTreeObserver.InternalInsetsInfo info) {
+ final boolean visible = isShown() && mWindowVis && getWidth() > 0 && getHeight() > 0;
+ final int[] loc = mLoc;
+ getLocationInWindow(loc);
+ final int l = loc[0];
+ final int r = l + getWidth();
+ final int t = loc[1];
+ final int b = t + getHeight();
+
+ View top = this;
+ while (top.getParent() instanceof View) {
+ top = (View)top.getParent();
+ }
+
+ if (visible) {
+ info.setTouchableInsets(
+ ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION);
+ info.touchableRegion.set(0, 0, top.getWidth(), top.getHeight());
+ info.touchableRegion.op(l, t, r, b, Region.Op.DIFFERENCE);
+ } else {
+ info.setTouchableInsets(
+ ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME);
+ }
+ }
+}
+
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationPanel.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationPanel.java
index 45a22b6..800f4b4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationPanel.java
@@ -52,7 +52,7 @@
View mNotificationScroller;
View mNotificationGlow;
ViewGroup mContentFrame;
- Rect mContentArea;
+ Rect mContentArea = new Rect();
View mSettingsView;
View mScrim, mGlow;
ViewGroup mContentParent;
@@ -136,7 +136,6 @@
@Override
public void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
- mContentArea = null;
}
public void onClick(View v) {
@@ -165,13 +164,11 @@
}
public boolean isInContentArea(int x, int y) {
- if (mContentArea == null) {
- mContentArea = new Rect(mContentFrame.getLeft(),
- mTitleArea.getTop(),
- mContentFrame.getRight(),
- mContentFrame.getBottom());
- offsetDescendantRectToMyCoords(mContentParent, mContentArea);
- }
+ mContentArea.left = mContentFrame.getLeft();
+ mContentArea.top = mTitleArea.getTop();
+ mContentArea.right = mContentFrame.getRight();
+ mContentArea.bottom = mContentFrame.getBottom();
+ offsetDescendantRectToMyCoords(mContentParent, mContentArea);
return mContentArea.contains(x, y);
}
diff --git a/packages/VpnServices/src/com/android/server/vpn/VpnService.java b/packages/VpnServices/src/com/android/server/vpn/VpnService.java
index 63b87b1..a618423 100644
--- a/packages/VpnServices/src/com/android/server/vpn/VpnService.java
+++ b/packages/VpnServices/src/com/android/server/vpn/VpnService.java
@@ -328,6 +328,7 @@
public void run() {
Log.i(TAG, "VPN connectivity monitor running");
try {
+ mNotification.update(mStartTime); // to pop up notification
for (int i = 10; ; i--) {
long now = System.currentTimeMillis();
@@ -417,13 +418,27 @@
// Helper class for showing, updating notification.
private class NotificationHelper {
+ private NotificationManager mNotificationManager = (NotificationManager)
+ mContext.getSystemService(Context.NOTIFICATION_SERVICE);
+ private Notification mNotification =
+ new Notification(R.drawable.vpn_connected, null, 0L);
+ private PendingIntent mPendingIntent = PendingIntent.getActivity(
+ mContext, 0,
+ new VpnManager(mContext).createSettingsActivityIntent(), 0);
+ private String mConnectedTitle;
+
void update(long now) {
- String title = getNotificationTitle(true);
- Notification n = new Notification(R.drawable.vpn_connected, title,
- mStartTime);
- n.setLatestEventInfo(mContext, title,
+ Notification n = mNotification;
+ if (now == mStartTime) {
+ // to pop up the notification for the first time
+ n.when = mStartTime;
+ n.tickerText = mConnectedTitle = getNotificationTitle(true);
+ } else {
+ n.tickerText = null;
+ }
+ n.setLatestEventInfo(mContext, mConnectedTitle,
getConnectedNotificationMessage(now),
- prepareNotificationIntent());
+ mPendingIntent);
n.flags |= Notification.FLAG_NO_CLEAR;
n.flags |= Notification.FLAG_ONGOING_EVENT;
enableNotification(n);
@@ -435,25 +450,18 @@
title, System.currentTimeMillis());
n.setLatestEventInfo(mContext, title,
getDisconnectedNotificationMessage(),
- prepareNotificationIntent());
+ mPendingIntent);
n.flags |= Notification.FLAG_AUTO_CANCEL;
disableNotification();
enableNotification(n);
}
void disableNotification() {
- ((NotificationManager) mContext.getSystemService(
- Context.NOTIFICATION_SERVICE)).cancel(NOTIFICATION_ID);
+ mNotificationManager.cancel(NOTIFICATION_ID);
}
private void enableNotification(Notification n) {
- ((NotificationManager) mContext.getSystemService(
- Context.NOTIFICATION_SERVICE)).notify(NOTIFICATION_ID, n);
- }
-
- private PendingIntent prepareNotificationIntent() {
- return PendingIntent.getActivity(mContext, 0,
- new VpnManager(mContext).createSettingsActivityIntent(), 0);
+ mNotificationManager.notify(NOTIFICATION_ID, n);
}
private String getNotificationTitle(boolean connected) {
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index fb20e81..c313713b 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -1985,6 +1985,7 @@
}
if (mActionModeView != null) {
+ mActionModeView.killMode();
mode = new StandaloneActionMode(getContext(), mActionModeView, wrappedCallback);
if (callback.onCreateActionMode(mode, mode.getMenu())) {
mode.invalidate();
@@ -2330,12 +2331,10 @@
if (mAlwaysReadCloseOnTouchAttr || getContext().getApplicationInfo().targetSdkVersion
>= android.os.Build.VERSION_CODES.HONEYCOMB) {
- if (!hasSetCloseOnTouchOutside()) {
- if (a.getBoolean(
- com.android.internal.R.styleable.Window_windowCloseOnTouchOutside,
- false)) {
- setCloseOnTouchOutside(true);
- }
+ if (a.getBoolean(
+ com.android.internal.R.styleable.Window_windowCloseOnTouchOutside,
+ false)) {
+ setCloseOnTouchOutsideIfNotSet(true);
}
}
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 51b5947..16c042d 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -131,18 +131,21 @@
: BnAudioFlinger(),
mAudioHardware(0), mMasterVolume(1.0f), mMasterMute(false), mNextUniqueId(1)
{
+ Mutex::Autolock _l(mLock);
+
mHardwareStatus = AUDIO_HW_IDLE;
mAudioHardware = AudioHardwareInterface::create();
mHardwareStatus = AUDIO_HW_INIT;
if (mAudioHardware->initCheck() == NO_ERROR) {
- // open 16-bit output stream for s/w mixer
+ AutoMutex lock(mHardwareLock);
mMode = AudioSystem::MODE_NORMAL;
- setMode(mMode);
-
- setMasterVolume(1.0f);
- setMasterMute(false);
+ mHardwareStatus = AUDIO_HW_SET_MODE;
+ mAudioHardware->setMode(mMode);
+ mHardwareStatus = AUDIO_HW_SET_MASTER_VOLUME;
+ mAudioHardware->setMasterVolume(1.0f);
+ mHardwareStatus = AUDIO_HW_IDLE;
} else {
LOGE("Couldn't even initialize the stubbed audio hardware!");
}
@@ -440,13 +443,16 @@
}
// when hw supports master volume, don't scale in sw mixer
- AutoMutex lock(mHardwareLock);
- mHardwareStatus = AUDIO_HW_SET_MASTER_VOLUME;
- if (mAudioHardware->setMasterVolume(value) == NO_ERROR) {
- value = 1.0f;
+ { // scope for the lock
+ AutoMutex lock(mHardwareLock);
+ mHardwareStatus = AUDIO_HW_SET_MASTER_VOLUME;
+ if (mAudioHardware->setMasterVolume(value) == NO_ERROR) {
+ value = 1.0f;
+ }
+ mHardwareStatus = AUDIO_HW_IDLE;
}
- mHardwareStatus = AUDIO_HW_IDLE;
+ Mutex::Autolock _l(mLock);
mMasterVolume = value;
for (uint32_t i = 0; i < mPlaybackThreads.size(); i++)
mPlaybackThreads.valueAt(i)->setMasterVolume(value);
@@ -517,6 +523,7 @@
return PERMISSION_DENIED;
}
+ Mutex::Autolock _l(mLock);
mMasterMute = muted;
for (uint32_t i = 0; i < mPlaybackThreads.size(); i++)
mPlaybackThreads.valueAt(i)->setMasterMute(muted);
@@ -579,6 +586,7 @@
return BAD_VALUE;
}
+ AutoMutex lock(mLock);
mStreamTypes[stream].mute = muted;
for (uint32_t i = 0; i < mPlaybackThreads.size(); i++)
mPlaybackThreads.valueAt(i)->setStreamMute(stream, muted);
diff --git a/services/audioflinger/AudioPolicyManagerBase.cpp b/services/audioflinger/AudioPolicyManagerBase.cpp
index eeca7ab..e4086c4 100644
--- a/services/audioflinger/AudioPolicyManagerBase.cpp
+++ b/services/audioflinger/AudioPolicyManagerBase.cpp
@@ -1052,25 +1052,27 @@
updateDeviceForStrategy();
#ifdef AUDIO_POLICY_TEST
- AudioParameter outputCmd = AudioParameter();
- outputCmd.addInt(String8("set_id"), 0);
- mpClientInterface->setParameters(mHardwareOutput, outputCmd.toString());
+ if (mHardwareOutput != 0) {
+ AudioParameter outputCmd = AudioParameter();
+ outputCmd.addInt(String8("set_id"), 0);
+ mpClientInterface->setParameters(mHardwareOutput, outputCmd.toString());
- mTestDevice = AudioSystem::DEVICE_OUT_SPEAKER;
- mTestSamplingRate = 44100;
- mTestFormat = AudioSystem::PCM_16_BIT;
- mTestChannels = AudioSystem::CHANNEL_OUT_STEREO;
- mTestLatencyMs = 0;
- mCurOutput = 0;
- mDirectOutput = false;
- for (int i = 0; i < NUM_TEST_OUTPUTS; i++) {
- mTestOutputs[i] = 0;
+ mTestDevice = AudioSystem::DEVICE_OUT_SPEAKER;
+ mTestSamplingRate = 44100;
+ mTestFormat = AudioSystem::PCM_16_BIT;
+ mTestChannels = AudioSystem::CHANNEL_OUT_STEREO;
+ mTestLatencyMs = 0;
+ mCurOutput = 0;
+ mDirectOutput = false;
+ for (int i = 0; i < NUM_TEST_OUTPUTS; i++) {
+ mTestOutputs[i] = 0;
+ }
+
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ snprintf(buffer, SIZE, "AudioPolicyManagerTest");
+ run(buffer, ANDROID_PRIORITY_AUDIO);
}
-
- const size_t SIZE = 256;
- char buffer[SIZE];
- snprintf(buffer, SIZE, "AudioPolicyManagerTest");
- run(buffer, ANDROID_PRIORITY_AUDIO);
#endif //AUDIO_POLICY_TEST
}
@@ -1091,6 +1093,11 @@
mInputs.clear();
}
+status_t AudioPolicyManagerBase::initCheck()
+{
+ return (mHardwareOutput == 0) ? NO_INIT : NO_ERROR;
+}
+
#ifdef AUDIO_POLICY_TEST
bool AudioPolicyManagerBase::threadLoop()
{
diff --git a/services/audioflinger/AudioPolicyService.cpp b/services/audioflinger/AudioPolicyService.cpp
index f24e08e..46a01ad 100644
--- a/services/audioflinger/AudioPolicyService.cpp
+++ b/services/audioflinger/AudioPolicyService.cpp
@@ -68,6 +68,8 @@
{
char value[PROPERTY_VALUE_MAX];
+ Mutex::Autolock _l(mLock);
+
// start tone playback thread
mTonePlaybackThread = new AudioCommandThread(String8(""));
// start audio commands thread
@@ -88,9 +90,18 @@
}
#endif
- // load properties
- property_get("ro.camera.sound.forced", value, "0");
- mpPolicyManager->setSystemProperty("ro.camera.sound.forced", value);
+ if ((mpPolicyManager != NULL) && (mpPolicyManager->initCheck() != NO_ERROR)) {
+ delete mpPolicyManager;
+ mpPolicyManager = NULL;
+ }
+
+ if (mpPolicyManager == NULL) {
+ LOGE("Could not create AudioPolicyManager");
+ } else {
+ // load properties
+ property_get("ro.camera.sound.forced", value, "0");
+ mpPolicyManager->setSystemProperty("ro.camera.sound.forced", value);
+ }
}
AudioPolicyService::~AudioPolicyService()
diff --git a/services/java/com/android/server/AppWidgetService.java b/services/java/com/android/server/AppWidgetService.java
index 22dd804..59a540b 100644
--- a/services/java/com/android/server/AppWidgetService.java
+++ b/services/java/com/android/server/AppWidgetService.java
@@ -16,6 +16,23 @@
package com.android.server;
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.appwidget.AppWidgetManager;
@@ -24,46 +41,37 @@
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.content.Intent.FilterComparison;
import android.content.IntentFilter;
+import android.content.ServiceConnection;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
import android.os.Process;
import android.os.RemoteException;
import android.os.SystemClock;
import android.util.AttributeSet;
+import android.util.Pair;
import android.util.Slog;
import android.util.TypedValue;
import android.util.Xml;
import android.widget.RemoteViews;
-import java.io.IOException;
-import java.io.File;
-import java.io.FileDescriptor;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Locale;
-import java.util.HashMap;
-import java.util.HashSet;
-
-import com.android.internal.appwidget.IAppWidgetService;
import com.android.internal.appwidget.IAppWidgetHost;
+import com.android.internal.appwidget.IAppWidgetService;
import com.android.internal.util.FastXmlSerializer;
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
+import com.android.internal.widget.IRemoteViewsAdapterConnection;
class AppWidgetService extends IAppWidgetService.Stub
{
@@ -107,6 +115,56 @@
Host host;
}
+ /**
+ * Acts as a proxy between the ServiceConnection and the RemoteViewsAdapterConnection.
+ * This needs to be a static inner class since a reference to the ServiceConnection is held
+ * globally and may lead us to leak AppWidgetService instances (if there were more than one).
+ */
+ static class ServiceConnectionProxy implements ServiceConnection {
+ private final AppWidgetService mAppWidgetService;
+ private final Pair<Integer, Intent.FilterComparison> mKey;
+ private final IBinder mConnectionCb;
+
+ ServiceConnectionProxy(AppWidgetService appWidgetService,
+ Pair<Integer, Intent.FilterComparison> key, IBinder connectionCb) {
+ mAppWidgetService = appWidgetService;
+ mKey = key;
+ mConnectionCb = connectionCb;
+ }
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ IRemoteViewsAdapterConnection cb =
+ IRemoteViewsAdapterConnection.Stub.asInterface(mConnectionCb);
+ try {
+ cb.onServiceConnected(service);
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ }
+ }
+ public void onServiceDisconnected(ComponentName name) {
+ IRemoteViewsAdapterConnection cb =
+ IRemoteViewsAdapterConnection.Stub.asInterface(mConnectionCb);
+ try {
+ cb.onServiceDisconnected();
+ mAppWidgetService.mServiceConnectionUpdateHandler.post(new Runnable() {
+ public void run() {
+ // We don't want to touch mBoundRemoteViewsServices from any other thread
+ // so queue this to run on the main thread.
+ if (mAppWidgetService.mBoundRemoteViewsServices.containsKey(mKey)) {
+ mAppWidgetService.mBoundRemoteViewsServices.remove(mKey);
+ }
+ }
+ });
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ // Manages connections to RemoteViewsServices
+ private final HashMap<Pair<Integer, FilterComparison>, ServiceConnection>
+ mBoundRemoteViewsServices = new HashMap<Pair<Integer,FilterComparison>,ServiceConnection>();
+ private final Handler mServiceConnectionUpdateHandler = new Handler();
+
Context mContext;
Locale mLocale;
PackageManager mPackageManager;
@@ -294,6 +352,9 @@
}
void deleteAppWidgetLocked(AppWidgetId id) {
+ // We first unbind all services that are bound to this id
+ unbindAppWidgetRemoteViewsServicesLocked(id);
+
Host host = id.host;
host.instances.remove(id);
pruneHostLocked(host);
@@ -376,6 +437,77 @@
}
}
+ public void bindRemoteViewsService(int appWidgetId, Intent intent, IBinder connection) {
+ synchronized (mAppWidgetIds) {
+ AppWidgetId id = lookupAppWidgetIdLocked(appWidgetId);
+ if (id == null) {
+ throw new IllegalArgumentException("bad appWidgetId");
+ }
+ final ComponentName componentName = intent.getComponent();
+ try {
+ final ServiceInfo si = mContext.getPackageManager().getServiceInfo(componentName,
+ PackageManager.GET_PERMISSIONS);
+ if (!android.Manifest.permission.BIND_REMOTEVIEWS.equals(si.permission)) {
+ throw new SecurityException("Selected service does not require "
+ + android.Manifest.permission.BIND_REMOTEVIEWS
+ + ": " + componentName);
+ }
+ } catch (PackageManager.NameNotFoundException e) {
+ throw new IllegalArgumentException("Unknown component " + componentName);
+ }
+
+ // Bind to the RemoteViewsService (which will trigger a callback to the
+ // RemoteViewsAdapter)
+ Pair<Integer, FilterComparison> key = Pair.create(appWidgetId,
+ new FilterComparison(intent));
+ final ServiceConnection conn = new ServiceConnectionProxy(this, key, connection);
+ final long token = Binder.clearCallingIdentity();
+ try {
+ mContext.bindService(intent, conn, Context.BIND_AUTO_CREATE);
+ mBoundRemoteViewsServices.put(key, conn);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+ }
+
+ public void unbindRemoteViewsService(int appWidgetId, Intent intent) {
+ synchronized (mAppWidgetIds) {
+ AppWidgetId id = lookupAppWidgetIdLocked(appWidgetId);
+ if (id == null) {
+ throw new IllegalArgumentException("bad appWidgetId");
+ }
+
+ // Unbind from the RemoteViewsService (which will trigger a callback to the bound
+ // RemoteViewsAdapter)
+ Pair<Integer, FilterComparison> key = Pair.create(appWidgetId,
+ new FilterComparison(intent));
+ if (mBoundRemoteViewsServices.containsKey(key)) {
+ final ServiceConnection conn = mBoundRemoteViewsServices.get(key);
+ mBoundRemoteViewsServices.remove(key);
+ conn.onServiceDisconnected(null);
+ mContext.unbindService(conn);
+ }
+ }
+ }
+
+ private void unbindAppWidgetRemoteViewsServicesLocked(AppWidgetId id) {
+ Iterator<Pair<Integer, Intent.FilterComparison>> it =
+ mBoundRemoteViewsServices.keySet().iterator();
+ int appWidgetId = id.appWidgetId;
+
+ // Unbind all connections to AppWidgets bound to this id
+ while (it.hasNext()) {
+ final Pair<Integer, Intent.FilterComparison> key = it.next();
+ if (key.first.intValue() == appWidgetId) {
+ final ServiceConnection conn = mBoundRemoteViewsServices.get(key);
+ it.remove();
+ conn.onServiceDisconnected(null);
+ mContext.unbindService(conn);
+ }
+ }
+ }
+
public AppWidgetProviderInfo getAppWidgetInfo(int appWidgetId) {
synchronized (mAppWidgetIds) {
AppWidgetId id = lookupAppWidgetIdLocked(appWidgetId);
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index 3e930ae..b7ff64d 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -583,7 +583,7 @@
void broadcastDragStartedLw(final float touchX, final float touchY) {
// Cache a base-class instance of the clip metadata so that parceling
// works correctly in calling out to the apps.
- mDataDescription = mData.getDescription();
+ mDataDescription = (mData != null) ? mData.getDescription() : null;
mNotifiedWindows.clear();
mDragInProgress = true;
@@ -708,16 +708,20 @@
// Move the surface to the given touch
if (SHOW_TRANSACTIONS) Slog.i(TAG, ">>> OPEN TRANSACTION notifyMoveLw");
- mSurface.openTransaction();
+ Surface.openTransaction();
try {
mSurface.setPosition((int)(x - mThumbOffsetX), (int)(y - mThumbOffsetY));
} finally {
- mSurface.closeTransaction();
+ Surface.closeTransaction();
if (SHOW_TRANSACTIONS) Slog.i(TAG, "<<< CLOSE TRANSACTION notifyMoveLw");
}
// Tell the affected window
WindowState touchedWin = getTouchedWinAtPointLw(x, y);
+ if (touchedWin == null) {
+ if (DEBUG_DRAG) Slog.d(TAG, "No touched win at x=" + x + " y=" + y);
+ return;
+ }
if ((mFlags & View.DRAG_FLAG_GLOBAL) == 0) {
final IBinder touchedBinder = touchedWin.mClient.asBinder();
if (touchedBinder != mLocalWin) {
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index dbf9a96..9e9a4f2 100755
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -3060,7 +3060,7 @@
}
if (uid == pkgUid || checkComponentPermission(
android.Manifest.permission.CLEAR_APP_USER_DATA,
- pid, uid, -1)
+ pid, uid, -1, true)
== PackageManager.PERMISSION_GRANTED) {
forceStopPackageLocked(packageName, pkgUid);
} else {
@@ -4151,7 +4151,7 @@
* This can be called with or without the global lock held.
*/
int checkComponentPermission(String permission, int pid, int uid,
- int reqUid) {
+ int owningUid, boolean exported) {
// We might be performing an operation on behalf of an indirect binder
// invocation, e.g. via {@link #openContentUri}. Check and adjust the
// client identity accordingly before proceeding.
@@ -4168,9 +4168,14 @@
!Process.supportsProcesses()) {
return PackageManager.PERMISSION_GRANTED;
}
- // If the target requires a specific UID, always fail for others.
- if (reqUid >= 0 && uid != reqUid) {
- Slog.w(TAG, "Permission denied: checkComponentPermission() reqUid=" + reqUid);
+ // If there is a uid that owns whatever is being accessed, it has
+ // blanket access to it regardless of the permissions it requires.
+ if (owningUid >= 0 && uid == owningUid) {
+ return PackageManager.PERMISSION_GRANTED;
+ }
+ // If the target is not exported, then nobody else can get to it.
+ if (!exported) {
+ Slog.w(TAG, "Permission denied: checkComponentPermission() owningUid=" + owningUid);
return PackageManager.PERMISSION_DENIED;
}
if (permission == null) {
@@ -4199,7 +4204,7 @@
if (permission == null) {
return PackageManager.PERMISSION_DENIED;
}
- return checkComponentPermission(permission, pid, uid, -1);
+ return checkComponentPermission(permission, pid, uid, -1, true);
}
/**
@@ -5322,12 +5327,12 @@
final int callingPid = (r != null) ? r.pid : Binder.getCallingPid();
final int callingUid = (r != null) ? r.info.uid : Binder.getCallingUid();
if (checkComponentPermission(cpi.readPermission, callingPid, callingUid,
- cpi.exported ? -1 : cpi.applicationInfo.uid)
+ cpi.applicationInfo.uid, cpi.exported)
== PackageManager.PERMISSION_GRANTED) {
return null;
}
if (checkComponentPermission(cpi.writePermission, callingPid, callingUid,
- cpi.exported ? -1 : cpi.applicationInfo.uid)
+ cpi.applicationInfo.uid, cpi.exported)
== PackageManager.PERMISSION_GRANTED) {
return null;
}
@@ -5339,12 +5344,12 @@
i--;
PathPermission pp = pps[i];
if (checkComponentPermission(pp.getReadPermission(), callingPid, callingUid,
- cpi.exported ? -1 : cpi.applicationInfo.uid)
+ cpi.applicationInfo.uid, cpi.exported)
== PackageManager.PERMISSION_GRANTED) {
return null;
}
if (checkComponentPermission(pp.getWritePermission(), callingPid, callingUid,
- cpi.exported ? -1 : cpi.applicationInfo.uid)
+ cpi.applicationInfo.uid, cpi.exported)
== PackageManager.PERMISSION_GRANTED) {
return null;
}
@@ -5360,10 +5365,18 @@
}
}
- String msg = "Permission Denial: opening provider " + cpi.name
- + " from " + (r != null ? r : "(null)") + " (pid=" + callingPid
- + ", uid=" + callingUid + ") requires "
- + cpi.readPermission + " or " + cpi.writePermission;
+ String msg;
+ if (!cpi.exported) {
+ msg = "Permission Denial: opening provider " + cpi.name
+ + " from " + (r != null ? r : "(null)") + " (pid=" + callingPid
+ + ", uid=" + callingUid + ") that is not exported from uid "
+ + cpi.applicationInfo.uid;
+ } else {
+ msg = "Permission Denial: opening provider " + cpi.name
+ + " from " + (r != null ? r : "(null)") + " (pid=" + callingPid
+ + ", uid=" + callingUid + ") requires "
+ + cpi.readPermission + " or " + cpi.writePermission;
+ }
Slog.w(TAG, msg);
return msg;
}
@@ -5953,7 +5966,7 @@
final int perm = checkComponentPermission(
android.Manifest.permission.STOP_APP_SWITCHES, callingPid,
- callingUid, -1);
+ callingUid, -1, true);
if (perm == PackageManager.PERMISSION_GRANTED) {
return true;
}
@@ -6804,6 +6817,9 @@
if (info.durationMillis != -1) {
sb.append("Duration-Millis: ").append(info.durationMillis).append("\n");
}
+ if (info.numInstances != -1) {
+ sb.append("Instance-Count: ").append(info.numInstances).append("\n");
+ }
if (info.tags != null) {
for (String tag : info.tags) {
sb.append("Span-Tag: ").append(tag).append("\n");
@@ -8892,8 +8908,16 @@
int callingPid = Binder.getCallingPid();
int callingUid = Binder.getCallingUid();
if (checkComponentPermission(r.permission,
- callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
+ callingPid, callingUid, r.appInfo.uid, r.exported)
!= PackageManager.PERMISSION_GRANTED) {
+ if (!r.exported) {
+ Slog.w(TAG, "Permission Denial: Accessing service " + r.name
+ + " from pid=" + callingPid
+ + ", uid=" + callingUid
+ + " that is not exported from uid " + r.appInfo.uid);
+ return new ServiceLookupResult(null, "not exported from uid "
+ + r.appInfo.uid);
+ }
Slog.w(TAG, "Permission Denial: Accessing service " + r.name
+ " from pid=" + callingPid
+ ", uid=" + callingUid
@@ -8975,11 +8999,19 @@
}
if (r != null) {
if (checkComponentPermission(r.permission,
- callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
+ callingPid, callingUid, r.appInfo.uid, r.exported)
!= PackageManager.PERMISSION_GRANTED) {
+ if (!r.exported) {
+ Slog.w(TAG, "Permission Denial: Accessing service " + r.name
+ + " from pid=" + callingPid
+ + ", uid=" + callingUid
+ + " that is not exported from uid " + r.appInfo.uid);
+ return new ServiceLookupResult(null, "not exported from uid "
+ + r.appInfo.uid);
+ }
Slog.w(TAG, "Permission Denial: Accessing service " + r.name
- + " from pid=" + Binder.getCallingPid()
- + ", uid=" + Binder.getCallingUid()
+ + " from pid=" + callingPid
+ + ", uid=" + callingUid
+ " requires " + r.permission);
return new ServiceLookupResult(null, r.permission);
}
@@ -10479,7 +10511,7 @@
|| uidRemoved) {
if (checkComponentPermission(
android.Manifest.permission.BROADCAST_PACKAGE_REMOVED,
- callingPid, callingUid, -1)
+ callingPid, callingUid, -1, true)
== PackageManager.PERMISSION_GRANTED) {
if (uidRemoved) {
final Bundle intentExtras = intent.getExtras();
@@ -11147,7 +11179,7 @@
boolean skip = false;
if (filter.requiredPermission != null) {
int perm = checkComponentPermission(filter.requiredPermission,
- r.callingPid, r.callingUid, -1);
+ r.callingPid, r.callingUid, -1, true);
if (perm != PackageManager.PERMISSION_GRANTED) {
Slog.w(TAG, "Permission Denial: broadcasting "
+ r.intent.toString()
@@ -11160,7 +11192,7 @@
}
if (r.requiredPermission != null) {
int perm = checkComponentPermission(r.requiredPermission,
- filter.receiverList.pid, filter.receiverList.uid, -1);
+ filter.receiverList.pid, filter.receiverList.uid, -1, true);
if (perm != PackageManager.PERMISSION_GRANTED) {
Slog.w(TAG, "Permission Denial: receiving "
+ r.intent.toString()
@@ -11426,17 +11458,26 @@
boolean skip = false;
int perm = checkComponentPermission(info.activityInfo.permission,
- r.callingPid, r.callingUid,
- info.activityInfo.exported
- ? -1 : info.activityInfo.applicationInfo.uid);
+ r.callingPid, r.callingUid, info.activityInfo.applicationInfo.uid,
+ info.activityInfo.exported);
if (perm != PackageManager.PERMISSION_GRANTED) {
- Slog.w(TAG, "Permission Denial: broadcasting "
- + r.intent.toString()
- + " from " + r.callerPackage + " (pid=" + r.callingPid
- + ", uid=" + r.callingUid + ")"
- + " requires " + info.activityInfo.permission
- + " due to receiver " + info.activityInfo.packageName
- + "/" + info.activityInfo.name);
+ if (!info.activityInfo.exported) {
+ Slog.w(TAG, "Permission Denial: broadcasting "
+ + r.intent.toString()
+ + " from " + r.callerPackage + " (pid=" + r.callingPid
+ + ", uid=" + r.callingUid + ")"
+ + " is not exported from uid " + info.activityInfo.applicationInfo.uid
+ + " due to receiver " + info.activityInfo.packageName
+ + "/" + info.activityInfo.name);
+ } else {
+ Slog.w(TAG, "Permission Denial: broadcasting "
+ + r.intent.toString()
+ + " from " + r.callerPackage + " (pid=" + r.callingPid
+ + ", uid=" + r.callingUid + ")"
+ + " requires " + info.activityInfo.permission
+ + " due to receiver " + info.activityInfo.packageName
+ + "/" + info.activityInfo.name);
+ }
skip = true;
}
if (r.callingUid != Process.SYSTEM_UID &&
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index bc00478..dd6ddd6 100644
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -2035,17 +2035,25 @@
}
final int perm = mService.checkComponentPermission(aInfo.permission, callingPid,
- callingUid, aInfo.exported ? -1 : aInfo.applicationInfo.uid);
+ callingUid, aInfo.applicationInfo.uid, aInfo.exported);
if (perm != PackageManager.PERMISSION_GRANTED) {
if (resultRecord != null) {
sendActivityResultLocked(-1,
resultRecord, resultWho, requestCode,
Activity.RESULT_CANCELED, null);
}
- String msg = "Permission Denial: starting " + intent.toString()
- + " from " + callerApp + " (pid=" + callingPid
- + ", uid=" + callingUid + ")"
- + " requires " + aInfo.permission;
+ String msg;
+ if (!aInfo.exported) {
+ msg = "Permission Denial: starting " + intent.toString()
+ + " from " + callerApp + " (pid=" + callingPid
+ + ", uid=" + callingUid + ")"
+ + " not exported from uid " + aInfo.applicationInfo.uid;
+ } else {
+ msg = "Permission Denial: starting " + intent.toString()
+ + " from " + callerApp + " (pid=" + callingPid
+ + ", uid=" + callingUid + ")"
+ + " requires " + aInfo.permission;
+ }
Slog.w(TAG, msg);
throw new SecurityException(msg);
}
diff --git a/services/surfaceflinger/LayerBase.cpp b/services/surfaceflinger/LayerBase.cpp
index 0c1fcf9..9ddb05f 100644
--- a/services/surfaceflinger/LayerBase.cpp
+++ b/services/surfaceflinger/LayerBase.cpp
@@ -534,6 +534,12 @@
result.append(buffer);
}
+void LayerBase::shortDump(String8& result, char* scratch, size_t size) const
+{
+ LayerBase::dump(result, scratch, size);
+}
+
+
// ---------------------------------------------------------------------------
int32_t LayerBaseClient::sIdentity = 1;
@@ -585,6 +591,12 @@
result.append(buffer);
}
+
+void LayerBaseClient::shortDump(String8& result, char* scratch, size_t size) const
+{
+ LayerBaseClient::dump(result, scratch, size);
+}
+
// ---------------------------------------------------------------------------
LayerBaseClient::Surface::Surface(
diff --git a/services/surfaceflinger/LayerBase.h b/services/surfaceflinger/LayerBase.h
index f6c49fc..13af223 100644
--- a/services/surfaceflinger/LayerBase.h
+++ b/services/surfaceflinger/LayerBase.h
@@ -211,6 +211,7 @@
/** always call base class first */
virtual void dump(String8& result, char* scratch, size_t size) const;
+ virtual void shortDump(String8& result, char* scratch, size_t size) const;
enum { // flags for doTransaction()
@@ -324,6 +325,7 @@
protected:
virtual void dump(String8& result, char* scratch, size_t size) const;
+ virtual void shortDump(String8& result, char* scratch, size_t size) const;
private:
mutable Mutex mLock;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 65ad956..434e473 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1491,8 +1491,13 @@
result.append(buffer);
}
+ /*
+ * Dump the visible layer list
+ */
const LayerVector& currentLayers = mCurrentState.layersSortedByZ;
const size_t count = currentLayers.size();
+ snprintf(buffer, SIZE, "Visible layers (count = %d)\n", count);
+ result.append(buffer);
for (size_t i=0 ; i<count ; i++) {
const sp<LayerBase>& layer(currentLayers[i]);
layer->dump(result, buffer, SIZE);
@@ -1502,6 +1507,24 @@
layer->visibleRegionScreen.dump(result, "visibleRegionScreen");
}
+ /*
+ * Dump the layers in the purgatory
+ */
+
+ const size_t purgatorySize = mLayerPurgatory.size();
+ snprintf(buffer, SIZE, "Purgatory state (%d entries)\n", purgatorySize);
+ result.append(buffer);
+ for (size_t i=0 ; i<purgatorySize ; i++) {
+ const sp<LayerBase>& layer(mLayerPurgatory.itemAt(i));
+ layer->shortDump(result, buffer, SIZE);
+ }
+
+ /*
+ * Dump SurfaceFlinger global state
+ */
+
+ snprintf(buffer, SIZE, "SurfaceFlinger global state\n");
+ result.append(buffer);
mWormholeRegion.dump(result, "WormholeRegion");
const DisplayHardware& hw(graphicPlane(0).displayHardware());
snprintf(buffer, SIZE,
@@ -1527,6 +1550,9 @@
result.append(buffer);
}
+ /*
+ * Dump HWComposer state
+ */
HWComposer& hwc(hw.getHwComposer());
snprintf(buffer, SIZE, " h/w composer %s and %s\n",
hwc.initCheck()==NO_ERROR ? "present" : "not present",
@@ -1534,6 +1560,9 @@
result.append(buffer);
hwc.dump(result, buffer, SIZE);
+ /*
+ * Dump gralloc state
+ */
const GraphicBufferAllocator& alloc(GraphicBufferAllocator::get());
alloc.dump(result);
hw.dump(result);
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/LoadTestsAutoTest.java b/tests/DumpRenderTree/src/com/android/dumprendertree/LoadTestsAutoTest.java
index e5a46b9..5bcf727 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/LoadTestsAutoTest.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/LoadTestsAutoTest.java
@@ -89,13 +89,12 @@
}
private void freeMem() {
- Log.v(LOGTAG, "freeMem: calling gc/finalization...");
+ Log.v(LOGTAG, "freeMem: calling gc...");
final VMRuntime runtime = VMRuntime.getRuntime();
runtime.gcSoftReferences();
runtime.gcSoftReferences();
runtime.gcSoftReferences();
- Runtime.getRuntime().runFinalization();
Runtime.getRuntime().gc();
Runtime.getRuntime().gc();
diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml
index 691aff28..7a61b3c 100644
--- a/tests/HwAccelerationTest/AndroidManifest.xml
+++ b/tests/HwAccelerationTest/AndroidManifest.xml
@@ -53,6 +53,15 @@
</activity>
<activity
+ android:name="ViewLayersActivity3"
+ android:label="_ViewLayers3">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+
+ <activity
android:name="AlphaLayersActivity"
android:label="_αLayers">
<intent-filter>
diff --git a/tests/HwAccelerationTest/res/layout/view_layers_3.xml b/tests/HwAccelerationTest/res/layout/view_layers_3.xml
new file mode 100644
index 0000000..a820f5f
--- /dev/null
+++ b/tests/HwAccelerationTest/res/layout/view_layers_3.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="horizontal"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <LinearLayout
+ android:background="#30ff0000"
+ android:layout_width="0dip"
+ android:layout_height="match_parent"
+ android:layout_weight="1" />
+
+ <LinearLayout
+ android:background="#3000ff00"
+ android:layout_width="0dip"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:padding="12dip">
+
+ <ListView
+ android:id="@+id/list1"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
+
+ </LinearLayout>
+
+ <LinearLayout
+ android:background="#300000ff"
+ android:layout_width="0dip"
+ android:layout_height="match_parent"
+ android:layout_weight="1" />
+
+</LinearLayout>
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/ViewLayersActivity3.java b/tests/HwAccelerationTest/src/com/android/test/hwui/ViewLayersActivity3.java
new file mode 100644
index 0000000..c8ae75b
--- /dev/null
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/ViewLayersActivity3.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.test.hwui;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.res.Resources;
+import android.os.Bundle;
+import android.util.DisplayMetrics;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.ListView;
+import android.widget.TextView;
+
+@SuppressWarnings({"UnusedDeclaration"})
+public class ViewLayersActivity3 extends Activity {
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ setContentView(R.layout.view_layers_3);
+
+ setupList(R.id.list1);
+ }
+
+ private void setupList(int listId) {
+ final ListView list = (ListView) findViewById(listId);
+ list.setAdapter(new SimpleListAdapter(this));
+ list.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+ ((View) list.getParent()).setLayerType(View.LAYER_TYPE_HARDWARE, null);
+ }
+
+ private static class SimpleListAdapter extends ArrayAdapter<String> {
+ public SimpleListAdapter(Context context) {
+ super(context, android.R.layout.simple_list_item_1, DATA_LIST);
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ TextView v = (TextView) super.getView(position, convertView, parent);
+ final Resources r = getContext().getResources();
+ final DisplayMetrics metrics = r.getDisplayMetrics();
+ v.setCompoundDrawablePadding((int) (6 * metrics.density + 0.5f));
+ v.setCompoundDrawablesWithIntrinsicBounds(r.getDrawable(R.drawable.icon),
+ null, null, null);
+ return v;
+ }
+ }
+
+ private static final String[] DATA_LIST = {
+ "Afghanistan", "Albania", "Algeria", "American Samoa", "Andorra",
+ "Angola", "Anguilla", "Antarctica", "Antigua and Barbuda", "Argentina",
+ "Armenia", "Aruba", "Australia", "Austria", "Azerbaijan",
+ "Bahrain", "Bangladesh", "Barbados", "Belarus", "Belgium",
+ "Belize", "Benin", "Bermuda", "Bhutan", "Bolivia",
+ "Bosnia and Herzegovina", "Botswana", "Bouvet Island", "Brazil",
+ "British Indian Ocean Territory", "British Virgin Islands", "Brunei", "Bulgaria",
+ "Burkina Faso", "Burundi", "Cote d'Ivoire", "Cambodia", "Cameroon", "Canada", "Cape Verde",
+ "Cayman Islands", "Central African Republic", "Chad", "Chile", "China",
+ "Christmas Island", "Cocos (Keeling) Islands", "Colombia", "Comoros", "Congo",
+ "Cook Islands", "Costa Rica", "Croatia", "Cuba", "Cyprus", "Czech Republic",
+ "Democratic Republic of the Congo", "Denmark", "Djibouti", "Dominica", "Dominican Republic",
+ "East Timor", "Ecuador", "Egypt", "El Salvador", "Equatorial Guinea", "Eritrea",
+ "Estonia", "Ethiopia", "Faeroe Islands", "Falkland Islands", "Fiji", "Finland",
+ "Former Yugoslav Republic of Macedonia", "France", "French Guiana", "French Polynesia",
+ "French Southern Territories", "Gabon", "Georgia", "Germany", "Ghana", "Gibraltar",
+ "Greece", "Greenland", "Grenada", "Guadeloupe", "Guam", "Guatemala", "Guinea", "Guinea-Bissau",
+ "Guyana", "Haiti", "Heard Island and McDonald Islands", "Honduras", "Hong Kong", "Hungary",
+ "Iceland", "India", "Indonesia", "Iran", "Iraq", "Ireland", "Israel", "Italy", "Jamaica",
+ "Japan", "Jordan", "Kazakhstan", "Kenya", "Kiribati", "Kuwait", "Kyrgyzstan", "Laos",
+ "Latvia", "Lebanon", "Lesotho", "Liberia", "Libya", "Liechtenstein", "Lithuania", "Luxembourg",
+ "Macau", "Madagascar", "Malawi", "Malaysia", "Maldives", "Mali", "Malta", "Marshall Islands",
+ "Martinique", "Mauritania", "Mauritius", "Mayotte", "Mexico", "Micronesia", "Moldova",
+ "Monaco", "Mongolia", "Montserrat", "Morocco", "Mozambique", "Myanmar", "Namibia",
+ "Nauru", "Nepal", "Netherlands", "Netherlands Antilles", "New Caledonia", "New Zealand",
+ "Nicaragua", "Niger", "Nigeria", "Niue", "Norfolk Island", "North Korea", "Northern Marianas",
+ "Norway", "Oman", "Pakistan", "Palau", "Panama", "Papua New Guinea", "Paraguay", "Peru",
+ "Philippines", "Pitcairn Islands", "Poland", "Portugal", "Puerto Rico", "Qatar",
+ "Reunion", "Romania", "Russia", "Rwanda", "Sqo Tome and Principe", "Saint Helena",
+ "Saint Kitts and Nevis", "Saint Lucia", "Saint Pierre and Miquelon",
+ "Saint Vincent and the Grenadines", "Samoa", "San Marino", "Saudi Arabia", "Senegal",
+ "Seychelles", "Sierra Leone", "Singapore", "Slovakia", "Slovenia", "Solomon Islands",
+ "Somalia", "South Africa", "South Georgia and the South Sandwich Islands", "South Korea",
+ "Spain", "Sri Lanka", "Sudan", "Suriname", "Svalbard and Jan Mayen", "Swaziland", "Sweden",
+ "Switzerland", "Syria", "Taiwan", "Tajikistan", "Tanzania", "Thailand", "The Bahamas",
+ "The Gambia", "Togo", "Tokelau", "Tonga", "Trinidad and Tobago", "Tunisia", "Turkey",
+ "Turkmenistan", "Turks and Caicos Islands", "Tuvalu", "Virgin Islands", "Uganda",
+ "Ukraine", "United Arab Emirates", "United Kingdom",
+ "United States", "United States Minor Outlying Islands", "Uruguay", "Uzbekistan",
+ "Vanuatu", "Vatican City", "Venezuela", "Vietnam", "Wallis and Futuna", "Western Sahara",
+ "Yemen", "Yugoslavia", "Zambia", "Zimbabwe"
+ };
+}
diff --git a/wifi/java/android/net/wifi/WifiStateMachine.java b/wifi/java/android/net/wifi/WifiStateMachine.java
index 0548b4d..df21399 100644
--- a/wifi/java/android/net/wifi/WifiStateMachine.java
+++ b/wifi/java/android/net/wifi/WifiStateMachine.java
@@ -61,7 +61,6 @@
import android.provider.Settings;
import android.util.EventLog;
import android.util.Log;
-import android.util.Slog;
import android.app.backup.IBackupManager;
import android.bluetooth.BluetoothAdapter;
import android.content.BroadcastReceiver;
@@ -1671,10 +1670,18 @@
nwService.startAccessPoint((WifiConfiguration) message.obj,
mInterfaceName,
SOFTAP_IFACE);
- } catch(Exception e) {
- Log.e(TAG, "Exception in startAccessPoint()");
- sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_AP_STATE_FAILED, 0));
- break;
+ } catch (Exception e) {
+ Log.e(TAG, "Exception in softap start " + e);
+ try {
+ nwService.stopAccessPoint();
+ nwService.startAccessPoint((WifiConfiguration) message.obj,
+ mInterfaceName,
+ SOFTAP_IFACE);
+ } catch (Exception ee) {
+ Log.e(TAG, "Exception during softap restart : " + ee);
+ sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_AP_STATE_FAILED, 0));
+ break;
+ }
}
Log.d(TAG, "Soft AP start successful");
setWifiApState(WIFI_AP_STATE_ENABLED);
@@ -2824,13 +2831,16 @@
mInterfaceName,
SOFTAP_IFACE);
} catch(Exception e) {
- Log.e(TAG, "Exception in nwService during soft AP set");
+ Log.e(TAG, "Exception in softap set " + e);
try {
nwService.stopAccessPoint();
+ nwService.startAccessPoint((WifiConfiguration) message.obj,
+ mInterfaceName,
+ SOFTAP_IFACE);
} catch (Exception ee) {
- Slog.e(TAG, "Could not stop AP, :" + ee);
+ Log.e(TAG, "Could not restart softap after set failed " + ee);
+ sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_AP_STATE_FAILED, 0));
}
- sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_AP_STATE_FAILED, 0));
}
break;
/* Fail client mode operation when soft AP is enabled */