diff options
375 files changed, 14322 insertions, 4402 deletions
diff --git a/Android.mk b/Android.mk index 90ffcd33ccb1..358bcc6a43ae 100644 --- a/Android.mk +++ b/Android.mk @@ -165,7 +165,7 @@ LOCAL_SRC_FILES += \ core/java/com/android/internal/view/IInputMethodSession.aidl \ core/java/com/android/internal/widget/IRemoteViewsFactory.aidl \ core/java/com/android/internal/widget/IRemoteViewsAdapterConnection.aidl \ - keystore/java/android/security/IKeyChainAliasResponse.aidl \ + keystore/java/android/security/IKeyChainAliasCallback.aidl \ keystore/java/android/security/IKeyChainService.aidl \ location/java/android/location/ICountryDetector.aidl \ location/java/android/location/ICountryListener.aidl \ diff --git a/CleanSpec.mk b/CleanSpec.mk index 1e59ff6da7d2..8d3463654ef5 100644 --- a/CleanSpec.mk +++ b/CleanSpec.mk @@ -99,6 +99,7 @@ $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framew $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates) $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libstagefright_intermediates) $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/core/java/android/os) +$(call add-clean-step, rm -rf $(OUT_DIR)target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/keystore/java/android/security/IKeyChainAliasResponse.java) # ************************************************ # NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST # ************************************************ diff --git a/api/13.xml b/api/13.xml index ff279e10f0c6..9af0640c728a 100644 --- a/api/13.xml +++ b/api/13.xml @@ -1024,6 +1024,17 @@ visibility="public" > </field> +<field name="SET_POINTER_SPEED" + type="java.lang.String" + transient="false" + volatile="false" + value=""android.permission.SET_POINTER_SPEED"" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="SET_PREFERRED_APPLICATIONS" type="java.lang.String" transient="false" @@ -3128,6 +3139,17 @@ visibility="public" > </field> +<field name="compatibleWidthLimitDp" + type="int" + transient="false" + volatile="false" + value="16843621" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="completionHint" type="int" transient="false" @@ -5878,6 +5900,17 @@ visibility="public" > </field> +<field name="largestWidthLimitDp" + type="int" + transient="false" + volatile="false" + value="16843622" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="launchMode" type="int" transient="false" @@ -7913,6 +7946,17 @@ visibility="public" > </field> +<field name="requiresSmallestWidthDp" + type="int" + transient="false" + volatile="false" + value="16843620" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="resizeMode" type="int" transient="false" @@ -15164,6 +15208,325 @@ visibility="public" > </field> +<field name="TextAppearance_Holo" + type="int" + transient="false" + volatile="false" + value="16974075" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="TextAppearance_Holo_DialogWindowTitle" + type="int" + transient="false" + volatile="false" + value="16974103" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="TextAppearance_Holo_Inverse" + type="int" + transient="false" + volatile="false" + value="16974076" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="TextAppearance_Holo_Large" + type="int" + transient="false" + volatile="false" + value="16974077" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="TextAppearance_Holo_Large_Inverse" + type="int" + transient="false" + volatile="false" + value="16974078" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="TextAppearance_Holo_Medium" + type="int" + transient="false" + volatile="false" + value="16974079" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="TextAppearance_Holo_Medium_Inverse" + type="int" + transient="false" + volatile="false" + value="16974080" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="TextAppearance_Holo_SearchResult_Subtitle" + type="int" + transient="false" + volatile="false" + value="16974084" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="TextAppearance_Holo_SearchResult_Title" + type="int" + transient="false" + volatile="false" + value="16974083" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="TextAppearance_Holo_Small" + type="int" + transient="false" + volatile="false" + value="16974081" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="TextAppearance_Holo_Small_Inverse" + type="int" + transient="false" + volatile="false" + value="16974082" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="TextAppearance_Holo_Widget" + type="int" + transient="false" + volatile="false" + value="16974085" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="TextAppearance_Holo_Widget_ActionBar_Subtitle" + type="int" + transient="false" + volatile="false" + value="16974099" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="TextAppearance_Holo_Widget_ActionBar_Title" + type="int" + transient="false" + volatile="false" + value="16974098" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="TextAppearance_Holo_Widget_ActionMode_Subtitle" + type="int" + transient="false" + volatile="false" + value="16974101" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="TextAppearance_Holo_Widget_ActionMode_Title" + type="int" + transient="false" + volatile="false" + value="16974100" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="TextAppearance_Holo_Widget_Button" + type="int" + transient="false" + volatile="false" + value="16974086" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="TextAppearance_Holo_Widget_DropDownHint" + type="int" + transient="false" + volatile="false" + value="16974091" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="TextAppearance_Holo_Widget_DropDownItem" + type="int" + transient="false" + volatile="false" + value="16974092" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="TextAppearance_Holo_Widget_EditText" + type="int" + transient="false" + volatile="false" + value="16974094" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="TextAppearance_Holo_Widget_IconMenu_Item" + type="int" + transient="false" + volatile="false" + value="16974087" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="TextAppearance_Holo_Widget_PopupMenu" + type="int" + transient="false" + volatile="false" + value="16974095" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="TextAppearance_Holo_Widget_PopupMenu_Large" + type="int" + transient="false" + volatile="false" + value="16974096" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="TextAppearance_Holo_Widget_PopupMenu_Small" + type="int" + transient="false" + volatile="false" + value="16974097" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="TextAppearance_Holo_Widget_TabWidget" + type="int" + transient="false" + volatile="false" + value="16974088" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="TextAppearance_Holo_Widget_TextView" + type="int" + transient="false" + volatile="false" + value="16974089" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="TextAppearance_Holo_Widget_TextView_PopupMenu" + type="int" + transient="false" + volatile="false" + value="16974090" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="TextAppearance_Holo_Widget_TextView_SpinnerItem" + type="int" + transient="false" + volatile="false" + value="16974093" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="TextAppearance_Holo_WindowTitle" + type="int" + transient="false" + volatile="false" + value="16974102" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="TextAppearance_Inverse" type="int" transient="false" @@ -15670,6 +16033,28 @@ visibility="public" > </field> +<field name="Theme_Holo_Light_NoActionBar" + type="int" + transient="false" + volatile="false" + value="16974064" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="Theme_Holo_Light_NoActionBar_Fullscreen" + type="int" + transient="false" + volatile="false" + value="16974065" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="Theme_Holo_Light_Panel" type="int" transient="false" @@ -15978,6 +16363,39 @@ visibility="public" > </field> +<field name="Widget_ActionBar_TabBar" + type="int" + transient="false" + volatile="false" + value="16974068" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="Widget_ActionBar_TabText" + type="int" + transient="false" + volatile="false" + value="16974067" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="Widget_ActionBar_TabView" + type="int" + transient="false" + volatile="false" + value="16974066" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="Widget_ActionButton" type="int" transient="false" @@ -16231,6 +16649,39 @@ visibility="public" > </field> +<field name="Widget_Holo_ActionBar_TabBar" + type="int" + transient="false" + volatile="false" + value="16974071" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="Widget_Holo_ActionBar_TabText" + type="int" + transient="false" + volatile="false" + value="16974070" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="Widget_Holo_ActionBar_TabView" + type="int" + transient="false" + volatile="false" + value="16974069" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="Widget_Holo_ActionButton" type="int" transient="false" @@ -16506,6 +16957,39 @@ visibility="public" > </field> +<field name="Widget_Holo_Light_ActionBar_TabBar" + type="int" + transient="false" + volatile="false" + value="16974074" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="Widget_Holo_Light_ActionBar_TabText" + type="int" + transient="false" + volatile="false" + value="16974073" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="Widget_Holo_Light_ActionBar_TabView" + type="int" + transient="false" + volatile="false" + value="16974072" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="Widget_Holo_Light_ActionButton" type="int" transient="false" @@ -22707,7 +23191,7 @@ synchronized="false" static="false" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > <parameter name="id" type="int"> @@ -22981,7 +23465,7 @@ synchronized="false" static="false" final="false" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </method> @@ -23434,7 +23918,7 @@ synchronized="false" static="false" final="false" - deprecated="not deprecated" + deprecated="deprecated" visibility="protected" > <parameter name="id" type="int"> @@ -23798,7 +24282,7 @@ synchronized="false" static="false" final="false" - deprecated="not deprecated" + deprecated="deprecated" visibility="protected" > <parameter name="id" type="int"> @@ -23880,7 +24364,7 @@ synchronized="false" static="false" final="false" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </method> @@ -24102,7 +24586,7 @@ synchronized="false" static="false" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > <parameter name="id" type="int"> @@ -24452,7 +24936,7 @@ synchronized="false" static="false" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > <parameter name="id" type="int"> @@ -24465,7 +24949,7 @@ synchronized="false" static="false" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > <parameter name="id" type="int"> @@ -30529,6 +31013,21 @@ visibility="public" > </method> +<method name="onViewCreated" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="view" type="android.view.View"> +</parameter> +<parameter name="savedInstanceState" type="android.os.Bundle"> +</parameter> +</method> <method name="registerForContextMenu" return="void" abstract="false" @@ -30568,6 +31067,19 @@ <parameter name="hasMenu" type="boolean"> </parameter> </method> +<method name="setInitialSavedState" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="state" type="android.app.Fragment.SavedState"> +</parameter> +</method> <method name="setRetainInstance" return="void" abstract="false" @@ -30659,6 +31171,53 @@ </parameter> </constructor> </class> +<class name="Fragment.SavedState" + extends="java.lang.Object" + abstract="false" + static="true" + final="false" + deprecated="not deprecated" + visibility="public" +> +<implements name="android.os.Parcelable"> +</implements> +<method name="describeContents" + return="int" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> +<method name="writeToParcel" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="dest" type="android.os.Parcel"> +</parameter> +<parameter name="flags" type="int"> +</parameter> +</method> +<field name="CREATOR" + type="android.os.Parcelable.ClassLoaderCreator" + transient="false" + volatile="false" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +</class> <class name="FragmentBreadCrumbs" extends="android.view.ViewGroup" abstract="false" @@ -31092,6 +31651,19 @@ <parameter name="listener" type="android.app.FragmentManager.OnBackStackChangedListener"> </parameter> </method> +<method name="saveFragmentInstanceState" + return="android.app.Fragment.SavedState" + abstract="true" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="f" type="android.app.Fragment"> +</parameter> +</method> <field name="POP_BACK_STACK_INCLUSIVE" type="int" transient="false" @@ -31262,6 +31834,19 @@ <parameter name="name" type="java.lang.String"> </parameter> </method> +<method name="attach" + return="android.app.FragmentTransaction" + abstract="true" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="fragment" type="android.app.Fragment"> +</parameter> +</method> <method name="commit" return="int" abstract="true" @@ -31284,6 +31869,19 @@ visibility="public" > </method> +<method name="detach" + return="android.app.FragmentTransaction" + abstract="true" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="fragment" type="android.app.Fragment"> +</parameter> +</method> <method name="disallowAddToBackStack" return="android.app.FragmentTransaction" abstract="true" @@ -31442,6 +32040,25 @@ <parameter name="exit" type="int"> </parameter> </method> +<method name="setCustomAnimations" + return="android.app.FragmentTransaction" + abstract="true" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="enter" type="int"> +</parameter> +<parameter name="exit" type="int"> +</parameter> +<parameter name="popEnter" type="int"> +</parameter> +<parameter name="popExit" type="int"> +</parameter> +</method> <method name="setTransition" return="android.app.FragmentTransaction" abstract="true" @@ -32623,7 +33240,7 @@ synchronized="false" static="false" final="false" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > <parameter name="callback" type="android.app.KeyguardManager.OnKeyguardExitResult"> @@ -32647,7 +33264,7 @@ synchronized="false" static="false" final="false" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > <parameter name="tag" type="java.lang.String"> @@ -32659,7 +33276,7 @@ abstract="false" static="false" final="false" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > <method name="disableKeyguard" @@ -57840,6 +58457,28 @@ visibility="public" > </field> +<field name="CONFIG_SCREEN_SIZE" + type="int" + transient="false" + volatile="false" + value="1024" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="CONFIG_SMALLEST_SCREEN_SIZE" + type="int" + transient="false" + volatile="false" + value="2048" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="CONFIG_TOUCHSCREEN" type="int" transient="false" @@ -58588,6 +59227,16 @@ visibility="public" > </field> +<field name="compatibleWidthLimitDp" + type="int" + transient="false" + volatile="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="dataDir" type="java.lang.String" transient="false" @@ -58628,6 +59277,16 @@ visibility="public" > </field> +<field name="largestWidthLimitDp" + type="int" + transient="false" + volatile="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="manageSpaceActivityName" type="java.lang.String" transient="false" @@ -58678,6 +59337,16 @@ visibility="public" > </field> +<field name="requiresSmallestWidthDp" + type="int" + transient="false" + volatile="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="sharedLibraryFiles" type="java.lang.String[]" transient="false" @@ -61053,6 +61722,28 @@ visibility="public" > </field> +<field name="FEATURE_FAKETOUCH_MULTITOUCH_DISTINCT" + type="java.lang.String" + transient="false" + volatile="false" + value=""android.hardware.faketouch.multitouch.distinct"" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="FEATURE_FAKETOUCH_MULTITOUCH_JAZZHAND" + type="java.lang.String" + transient="false" + volatile="false" + value=""android.hardware.faketouch.multitouch.jazzhand"" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="FEATURE_LIVE_WALLPAPER" type="java.lang.String" transient="false" @@ -63902,6 +64593,39 @@ visibility="public" > </field> +<field name="SCREEN_HEIGHT_DP_UNDEFINED" + type="int" + transient="false" + volatile="false" + value="0" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="SCREEN_WIDTH_DP_UNDEFINED" + type="int" + transient="false" + volatile="false" + value="0" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="SMALLEST_SCREEN_WIDTH_DP_UNDEFINED" + type="int" + transient="false" + volatile="false" + value="0" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="TOUCHSCREEN_FINGER" type="int" transient="false" @@ -64034,6 +64758,17 @@ visibility="public" > </field> +<field name="UI_MODE_TYPE_TELEVISION" + type="int" + transient="false" + volatile="false" + value="4" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="UI_MODE_TYPE_UNDEFINED" type="int" transient="false" @@ -64145,6 +64880,16 @@ visibility="public" > </field> +<field name="screenHeightDp" + type="int" + transient="false" + volatile="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="screenLayout" type="int" transient="false" @@ -64155,6 +64900,26 @@ visibility="public" > </field> +<field name="screenWidthDp" + type="int" + transient="false" + volatile="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="smallestScreenWidthDp" + type="int" + transient="false" + volatile="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="touchscreen" type="int" transient="false" @@ -84584,6 +85349,8 @@ deprecated="not deprecated" visibility="public" > +<implements name="android.os.Parcelable"> +</implements> <constructor name="Point" type="android.graphics.Point" static="false" @@ -84614,6 +85381,17 @@ <parameter name="src" type="android.graphics.Point"> </parameter> </constructor> +<method name="describeContents" + return="int" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> <method name="equals" return="boolean" abstract="false" @@ -84655,6 +85433,19 @@ <parameter name="dy" type="int"> </parameter> </method> +<method name="readFromParcel" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="in" type="android.os.Parcel"> +</parameter> +</method> <method name="set" return="void" abstract="false" @@ -84670,6 +85461,31 @@ <parameter name="y" type="int"> </parameter> </method> +<method name="writeToParcel" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="out" type="android.os.Parcel"> +</parameter> +<parameter name="flags" type="int"> +</parameter> +</method> +<field name="CREATOR" + type="android.os.Parcelable.Creator" + transient="false" + volatile="false" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="x" type="int" transient="false" @@ -84699,6 +85515,8 @@ deprecated="not deprecated" visibility="public" > +<implements name="android.os.Parcelable"> +</implements> <constructor name="PointF" type="android.graphics.PointF" static="false" @@ -84729,6 +85547,17 @@ <parameter name="p" type="android.graphics.Point"> </parameter> </constructor> +<method name="describeContents" + return="int" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> <method name="equals" return="boolean" abstract="false" @@ -84796,6 +85625,19 @@ <parameter name="dy" type="float"> </parameter> </method> +<method name="readFromParcel" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="in" type="android.os.Parcel"> +</parameter> +</method> <method name="set" return="void" abstract="false" @@ -84824,6 +85666,31 @@ <parameter name="p" type="android.graphics.PointF"> </parameter> </method> +<method name="writeToParcel" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="out" type="android.os.Parcel"> +</parameter> +<parameter name="flags" type="int"> +</parameter> +</method> +<field name="CREATOR" + type="android.os.Parcelable.Creator" + transient="false" + volatile="false" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="x" type="float" transient="false" @@ -95253,6 +96120,17 @@ visibility="public" > </method> +<method name="getRawDescriptors" + return="byte[]" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> <method name="getSerial" return="java.lang.String" abstract="false" @@ -114060,6 +114938,28 @@ visibility="public" > </field> +<field name="TYPE_BLUETOOTH" + type="int" + transient="false" + volatile="false" + value="7" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="TYPE_ETHERNET" + type="int" + transient="false" + volatile="false" + value="9" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="TYPE_MOBILE" type="int" transient="false" @@ -143402,6 +144302,21 @@ <parameter name="args" type="java.lang.String[]"> </parameter> </method> +<method name="dumpAsync" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="fd" type="java.io.FileDescriptor"> +</parameter> +<parameter name="args" type="java.lang.String[]"> +</parameter> +</method> <method name="flushPendingCommands" return="void" abstract="false" @@ -144032,6 +144947,17 @@ visibility="public" > </field> +<field name="HONEYCOMB_MR2" + type="int" + transient="false" + volatile="false" + value="13" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> </class> <class name="Bundle" extends="java.lang.Object" @@ -147863,6 +148789,23 @@ <exception name="RemoteException" type="android.os.RemoteException"> </exception> </method> +<method name="dumpAsync" + return="void" + abstract="true" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="fd" type="java.io.FileDescriptor"> +</parameter> +<parameter name="args" type="java.lang.String[]"> +</parameter> +<exception name="RemoteException" type="android.os.RemoteException"> +</exception> +</method> <method name="getInterfaceDescriptor" return="java.lang.String" abstract="true" @@ -150169,6 +151112,19 @@ <parameter name="descriptor" type="android.os.ParcelFileDescriptor"> </parameter> </constructor> +<method name="adoptFd" + return="android.os.ParcelFileDescriptor" + abstract="false" + native="false" + synchronized="false" + static="true" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="fd" type="int"> +</parameter> +</method> <method name="close" return="void" abstract="false" @@ -150217,6 +151173,36 @@ visibility="public" > </method> +<method name="dup" + return="android.os.ParcelFileDescriptor" + abstract="false" + native="false" + synchronized="false" + static="true" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="orig" type="java.io.FileDescriptor"> +</parameter> +<exception name="IOException" type="java.io.IOException"> +</exception> +</method> +<method name="fromFd" + return="android.os.ParcelFileDescriptor" + abstract="false" + native="false" + synchronized="false" + static="true" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="fd" type="int"> +</parameter> +<exception name="IOException" type="java.io.IOException"> +</exception> +</method> <method name="fromSocket" return="android.os.ParcelFileDescriptor" abstract="false" @@ -150596,6 +151582,31 @@ > </field> </interface> +<interface name="Parcelable.ClassLoaderCreator" + abstract="true" + static="true" + final="false" + deprecated="not deprecated" + visibility="public" +> +<implements name="android.os.Parcelable.Creator"> +</implements> +<method name="createFromParcel" + return="T" + abstract="true" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="source" type="android.os.Parcel"> +</parameter> +<parameter name="loader" type="java.lang.ClassLoader"> +</parameter> +</method> +</interface> <interface name="Parcelable.Creator" abstract="true" static="true" @@ -150893,7 +151904,7 @@ value="10" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -184155,6 +185166,17 @@ visibility="public" > </field> +<field name="NETWORK_TYPE_HSPAP" + type="int" + transient="false" + volatile="false" + value="15" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="NETWORK_TYPE_HSUPA" type="int" transient="false" @@ -205789,6 +206811,17 @@ visibility="public" > </field> +<field name="DENSITY_TV" + type="int" + transient="false" + volatile="false" + value="213" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="DENSITY_XHIGH" type="int" transient="false" @@ -209950,11 +210983,11 @@ <method name="getHeight" return="int" abstract="false" - native="true" + native="false" synchronized="false" static="false" final="false" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </method> @@ -209993,6 +211026,19 @@ visibility="public" > </method> +<method name="getRectSize" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="outSize" type="android.graphics.Rect"> +</parameter> +</method> <method name="getRefreshRate" return="float" abstract="false" @@ -210015,14 +211061,27 @@ visibility="public" > </method> +<method name="getSize" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="outSize" type="android.graphics.Point"> +</parameter> +</method> <method name="getWidth" return="int" abstract="false" - native="true" + native="false" synchronized="false" static="false" final="false" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </method> @@ -212742,6 +213801,17 @@ visibility="public" > </method> +<method name="getModifiers" + return="int" + abstract="false" + native="false" + synchronized="false" + static="false" + final="true" + deprecated="not deprecated" + visibility="public" +> +</method> <method name="getNumber" return="char" abstract="false" @@ -220966,7 +222036,7 @@ deprecated="not deprecated" visibility="public" > -<parameter name="ev" type="android.view.MotionEvent"> +<parameter name="event" type="android.view.MotionEvent"> </parameter> </method> <method name="clear" diff --git a/api/14.txt b/api/14.txt index ea09dc9b8128..5c4732e0e87f 100644 --- a/api/14.txt +++ b/api/14.txt @@ -14255,20 +14255,10 @@ package android.os.storage { package android.preference { - public class CheckBoxPreference extends android.preference.Preference { + public class CheckBoxPreference extends android.preference.TwoStatePreference { ctor public CheckBoxPreference(android.content.Context, android.util.AttributeSet, int); ctor public CheckBoxPreference(android.content.Context, android.util.AttributeSet); ctor public CheckBoxPreference(android.content.Context); - method public boolean getDisableDependentsState(); - method public java.lang.CharSequence getSummaryOff(); - method public java.lang.CharSequence getSummaryOn(); - method public boolean isChecked(); - method public void setChecked(boolean); - method public void setDisableDependentsState(boolean); - method public void setSummaryOff(java.lang.CharSequence); - method public void setSummaryOff(int); - method public void setSummaryOn(java.lang.CharSequence); - method public void setSummaryOn(int); } public abstract class DialogPreference extends android.preference.Preference implements android.content.DialogInterface.OnClickListener android.content.DialogInterface.OnDismissListener android.preference.PreferenceManager.OnActivityDestroyListener { diff --git a/api/current.txt b/api/current.txt index 6046026b16f1..63771b9d8536 100644 --- a/api/current.txt +++ b/api/current.txt @@ -78,6 +78,7 @@ package android { field public static final java.lang.String READ_INPUT_STATE = "android.permission.READ_INPUT_STATE"; field public static final java.lang.String READ_LOGS = "android.permission.READ_LOGS"; field public static final java.lang.String READ_PHONE_STATE = "android.permission.READ_PHONE_STATE"; + field public static final java.lang.String READ_PROFILE = "android.permission.READ_PROFILE"; field public static final java.lang.String READ_SMS = "android.permission.READ_SMS"; field public static final java.lang.String READ_SYNC_SETTINGS = "android.permission.READ_SYNC_SETTINGS"; field public static final java.lang.String READ_SYNC_STATS = "android.permission.READ_SYNC_STATS"; @@ -121,6 +122,7 @@ package android { field public static final java.lang.String WRITE_EXTERNAL_STORAGE = "android.permission.WRITE_EXTERNAL_STORAGE"; field public static final java.lang.String WRITE_GSERVICES = "android.permission.WRITE_GSERVICES"; field public static final java.lang.String WRITE_HISTORY_BOOKMARKS = "com.android.browser.permission.WRITE_HISTORY_BOOKMARKS"; + field public static final java.lang.String WRITE_PROFILE = "android.permission.WRITE_PROFILE"; field public static final java.lang.String WRITE_SECURE_SETTINGS = "android.permission.WRITE_SECURE_SETTINGS"; field public static final java.lang.String WRITE_SETTINGS = "android.permission.WRITE_SETTINGS"; field public static final java.lang.String WRITE_SMS = "android.permission.WRITE_SMS"; @@ -181,9 +183,9 @@ package android { public static final class R.attr { ctor public R.attr(); field public static final int absListViewStyle = 16842858; // 0x101006a - field public static final int accessibilityEventTypes = 16843647; // 0x101037f - field public static final int accessibilityFeedbackType = 16843649; // 0x1010381 - field public static final int accessibilityFlags = 16843651; // 0x1010383 + field public static final int accessibilityEventTypes = 16843650; // 0x1010382 + field public static final int accessibilityFeedbackType = 16843652; // 0x1010384 + field public static final int accessibilityFlags = 16843654; // 0x1010386 field public static final int accountPreferences = 16843423; // 0x101029f field public static final int accountType = 16843407; // 0x101028f field public static final int action = 16842797; // 0x101002d @@ -203,7 +205,7 @@ package android { field public static final int actionModeCopyDrawable = 16843538; // 0x1010312 field public static final int actionModeCutDrawable = 16843537; // 0x1010311 field public static final int actionModePasteDrawable = 16843539; // 0x1010313 - field public static final int actionModeSelectAllDrawable = 16843645; // 0x101037d + field public static final int actionModeSelectAllDrawable = 16843648; // 0x1010380 field public static final int actionOverflowButtonStyle = 16843510; // 0x10102f6 field public static final int actionViewClass = 16843516; // 0x10102fc field public static final int activatedBackgroundIndicator = 16843517; // 0x10102fd @@ -275,7 +277,7 @@ package android { field public static final int cacheColorHint = 16843009; // 0x1010101 field public static final int calendarViewShown = 16843596; // 0x101034c field public static final int calendarViewStyle = 16843613; // 0x101035d - field public static final int canRetrieveWindowContent = 16843652; // 0x1010384 + field public static final int canRetrieveWindowContent = 16843655; // 0x1010387 field public static final int candidatesTextStyleSpans = 16843312; // 0x1010230 field public static final deprecated int capitalize = 16843113; // 0x1010169 field public static final int centerBright = 16842956; // 0x10100cc @@ -308,9 +310,9 @@ package android { field public static final int colorBackgroundCacheHint = 16843435; // 0x10102ab field public static final int colorForeground = 16842800; // 0x1010030 field public static final int colorForegroundInverse = 16843270; // 0x1010206 - field public static final int columnCount = 16843636; // 0x1010374 + field public static final int columnCount = 16843639; // 0x1010377 field public static final int columnDelay = 16843215; // 0x10101cf - field public static final int columnOrderPreserved = 16843637; // 0x1010375 + field public static final int columnOrderPreserved = 16843640; // 0x1010378 field public static final int columnWidth = 16843031; // 0x1010117 field public static final int compatibleWidthLimitDp = 16843621; // 0x1010365 field public static final int completionHint = 16843122; // 0x1010172 @@ -423,6 +425,7 @@ package android { field public static final int fastScrollTextColor = 16843609; // 0x1010359 field public static final int fastScrollThumbDrawable = 16843574; // 0x1010336 field public static final int fastScrollTrackDrawable = 16843577; // 0x1010339 + field public static final int feedbackCount = 16843665; // 0x1010391 field public static final int fillAfter = 16843197; // 0x10101bd field public static final int fillBefore = 16843196; // 0x10101bc field public static final int fillEnabled = 16843343; // 0x101024f @@ -455,7 +458,7 @@ package android { field public static final int fromXScale = 16843202; // 0x10101c2 field public static final int fromYDelta = 16843208; // 0x10101c8 field public static final int fromYScale = 16843204; // 0x10101c4 - field public static final int fullBackupAgent = 16843632; // 0x1010370 + field public static final int fullBackupAgent = 16843635; // 0x1010373 field public static final int fullBright = 16842954; // 0x10100ca field public static final int fullDark = 16842950; // 0x10100c6 field public static final int functionalTest = 16842787; // 0x1010023 @@ -476,6 +479,7 @@ package android { field public static final int hand_hour = 16843011; // 0x1010103 field public static final int hand_minute = 16843012; // 0x1010104 field public static final int handle = 16843354; // 0x101025a + field public static final int handleDrawable = 16843657; // 0x1010389 field public static final int handleProfiling = 16842786; // 0x1010022 field public static final int hapticFeedbackEnabled = 16843358; // 0x101025e field public static final int hardwareAccelerated = 16843475; // 0x10102d3 @@ -484,10 +488,12 @@ package android { field public static final int headerDividersEnabled = 16843310; // 0x101022e field public static final int height = 16843093; // 0x1010155 field public static final int hint = 16843088; // 0x1010150 + field public static final int hitRadius = 16843662; // 0x101038e field public static final int homeAsUpIndicator = 16843531; // 0x101030b field public static final int homeLayout = 16843549; // 0x101031d field public static final int horizontalDivider = 16843053; // 0x101012d field public static final int horizontalGap = 16843327; // 0x101023f + field public static final int horizontalOffset = 16843667; // 0x1010393 field public static final int horizontalScrollViewStyle = 16843603; // 0x1010353 field public static final int horizontalSpacing = 16843028; // 0x1010114 field public static final int host = 16842792; // 0x1010028 @@ -533,7 +539,7 @@ package android { field public static final int installLocation = 16843447; // 0x10102b7 field public static final int interpolator = 16843073; // 0x1010141 field public static final int isAlwaysSyncable = 16843571; // 0x1010333 - field public static final int isAuxiliary = 16843646; // 0x101037e + field public static final int isAuxiliary = 16843649; // 0x1010381 field public static final int isDefault = 16843297; // 0x1010221 field public static final int isIndicator = 16843079; // 0x1010147 field public static final int isModifier = 16843334; // 0x1010246 @@ -570,7 +576,7 @@ package android { field public static final int layerType = 16843604; // 0x1010354 field public static final int layout = 16842994; // 0x10100f2 field public static final int layoutAnimation = 16842988; // 0x10100ec - field public static final int layoutDirection = 16843631; // 0x101036f + field public static final int layoutDirection = 16843634; // 0x1010372 field public static final int layout_above = 16843140; // 0x1010184 field public static final int layout_alignBaseline = 16843142; // 0x1010186 field public static final int layout_alignBottom = 16843146; // 0x101018a @@ -587,8 +593,8 @@ package android { field public static final int layout_centerInParent = 16843151; // 0x101018f field public static final int layout_centerVertical = 16843153; // 0x1010191 field public static final int layout_column = 16843084; // 0x101014c - field public static final int layout_columnSpan = 16843643; // 0x101037b - field public static final int layout_columnWeight = 16843644; // 0x101037c + field public static final int layout_columnSpan = 16843646; // 0x101037e + field public static final int layout_columnWeight = 16843647; // 0x101037f field public static final int layout_gravity = 16842931; // 0x10100b3 field public static final int layout_height = 16842997; // 0x10100f5 field public static final int layout_margin = 16842998; // 0x10100f6 @@ -596,9 +602,9 @@ package android { field public static final int layout_marginLeft = 16842999; // 0x10100f7 field public static final int layout_marginRight = 16843001; // 0x10100f9 field public static final int layout_marginTop = 16843000; // 0x10100f8 - field public static final int layout_row = 16843640; // 0x1010378 - field public static final int layout_rowSpan = 16843641; // 0x1010379 - field public static final int layout_rowWeight = 16843642; // 0x101037a + field public static final int layout_row = 16843643; // 0x101037b + field public static final int layout_rowSpan = 16843644; // 0x101037c + field public static final int layout_rowWeight = 16843645; // 0x101037d field public static final int layout_scale = 16843155; // 0x1010193 field public static final int layout_span = 16843085; // 0x101014d field public static final int layout_toLeftOf = 16843138; // 0x1010182 @@ -608,6 +614,7 @@ package android { field public static final int layout_x = 16843135; // 0x101017f field public static final int layout_y = 16843136; // 0x1010180 field public static final int left = 16843181; // 0x10101ad + field public static final int leftChevronDrawable = 16843658; // 0x101038a field public static final int lineSpacingExtra = 16843287; // 0x1010217 field public static final int lineSpacingMultiplier = 16843288; // 0x1010218 field public static final int lines = 16843092; // 0x1010154 @@ -628,7 +635,7 @@ package android { field public static final int loopViews = 16843527; // 0x1010307 field public static final int manageSpaceActivity = 16842756; // 0x1010004 field public static final int mapViewStyle = 16842890; // 0x101008a - field public static final int marginsIncludedInAlignment = 16843639; // 0x1010377 + field public static final int marginsIncludedInAlignment = 16843642; // 0x101037a field public static final int marqueeRepeatLimit = 16843293; // 0x101021d field public static final int max = 16843062; // 0x1010136 field public static final int maxDate = 16843584; // 0x1010340 @@ -665,7 +672,7 @@ package android { field public static final int nextFocusUp = 16842979; // 0x10100e3 field public static final int noHistory = 16843309; // 0x101022d field public static final int normalScreens = 16843397; // 0x1010285 - field public static final int notificationTimeout = 16843650; // 0x1010382 + field public static final int notificationTimeout = 16843653; // 0x1010385 field public static final int numColumns = 16843032; // 0x1010118 field public static final int numStars = 16843076; // 0x1010144 field public static final deprecated int numeric = 16843109; // 0x1010165 @@ -679,10 +686,11 @@ package android { field public static final int orderingFromXml = 16843239; // 0x10101e7 field public static final int orientation = 16842948; // 0x10100c4 field public static final int outAnimation = 16843128; // 0x1010178 + field public static final int outerRadius = 16843661; // 0x101038d field public static final int overScrollFooter = 16843459; // 0x10102c3 field public static final int overScrollHeader = 16843458; // 0x10102c2 field public static final int overScrollMode = 16843457; // 0x10102c1 - field public static final int packageNames = 16843648; // 0x1010380 + field public static final int packageNames = 16843651; // 0x1010383 field public static final int padding = 16842965; // 0x10100d5 field public static final int paddingBottom = 16842969; // 0x10100d9 field public static final int paddingLeft = 16842966; // 0x10100d6 @@ -767,16 +775,17 @@ package android { field public static final int restoreAnyVersion = 16843450; // 0x10102ba field public static final deprecated int restoreNeedsApplication = 16843421; // 0x101029d field public static final int right = 16843183; // 0x10101af + field public static final int rightChevronDrawable = 16843659; // 0x101038b field public static final int ringtonePreferenceStyle = 16842899; // 0x1010093 field public static final int ringtoneType = 16843257; // 0x10101f9 field public static final int rotation = 16843558; // 0x1010326 field public static final int rotationX = 16843559; // 0x1010327 field public static final int rotationY = 16843560; // 0x1010328 - field public static final int rowCount = 16843634; // 0x1010372 + field public static final int rowCount = 16843637; // 0x1010375 field public static final int rowDelay = 16843216; // 0x10101d0 field public static final int rowEdgeFlags = 16843329; // 0x1010241 field public static final int rowHeight = 16843058; // 0x1010132 - field public static final int rowOrderPreserved = 16843635; // 0x1010373 + field public static final int rowOrderPreserved = 16843638; // 0x1010376 field public static final int saveEnabled = 16842983; // 0x10100e7 field public static final int scaleGravity = 16843262; // 0x10101fe field public static final int scaleHeight = 16843261; // 0x10101fd @@ -842,6 +851,7 @@ package android { field public static final int smallIcon = 16843422; // 0x101029e field public static final int smallScreens = 16843396; // 0x1010284 field public static final int smoothScrollbar = 16843313; // 0x1010231 + field public static final int snapMargin = 16843664; // 0x1010390 field public static final int soundEffectsEnabled = 16843285; // 0x1010215 field public static final int spacing = 16843027; // 0x1010113 field public static final int spinnerDropDownItemStyle = 16842887; // 0x1010087 @@ -889,12 +899,15 @@ package android { field public static final int subtitleTextStyle = 16843513; // 0x10102f9 field public static final int suggestActionMsg = 16843228; // 0x10101dc field public static final int suggestActionMsgColumn = 16843229; // 0x10101dd - field public static final int suggestionsEnabled = 16843633; // 0x1010371 + field public static final int suggestionsEnabled = 16843636; // 0x1010374 field public static final int summary = 16843241; // 0x10101e9 field public static final int summaryColumn = 16843426; // 0x10102a2 field public static final int summaryOff = 16843248; // 0x10101f0 field public static final int summaryOn = 16843247; // 0x10101ef field public static final int supportsUploading = 16843419; // 0x101029b + field public static final int switchPreferenceStyle = 16843629; // 0x101036d + field public static final int switchTextOff = 16843628; // 0x101036c + field public static final int switchTextOn = 16843627; // 0x101036b field public static final int syncable = 16842777; // 0x1010019 field public static final int tabStripEnabled = 16843453; // 0x10102bd field public static final int tabStripLeft = 16843451; // 0x10102bb @@ -903,6 +916,7 @@ package android { field public static final int tag = 16842961; // 0x10100d1 field public static final int targetActivity = 16843266; // 0x1010202 field public static final int targetClass = 16842799; // 0x101002f + field public static final int targetDrawables = 16843656; // 0x1010388 field public static final int targetPackage = 16842785; // 0x1010021 field public static final int targetSdkVersion = 16843376; // 0x1010270 field public static final int taskAffinity = 16842770; // 0x1010012 @@ -957,9 +971,9 @@ package android { field public static final int textEditPasteWindowLayout = 16843540; // 0x1010314 field public static final int textEditSideNoPasteWindowLayout = 16843615; // 0x101035f field public static final int textEditSidePasteWindowLayout = 16843614; // 0x101035e - field public static final int textEditSuggestionItemLayout = 16843630; // 0x101036e - field public static final int textEditSuggestionsBottomWindowLayout = 16843628; // 0x101036c - field public static final int textEditSuggestionsTopWindowLayout = 16843629; // 0x101036d + field public static final int textEditSuggestionItemLayout = 16843633; // 0x1010371 + field public static final int textEditSuggestionsBottomWindowLayout = 16843631; // 0x101036f + field public static final int textEditSuggestionsTopWindowLayout = 16843632; // 0x1010370 field public static final int textFilterEnabled = 16843007; // 0x10100ff field public static final int textIsSelectable = 16843542; // 0x1010316 field public static final int textOff = 16843045; // 0x1010125 @@ -971,7 +985,7 @@ package android { field public static final int textSelectHandleWindowStyle = 16843464; // 0x10102c8 field public static final int textSize = 16842901; // 0x1010095 field public static final int textStyle = 16842903; // 0x1010097 - field public static final int textSuggestionsWindowStyle = 16843627; // 0x101036b + field public static final int textSuggestionsWindowStyle = 16843630; // 0x101036e field public static final int textViewStyle = 16842884; // 0x1010084 field public static final int theme = 16842752; // 0x1010000 field public static final int thickness = 16843360; // 0x1010260 @@ -1007,7 +1021,7 @@ package android { field public static final int unfocusedMonthDateColor = 16843588; // 0x1010344 field public static final int unselectedAlpha = 16843278; // 0x101020e field public static final int updatePeriodMillis = 16843344; // 0x1010250 - field public static final int useDefaultMargins = 16843638; // 0x1010376 + field public static final int useDefaultMargins = 16843641; // 0x1010379 field public static final int useIntrinsicSizeAsMinimum = 16843536; // 0x1010310 field public static final int useLevel = 16843167; // 0x101019f field public static final int userVisible = 16843409; // 0x1010291 @@ -1021,8 +1035,10 @@ package android { field public static final int verticalCorrection = 16843322; // 0x101023a field public static final int verticalDivider = 16843054; // 0x101012e field public static final int verticalGap = 16843328; // 0x1010240 + field public static final int verticalOffset = 16843666; // 0x1010392 field public static final int verticalScrollbarPosition = 16843572; // 0x1010334 field public static final int verticalSpacing = 16843029; // 0x1010115 + field public static final int vibrationDuration = 16843663; // 0x101038f field public static final int visibility = 16842972; // 0x10100dc field public static final int visible = 16843156; // 0x1010194 field public static final int vmSafeMode = 16843448; // 0x10102b8 @@ -1039,6 +1055,7 @@ package android { field public static final int wallpaperIntraOpenExitAnimation = 16843416; // 0x1010298 field public static final int wallpaperOpenEnterAnimation = 16843411; // 0x1010293 field public static final int wallpaperOpenExitAnimation = 16843412; // 0x1010294 + field public static final int waveDrawable = 16843660; // 0x101038c field public static final int webTextViewStyle = 16843449; // 0x10102b9 field public static final int webViewStyle = 16842885; // 0x1010085 field public static final int weekDayTextAppearance = 16843592; // 0x1010348 @@ -1469,6 +1486,35 @@ package android { field public static final int MediaButton_Rew = 16973884; // 0x103003c field public static final int TextAppearance = 16973886; // 0x103003e field public static final int TextAppearance_DialogWindowTitle = 16973889; // 0x1030041 + field public static final int TextAppearance_Holo = 16974075; // 0x10300fb + field public static final int TextAppearance_Holo_DialogWindowTitle = 16974103; // 0x1030117 + field public static final int TextAppearance_Holo_Inverse = 16974076; // 0x10300fc + field public static final int TextAppearance_Holo_Large = 16974077; // 0x10300fd + field public static final int TextAppearance_Holo_Large_Inverse = 16974078; // 0x10300fe + field public static final int TextAppearance_Holo_Medium = 16974079; // 0x10300ff + field public static final int TextAppearance_Holo_Medium_Inverse = 16974080; // 0x1030100 + field public static final int TextAppearance_Holo_SearchResult_Subtitle = 16974084; // 0x1030104 + field public static final int TextAppearance_Holo_SearchResult_Title = 16974083; // 0x1030103 + field public static final int TextAppearance_Holo_Small = 16974081; // 0x1030101 + field public static final int TextAppearance_Holo_Small_Inverse = 16974082; // 0x1030102 + field public static final int TextAppearance_Holo_Widget = 16974085; // 0x1030105 + field public static final int TextAppearance_Holo_Widget_ActionBar_Subtitle = 16974099; // 0x1030113 + field public static final int TextAppearance_Holo_Widget_ActionBar_Title = 16974098; // 0x1030112 + field public static final int TextAppearance_Holo_Widget_ActionMode_Subtitle = 16974101; // 0x1030115 + field public static final int TextAppearance_Holo_Widget_ActionMode_Title = 16974100; // 0x1030114 + field public static final int TextAppearance_Holo_Widget_Button = 16974086; // 0x1030106 + field public static final int TextAppearance_Holo_Widget_DropDownHint = 16974091; // 0x103010b + field public static final int TextAppearance_Holo_Widget_DropDownItem = 16974092; // 0x103010c + field public static final int TextAppearance_Holo_Widget_EditText = 16974094; // 0x103010e + field public static final int TextAppearance_Holo_Widget_IconMenu_Item = 16974087; // 0x1030107 + field public static final int TextAppearance_Holo_Widget_PopupMenu = 16974095; // 0x103010f + field public static final int TextAppearance_Holo_Widget_PopupMenu_Large = 16974096; // 0x1030110 + field public static final int TextAppearance_Holo_Widget_PopupMenu_Small = 16974097; // 0x1030111 + field public static final int TextAppearance_Holo_Widget_TabWidget = 16974088; // 0x1030108 + field public static final int TextAppearance_Holo_Widget_TextView = 16974089; // 0x1030109 + field public static final int TextAppearance_Holo_Widget_TextView_PopupMenu = 16974090; // 0x103010a + field public static final int TextAppearance_Holo_Widget_TextView_SpinnerItem = 16974093; // 0x103010d + field public static final int TextAppearance_Holo_WindowTitle = 16974102; // 0x1030116 field public static final int TextAppearance_Inverse = 16973887; // 0x103003f field public static final int TextAppearance_Large = 16973890; // 0x1030042 field public static final int TextAppearance_Large_Inverse = 16973891; // 0x1030043 @@ -1518,11 +1564,11 @@ package android { field public static final int Theme_Holo_Light_NoActionBar = 16974064; // 0x10300f0 field public static final int Theme_Holo_Light_NoActionBar_Fullscreen = 16974065; // 0x10300f1 field public static final int Theme_Holo_Light_Panel = 16973948; // 0x103007c - field public static final int Theme_Holo_Light_SplitActionBarWhenNarrow = 16974068; // 0x10300f4 + field public static final int Theme_Holo_Light_SplitActionBarWhenNarrow = 16974106; // 0x103011a field public static final int Theme_Holo_NoActionBar = 16973932; // 0x103006c field public static final int Theme_Holo_NoActionBar_Fullscreen = 16973933; // 0x103006d field public static final int Theme_Holo_Panel = 16973947; // 0x103007b - field public static final int Theme_Holo_SplitActionBarWhenNarrow = 16974067; // 0x10300f3 + field public static final int Theme_Holo_SplitActionBarWhenNarrow = 16974105; // 0x1030119 field public static final int Theme_Holo_Wallpaper = 16973949; // 0x103007d field public static final int Theme_Holo_Wallpaper_NoTitleBar = 16973950; // 0x103007e field public static final int Theme_InputMethod = 16973908; // 0x1030054 @@ -1547,6 +1593,9 @@ package android { field public static final int Widget = 16973842; // 0x1030012 field public static final int Widget_AbsListView = 16973843; // 0x1030013 field public static final int Widget_ActionBar = 16973954; // 0x1030082 + field public static final int Widget_ActionBar_TabBar = 16974068; // 0x10300f4 + field public static final int Widget_ActionBar_TabText = 16974067; // 0x10300f3 + field public static final int Widget_ActionBar_TabView = 16974066; // 0x10300f2 field public static final int Widget_ActionButton = 16973956; // 0x1030084 field public static final int Widget_ActionButton_CloseMode = 16973960; // 0x1030088 field public static final int Widget_ActionButton_Overflow = 16973959; // 0x1030087 @@ -1570,6 +1619,9 @@ package android { field public static final int Widget_GridView = 16973874; // 0x1030032 field public static final int Widget_Holo = 16973962; // 0x103008a field public static final int Widget_Holo_ActionBar = 16974004; // 0x10300b4 + field public static final int Widget_Holo_ActionBar_TabBar = 16974071; // 0x10300f7 + field public static final int Widget_Holo_ActionBar_TabText = 16974070; // 0x10300f6 + field public static final int Widget_Holo_ActionBar_TabView = 16974069; // 0x10300f5 field public static final int Widget_Holo_ActionButton = 16973999; // 0x10300af field public static final int Widget_Holo_ActionButton_CloseMode = 16974003; // 0x10300b3 field public static final int Widget_Holo_ActionButton_Overflow = 16974000; // 0x10300b0 @@ -1595,6 +1647,9 @@ package android { field public static final int Widget_Holo_ImageButton = 16973974; // 0x1030096 field public static final int Widget_Holo_Light = 16974005; // 0x10300b5 field public static final int Widget_Holo_Light_ActionBar = 16974049; // 0x10300e1 + field public static final int Widget_Holo_Light_ActionBar_TabBar = 16974074; // 0x10300fa + field public static final int Widget_Holo_Light_ActionBar_TabText = 16974073; // 0x10300f9 + field public static final int Widget_Holo_Light_ActionBar_TabView = 16974072; // 0x10300f8 field public static final int Widget_Holo_Light_ActionButton = 16974045; // 0x10300dd field public static final int Widget_Holo_Light_ActionButton_CloseMode = 16974048; // 0x10300e0 field public static final int Widget_Holo_Light_ActionButton_Overflow = 16974046; // 0x10300de @@ -3563,6 +3618,7 @@ package android.app.admin { method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator CREATOR; field public static final int USES_ENCRYPTED_STORAGE = 7; // 0x7 + field public static final int USES_POLICY_DISABLE_CAMERA = 8; // 0x8 field public static final int USES_POLICY_EXPIRE_PASSWORD = 6; // 0x6 field public static final int USES_POLICY_FORCE_LOCK = 3; // 0x3 field public static final int USES_POLICY_LIMIT_PASSWORD = 0; // 0x0 @@ -3596,6 +3652,7 @@ package android.app.admin { public class DevicePolicyManager { method public java.util.List<android.content.ComponentName> getActiveAdmins(); + method public boolean getCameraDisabled(android.content.ComponentName); method public int getCurrentFailedPasswordAttempts(); method public int getMaximumFailedPasswordsForWipe(android.content.ComponentName); method public long getMaximumTimeToLock(android.content.ComponentName); @@ -3619,6 +3676,7 @@ package android.app.admin { method public void lockNow(); method public void removeActiveAdmin(android.content.ComponentName); method public boolean resetPassword(java.lang.String, int); + method public void setCameraDisabled(android.content.ComponentName, boolean); method public void setMaximumFailedPasswordsForWipe(android.content.ComponentName, int); method public void setMaximumTimeToLock(android.content.ComponentName, long); method public void setPasswordExpirationTimeout(android.content.ComponentName, long); @@ -5752,6 +5810,8 @@ package android.content.pm { field public static final java.lang.String FEATURE_CAMERA_FLASH = "android.hardware.camera.flash"; field public static final java.lang.String FEATURE_CAMERA_FRONT = "android.hardware.camera.front"; field public static final java.lang.String FEATURE_FAKETOUCH = "android.hardware.faketouch"; + field public static final java.lang.String FEATURE_FAKETOUCH_MULTITOUCH_DISTINCT = "android.hardware.faketouch.multitouch.distinct"; + field public static final java.lang.String FEATURE_FAKETOUCH_MULTITOUCH_JAZZHAND = "android.hardware.faketouch.multitouch.jazzhand"; field public static final java.lang.String FEATURE_LIVE_WALLPAPER = "android.software.live_wallpaper"; field public static final java.lang.String FEATURE_LOCATION = "android.hardware.location"; field public static final java.lang.String FEATURE_LOCATION_GPS = "android.hardware.location.gps"; @@ -13572,7 +13632,7 @@ package android.os { field public static final int GINGERBREAD_MR1 = 10; // 0xa field public static final int HONEYCOMB = 11; // 0xb field public static final int HONEYCOMB_MR1 = 12; // 0xc - field public static final int HONEYCOMB_MR2 = 10000; // 0x2710 + field public static final int HONEYCOMB_MR2 = 13; // 0xd field public static final int ICE_CREAM_SANDWICH = 10000; // 0x2710 } @@ -14433,20 +14493,10 @@ package android.os.storage { package android.preference { - public class CheckBoxPreference extends android.preference.Preference { + public class CheckBoxPreference extends android.preference.TwoStatePreference { ctor public CheckBoxPreference(android.content.Context, android.util.AttributeSet, int); ctor public CheckBoxPreference(android.content.Context, android.util.AttributeSet); ctor public CheckBoxPreference(android.content.Context); - method public boolean getDisableDependentsState(); - method public java.lang.CharSequence getSummaryOff(); - method public java.lang.CharSequence getSummaryOn(); - method public boolean isChecked(); - method public void setChecked(boolean); - method public void setDisableDependentsState(boolean); - method public void setSummaryOff(java.lang.CharSequence); - method public void setSummaryOff(int); - method public void setSummaryOn(java.lang.CharSequence); - method public void setSummaryOn(int); } public abstract class DialogPreference extends android.preference.Preference implements android.content.DialogInterface.OnClickListener android.content.DialogInterface.OnDismissListener android.preference.PreferenceManager.OnActivityDestroyListener { @@ -14774,6 +14824,34 @@ package android.preference { method public void setShowSilent(boolean); } + public class SwitchPreference extends android.preference.TwoStatePreference { + ctor public SwitchPreference(android.content.Context, android.util.AttributeSet, int); + ctor public SwitchPreference(android.content.Context, android.util.AttributeSet); + ctor public SwitchPreference(android.content.Context); + method public java.lang.CharSequence getSwitchTextOff(); + method public java.lang.CharSequence getSwitchTextOn(); + method public void setSwitchTextOff(java.lang.CharSequence); + method public void setSwitchTextOff(int); + method public void setSwitchTextOn(java.lang.CharSequence); + method public void setSwitchTextOn(int); + } + + public abstract class TwoStatePreference extends android.preference.Preference { + ctor public TwoStatePreference(android.content.Context, android.util.AttributeSet, int); + ctor public TwoStatePreference(android.content.Context, android.util.AttributeSet); + ctor public TwoStatePreference(android.content.Context); + method public boolean getDisableDependentsState(); + method public java.lang.CharSequence getSummaryOff(); + method public java.lang.CharSequence getSummaryOn(); + method public boolean isChecked(); + method public void setChecked(boolean); + method public void setDisableDependentsState(boolean); + method public void setSummaryOff(java.lang.CharSequence); + method public void setSummaryOff(int); + method public void setSummaryOn(java.lang.CharSequence); + method public void setSummaryOn(int); + } + } package android.provider { @@ -15174,6 +15252,7 @@ package android.provider { field public static final android.net.Uri AUTHORITY_URI; field public static final java.lang.String CALLER_IS_SYNCADAPTER = "caller_is_syncadapter"; field public static final java.lang.String DIRECTORY_PARAM_KEY = "directory"; + field public static final java.lang.String INCLUDE_PROFILE = "include_profile"; field public static final java.lang.String LIMIT_PARAM_KEY = "limit"; } @@ -15473,6 +15552,7 @@ package android.provider { field public static final java.lang.String DISPLAY_NAME = "display_name"; field public static final java.lang.String HAS_PHONE_NUMBER = "has_phone_number"; field public static final java.lang.String IN_VISIBLE_GROUP = "in_visible_group"; + field public static final java.lang.String IS_USER_PROFILE = "is_user_profile"; field public static final java.lang.String LOOKUP_KEY = "lookup"; field public static final java.lang.String PHOTO_ID = "photo_id"; field public static final java.lang.String PHOTO_THUMBNAIL_URI = "photo_thumb_uri"; @@ -15656,6 +15736,12 @@ package android.provider { field public static final java.lang.String PROTOCOL = "protocol"; } + public static final class ContactsContract.Profile implements android.provider.BaseColumns android.provider.ContactsContract.ContactNameColumns android.provider.ContactsContract.ContactOptionsColumns android.provider.ContactsContract.ContactStatusColumns android.provider.ContactsContract.ContactsColumns { + field public static final android.net.Uri CONTENT_RAW_CONTACTS_URI; + field public static final android.net.Uri CONTENT_URI; + field public static final android.net.Uri CONTENT_VCARD_URI; + } + public static final class ContactsContract.QuickContact { ctor public ContactsContract.QuickContact(); method public static void showQuickContact(android.content.Context, android.view.View, android.net.Uri, int, java.lang.String[]); @@ -15691,6 +15777,7 @@ package android.provider { field public static final java.lang.String CONTACT_ID = "contact_id"; field public static final java.lang.String DELETED = "deleted"; field public static final java.lang.String RAW_CONTACT_IS_READ_ONLY = "raw_contact_is_read_only"; + field public static final java.lang.String RAW_CONTACT_IS_USER_PROFILE = "raw_contact_is_user_profile"; } public static final class ContactsContract.RawContactsEntity implements android.provider.BaseColumns android.provider.ContactsContract.DataColumns android.provider.ContactsContract.RawContactsColumns { @@ -17318,6 +17405,28 @@ package android.sax { } +package android.security { + + public final class KeyChain { + ctor public KeyChain(); + method public static void choosePrivateKeyAlias(android.app.Activity, android.security.KeyChainAliasCallback, java.lang.String[], java.security.Principal[], java.lang.String, int); + method public static java.security.cert.X509Certificate[] getCertificateChain(android.content.Context, java.lang.String) throws java.lang.InterruptedException, android.security.KeyChainException; + method public static java.security.PrivateKey getPrivateKey(android.content.Context, java.lang.String) throws java.lang.InterruptedException, android.security.KeyChainException; + } + + public abstract interface KeyChainAliasCallback { + method public abstract void alias(java.lang.String); + } + + public class KeyChainException extends java.lang.Exception { + ctor public KeyChainException(); + ctor public KeyChainException(java.lang.String); + ctor public KeyChainException(java.lang.String, java.lang.Throwable); + ctor public KeyChainException(java.lang.Throwable); + } + +} + package android.service.wallpaper { public abstract class WallpaperService extends android.app.Service { @@ -17455,21 +17564,23 @@ package android.speech { package android.speech.tts { - public abstract class SynthesisRequest { - ctor public SynthesisRequest(java.lang.String, android.os.Bundle); + public abstract interface SynthesisCallback { method public abstract int audioAvailable(byte[], int, int); method public abstract int completeAudioAvailable(int, int, int, byte[], int, int); method public abstract int done(); method public abstract void error(); + method public abstract int getMaxBufferSize(); + method public abstract int start(int, int, int); + } + + public final class SynthesisRequest { method public java.lang.String getCountry(); method public java.lang.String getLanguage(); - method public abstract int getMaxBufferSize(); method public android.os.Bundle getParams(); method public int getPitch(); method public int getSpeechRate(); method public java.lang.String getText(); method public java.lang.String getVariant(); - method public abstract int start(int, int, int); } public class TextToSpeech { @@ -17555,7 +17666,7 @@ package android.speech.tts { method protected abstract int onIsLanguageAvailable(java.lang.String, java.lang.String, java.lang.String); method protected abstract int onLoadLanguage(java.lang.String, java.lang.String, java.lang.String); method protected abstract void onStop(); - method protected abstract void onSynthesizeText(android.speech.tts.SynthesisRequest); + method protected abstract void onSynthesizeText(android.speech.tts.SynthesisRequest, android.speech.tts.SynthesisCallback); } } @@ -21450,7 +21561,8 @@ package android.view { } public static abstract interface TextureView.SurfaceTextureListener { - method public abstract void onSurfaceTextureAvailable(android.graphics.SurfaceTexture); + method public abstract void onSurfaceTextureAvailable(android.graphics.SurfaceTexture, int, int); + method public abstract void onSurfaceTextureDestroyed(android.graphics.SurfaceTexture); method public abstract void onSurfaceTextureSizeChanged(android.graphics.SurfaceTexture, int, int); } @@ -23269,6 +23381,7 @@ package android.view.inputmethod { method public boolean isWatchingCursor(android.view.View); method public void restartInput(android.view.View); method public void sendAppPrivateCommand(android.view.View, java.lang.String, android.os.Bundle); + method public boolean setAdditionalInputMethodSubtypes(android.os.IBinder, android.view.inputmethod.InputMethodSubtype[]); method public boolean setCurrentInputMethodSubtype(android.view.inputmethod.InputMethodSubtype); method public void setInputMethod(android.os.IBinder, java.lang.String); method public void setInputMethodAndSubtype(android.os.IBinder, java.lang.String, android.view.inputmethod.InputMethodSubtype); diff --git a/cmds/installd/commands.c b/cmds/installd/commands.c index 9aa70a458240..d45ac1925a24 100644 --- a/cmds/installd/commands.c +++ b/cmds/installd/commands.c @@ -237,7 +237,7 @@ int move_dex(const char *src, const char *dst) if (create_cache_path(src_dex, src)) return -1; if (create_cache_path(dst_dex, dst)) return -1; - LOGI("move %s -> %s\n", src_dex, dst_dex); + LOGV("move %s -> %s\n", src_dex, dst_dex); if (rename(src_dex, dst_dex) < 0) { LOGE("Couldn't move %s: %s\n", src_dex, strerror(errno)); return -1; @@ -253,7 +253,7 @@ int rm_dex(const char *path) if (validate_apk_path(path)) return -1; if (create_cache_path(dex_path, path)) return -1; - LOGI("unlink %s\n", dex_path); + LOGV("unlink %s\n", dex_path); if (unlink(dex_path) < 0) { LOGE("Couldn't unlink %s: %s\n", dex_path, strerror(errno)); return -1; @@ -452,7 +452,7 @@ static int wait_dexopt(pid_t pid, const char* apk_path) } if (WIFEXITED(status) && WEXITSTATUS(status) == 0) { - LOGD("DexInv: --- END '%s' (success) ---\n", apk_path); + LOGV("DexInv: --- END '%s' (success) ---\n", apk_path); return 0; } else { LOGW("DexInv: --- END '%s' --- status=0x%04x, process failed\n", @@ -519,7 +519,7 @@ int dexopt(const char *apk_path, uid_t uid, int is_public) goto fail; } - LOGD("DexInv: --- BEGIN '%s' ---\n", apk_path); + LOGV("DexInv: --- BEGIN '%s' ---\n", apk_path); pid_t pid; pid = fork(); @@ -587,7 +587,7 @@ void mkinnerdirs(char* path, int basepos, mode_t mode, int uid, int gid, if (path[basepos] == '/') { path[basepos] = 0; if (lstat(path, statbuf) < 0) { - LOGI("Making directory: %s\n", path); + LOGV("Making directory: %s\n", path); if (mkdir(path, mode) == 0) { chown(path, uid, gid); } else { @@ -619,7 +619,7 @@ int movefileordir(char* srcpath, char* dstpath, int dstbasepos, if ((statbuf->st_mode&S_IFDIR) == 0) { mkinnerdirs(dstpath, dstbasepos, S_IRWXU|S_IRWXG|S_IXOTH, dstuid, dstgid, statbuf); - LOGI("Renaming %s to %s (uid %d)\n", srcpath, dstpath, dstuid); + LOGV("Renaming %s to %s (uid %d)\n", srcpath, dstpath, dstuid); if (rename(srcpath, dstpath) >= 0) { if (chown(dstpath, dstuid, dstgid) < 0) { LOGE("cannot chown %s: %s\n", dstpath, strerror(errno)); diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 7e94cf29e092..1ec7a964e5cd 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -155,7 +155,9 @@ public final class ActivityThread { = new HashMap<IBinder, Service>(); AppBindData mBoundApplication; Configuration mConfiguration; + Configuration mCompatConfiguration; Configuration mResConfiguration; + CompatibilityInfo mResCompatibilityInfo; Application mInitialApplication; final ArrayList<Application> mAllApplications = new ArrayList<Application>(); @@ -181,8 +183,8 @@ public final class ActivityThread { = new HashMap<String, WeakReference<LoadedApk>>(); final HashMap<String, WeakReference<LoadedApk>> mResourcePackages = new HashMap<String, WeakReference<LoadedApk>>(); - Display mDisplay = null; - DisplayMetrics mDisplayMetrics = null; + final HashMap<CompatibilityInfo, DisplayMetrics> mDisplayMetrics + = new HashMap<CompatibilityInfo, DisplayMetrics>(); final HashMap<ResourcesKey, WeakReference<Resources> > mActiveResources = new HashMap<ResourcesKey, WeakReference<Resources> >(); final ArrayList<ActivityClientRecord> mRelaunchingActivities @@ -1276,20 +1278,45 @@ public final class ActivityThread { return sPackageManager; } - DisplayMetrics getDisplayMetricsLocked(boolean forceUpdate) { - if (mDisplayMetrics != null && !forceUpdate) { - return mDisplayMetrics; + DisplayMetrics getDisplayMetricsLocked(CompatibilityInfo ci, boolean forceUpdate) { + DisplayMetrics dm = mDisplayMetrics.get(ci); + if (dm != null && !forceUpdate) { + return dm; } - if (mDisplay == null) { - WindowManager wm = WindowManagerImpl.getDefault(); - mDisplay = wm.getDefaultDisplay(); + if (dm == null) { + dm = new DisplayMetrics(); + mDisplayMetrics.put(ci, dm); } - DisplayMetrics metrics = mDisplayMetrics = new DisplayMetrics(); - mDisplay.getMetrics(metrics); + Display d = WindowManagerImpl.getDefault(ci).getDefaultDisplay(); + d.getMetrics(dm); //Slog.i("foo", "New metrics: w=" + metrics.widthPixels + " h=" // + metrics.heightPixels + " den=" + metrics.density // + " xdpi=" + metrics.xdpi + " ydpi=" + metrics.ydpi); - return metrics; + return dm; + } + + static Configuration applyConfigCompat(Configuration config, CompatibilityInfo compat) { + if (config == null) { + return null; + } + if (compat != null && !compat.supportsScreen()) { + config = new Configuration(config); + compat.applyToConfiguration(config); + } + return config; + } + + private final Configuration mMainThreadConfig = new Configuration(); + Configuration applyConfigCompatMainThread(Configuration config, CompatibilityInfo compat) { + if (config == null) { + return null; + } + if (compat != null && !compat.supportsScreen()) { + mMainThreadConfig.setTo(config); + config = mMainThreadConfig; + compat.applyToConfiguration(config); + } + return config; } /** @@ -1331,7 +1358,7 @@ public final class ActivityThread { } //Slog.i(TAG, "Resource: key=" + key + ", display metrics=" + metrics); - DisplayMetrics metrics = getDisplayMetricsLocked(false); + DisplayMetrics metrics = getDisplayMetricsLocked(compInfo, false); r = new Resources(assets, metrics, getConfiguration(), compInfo); if (false) { Slog.i(TAG, "Created app resources " + resDir + " " + r + ": " @@ -1359,7 +1386,7 @@ public final class ActivityThread { * Creates the top level resources for the given package. */ Resources getTopLevelResources(String resDir, LoadedApk pkgInfo) { - return getTopLevelResources(resDir, pkgInfo.mCompatibilityInfo); + return getTopLevelResources(resDir, pkgInfo.mCompatibilityInfo.get()); } final Handler getHandler() { @@ -1526,7 +1553,8 @@ public final class ActivityThread { CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO); context.init(info, null, this); context.getResources().updateConfiguration( - getConfiguration(), getDisplayMetricsLocked(false)); + getConfiguration(), getDisplayMetricsLocked( + CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, false)); mSystemContext = context; //Slog.i(TAG, "Created system resources " + context.getResources() // + ": " + context.getResources().getConfiguration()); @@ -1739,7 +1767,7 @@ public final class ActivityThread { appContext.init(r.packageInfo, r.token, this); appContext.setOuterContext(activity); CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager()); - Configuration config = new Configuration(mConfiguration); + Configuration config = new Configuration(mCompatConfiguration); if (DEBUG_CONFIGURATION) Slog.v(TAG, "Launching activity " + r.activityInfo.name + " with config " + config); activity.attach(appContext, this, getInstrumentation(), r.token, @@ -2782,13 +2810,14 @@ public final class ActivityThread { private void handleUpdatePackageCompatibilityInfo(UpdateCompatibilityData data) { LoadedApk apk = peekPackageInfo(data.pkg, false); if (apk != null) { - apk.mCompatibilityInfo = data.info; + apk.mCompatibilityInfo.set(data.info); } apk = peekPackageInfo(data.pkg, true); if (apk != null) { - apk.mCompatibilityInfo = data.info; + apk.mCompatibilityInfo.set(data.info); } handleConfigurationChanged(mConfiguration, data.info); + WindowManagerImpl.getDefault().reportNewConfiguration(mConfiguration); } private final void deliverResults(ActivityClientRecord r, List<ResultInfo> results) { @@ -3211,20 +3240,22 @@ public final class ActivityThread { ActivityClientRecord ar = it.next(); Activity a = ar.activity; if (a != null) { + Configuration thisConfig = applyConfigCompatMainThread(newConfig, + ar.packageInfo.mCompatibilityInfo.getIfNeeded()); if (!ar.activity.mFinished && (allActivities || (a != null && !ar.paused))) { // If the activity is currently resumed, its configuration // needs to change right now. callbacks.add(a); - } else if (newConfig != null) { + } else if (thisConfig != null) { // Otherwise, we will tell it about the change // the next time it is resumed or shown. Note that // the activity manager may, before then, decide the // activity needs to be destroyed to handle its new // configuration. if (DEBUG_CONFIGURATION) Slog.v(TAG, "Setting activity " - + ar.activityInfo.name + " newConfig=" + newConfig); - ar.newConfig = newConfig; + + ar.activityInfo.name + " newConfig=" + thisConfig); + ar.newConfig = thisConfig; } } } @@ -3271,7 +3302,6 @@ public final class ActivityThread { // onConfigurationChanged int diff = activity.mCurrentConfig.diff(config); if (diff != 0) { - // If this activity doesn't handle any of the config changes // then don't bother calling onConfigurationChanged as we're // going to destroy it. @@ -3315,7 +3345,15 @@ public final class ActivityThread { return false; } int changes = mResConfiguration.updateFrom(config); - DisplayMetrics dm = getDisplayMetricsLocked(true); + DisplayMetrics dm = getDisplayMetricsLocked(compat, true); + + if (compat != null && (mResCompatibilityInfo == null || + !mResCompatibilityInfo.equals(compat))) { + mResCompatibilityInfo = compat; + changes |= ActivityInfo.CONFIG_SCREEN_LAYOUT + | ActivityInfo.CONFIG_SCREEN_SIZE + | ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE; + } // set it for java, this also affects newly created Resources if (config.locale != null) { @@ -3377,13 +3415,14 @@ public final class ActivityThread { return; } mConfiguration.updateFrom(config); - if (compat != null) { - // Can't do this here, because it causes us to report the - // comatible config back to the am as the current config - // of the activity, and much unhappiness results. - //compat.applyToConfiguration(mConfiguration); + if (mCompatConfiguration == null) { + mCompatConfiguration = new Configuration(); + } + mCompatConfiguration.setTo(mConfiguration); + if (mResCompatibilityInfo != null && !mResCompatibilityInfo.supportsScreen()) { + mResCompatibilityInfo.applyToConfiguration(mCompatConfiguration); + config = mCompatConfiguration; } - callbacks = collectComponentCallbacksLocked(false, config); } @@ -3404,7 +3443,7 @@ public final class ActivityThread { if (DEBUG_CONFIGURATION) Slog.v(TAG, "Handle activity config changed: " + r.activityInfo.name); - performConfigurationChanged(r.activity, mConfiguration); + performConfigurationChanged(r.activity, mCompatConfiguration); } final void handleProfilerControl(boolean start, ProfilerControlData pcd) { @@ -3498,6 +3537,7 @@ public final class ActivityThread { private final void handleBindApplication(AppBindData data) { mBoundApplication = data; mConfiguration = new Configuration(data.config); + mCompatConfiguration = new Configuration(data.config); // send up app name; do this *before* waiting for debugger Process.setArgV0(data.processName); diff --git a/core/java/android/app/Application.java b/core/java/android/app/Application.java index b9ac84838e65..10cc9f8de3a6 100644 --- a/core/java/android/app/Application.java +++ b/core/java/android/app/Application.java @@ -37,6 +37,8 @@ import android.content.res.Configuration; * when first constructing the singleton.</p> */ public class Application extends ContextWrapper implements ComponentCallbacks { + /** @hide */ + public LoadedApk mLoadedApk; public Application() { super(null); @@ -75,6 +77,6 @@ public class Application extends ContextWrapper implements ComponentCallbacks { */ /* package */ final void attach(Context context) { attachBaseContext(context); + mLoadedApk = ContextImpl.getImpl(context).mPackageInfo; } - } diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java index 73170bb49021..20dc792995bb 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -425,11 +425,19 @@ class ContextImpl extends Context { registerService(WINDOW_SERVICE, new ServiceFetcher() { public Object getService(ContextImpl ctx) { - CompatibilityInfo ci = ctx.mResources.getCompatibilityInfo(); - return WindowManagerImpl.getDefault(ci); + return WindowManagerImpl.getDefault(ctx.mPackageInfo.mCompatibilityInfo); }}); } + static ContextImpl getImpl(Context context) { + Context nextContext; + while ((context instanceof ContextWrapper) && + (nextContext=((ContextWrapper)context).getBaseContext()) != null) { + context = nextContext; + } + return (ContextImpl)context; + } + // The system service cache for the system services that are // cached per-ContextImpl. Package-scoped to avoid accessor // methods. diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java index 6287d3375df8..2549c84a9f95 100644 --- a/core/java/android/app/LoadedApk.java +++ b/core/java/android/app/LoadedApk.java @@ -38,6 +38,7 @@ import android.os.RemoteException; import android.os.StrictMode; import android.util.AndroidRuntimeException; import android.util.Slog; +import android.view.CompatibilityInfoHolder; import java.io.File; import java.io.IOException; @@ -64,7 +65,7 @@ final class ServiceConnectionLeaked extends AndroidRuntimeException { * Local state maintained about a currently loaded .apk. * @hide */ -final class LoadedApk { +public final class LoadedApk { private final ActivityThread mActivityThread; private final ApplicationInfo mApplicationInfo; @@ -78,10 +79,10 @@ final class LoadedApk { private final ClassLoader mBaseClassLoader; private final boolean mSecurityViolation; private final boolean mIncludeCode; + public final CompatibilityInfoHolder mCompatibilityInfo = new CompatibilityInfoHolder(); Resources mResources; private ClassLoader mClassLoader; private Application mApplication; - CompatibilityInfo mCompatibilityInfo; private final HashMap<Context, HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>> mReceivers = new HashMap<Context, HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>>(); @@ -121,7 +122,7 @@ final class LoadedApk { mBaseClassLoader = baseLoader; mSecurityViolation = securityViolation; mIncludeCode = includeCode; - mCompatibilityInfo = compatInfo; + mCompatibilityInfo.set(compatInfo); if (mAppDir == null) { if (ActivityThread.mSystemContext == null) { @@ -129,7 +130,7 @@ final class LoadedApk { ContextImpl.createSystemContext(mainThread); ActivityThread.mSystemContext.getResources().updateConfiguration( mainThread.getConfiguration(), - mainThread.getDisplayMetricsLocked(false), + mainThread.getDisplayMetricsLocked(compatInfo, false), compatInfo); //Slog.i(TAG, "Created system resources " // + mSystemContext.getResources() + ": " @@ -157,7 +158,7 @@ final class LoadedApk { mIncludeCode = true; mClassLoader = systemContext.getClassLoader(); mResources = systemContext.getResources(); - mCompatibilityInfo = compatInfo; + mCompatibilityInfo.set(compatInfo); } public String getPackageName() { diff --git a/core/java/android/app/admin/DeviceAdminInfo.java b/core/java/android/app/admin/DeviceAdminInfo.java index 1c7eb98c93bf..1c37414032a2 100644 --- a/core/java/android/app/admin/DeviceAdminInfo.java +++ b/core/java/android/app/admin/DeviceAdminInfo.java @@ -130,6 +130,14 @@ public final class DeviceAdminInfo implements Parcelable { */ public static final int USES_ENCRYPTED_STORAGE = 7; + /** + * A type of policy that this device admin can use: disables use of all device cameras. + * + * <p>To control this policy, the device admin must have a "disable-camera" + * tag in the "uses-policies" section of its meta-data. + */ + public static final int USES_POLICY_DISABLE_CAMERA = 8; + /** @hide */ public static class PolicyInfo { public final int ident; @@ -174,6 +182,9 @@ public final class DeviceAdminInfo implements Parcelable { sPoliciesDisplayOrder.add(new PolicyInfo(USES_ENCRYPTED_STORAGE, "encrypted-storage", com.android.internal.R.string.policylab_encryptedStorage, com.android.internal.R.string.policydesc_encryptedStorage)); + sPoliciesDisplayOrder.add(new PolicyInfo(USES_POLICY_DISABLE_CAMERA, "disable-camera", + com.android.internal.R.string.policylab_disableCamera, + com.android.internal.R.string.policydesc_disableCamera)); for (int i=0; i<sPoliciesDisplayOrder.size(); i++) { PolicyInfo pi = sPoliciesDisplayOrder.get(i); @@ -365,7 +376,8 @@ public final class DeviceAdminInfo implements Parcelable { * {@link #USES_POLICY_LIMIT_PASSWORD}, {@link #USES_POLICY_WATCH_LOGIN}, * {@link #USES_POLICY_RESET_PASSWORD}, {@link #USES_POLICY_FORCE_LOCK}, * {@link #USES_POLICY_WIPE_DATA}, - * {@link #USES_POLICY_EXPIRE_PASSWORD}, {@link #USES_ENCRYPTED_STORAGE}. + * {@link #USES_POLICY_EXPIRE_PASSWORD}, {@link #USES_ENCRYPTED_STORAGE}, + * {@link #USES_POLICY_DISABLE_CAMERA}. */ public boolean usesPolicy(int policyIdent) { return (mUsesPolicies & (1<<policyIdent)) != 0; diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index efe263336063..4147b0fd1c8f 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -1228,6 +1228,45 @@ public class DevicePolicyManager { } /** + * Called by an application that is administering the device to disable all cameras + * on the device. After setting this, no applications will be able to access any cameras + * on the device. + * + * <p>The calling device admin must have requested + * {@link DeviceAdminInfo#USES_POLICY_DISABLE_CAMERA} to be able to call + * this method; if it has not, a security exception will be thrown. + * + * @param admin Which {@link DeviceAdminReceiver} this request is associated with. + * @param disabled Whether or not the camera should be disabled. + */ + public void setCameraDisabled(ComponentName admin, boolean disabled) { + if (mService != null) { + try { + mService.setCameraDisabled(admin, disabled); + } catch (RemoteException e) { + Log.w(TAG, "Failed talking with device policy service", e); + } + } + } + + /** + * Determine whether or not the device's cameras have been disabled either by the current + * admin, if specified, or all admins. + * @param admin The name of the admin component to check, or null to check if any admins + * have disabled the camera + */ + public boolean getCameraDisabled(ComponentName admin) { + if (mService != null) { + try { + return mService.getCameraDisabled(admin); + } catch (RemoteException e) { + Log.w(TAG, "Failed talking with device policy service", e); + } + } + return false; + } + + /** * @hide */ public void setActiveAdmin(ComponentName policyReceiver, boolean refreshing) { diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl index e8caca153467..9419a62b7de8 100644 --- a/core/java/android/app/admin/IDevicePolicyManager.aidl +++ b/core/java/android/app/admin/IDevicePolicyManager.aidl @@ -79,6 +79,9 @@ interface IDevicePolicyManager { boolean getStorageEncryption(in ComponentName who); int getStorageEncryptionStatus(); + void setCameraDisabled(in ComponentName who, boolean disabled); + boolean getCameraDisabled(in ComponentName who); + void setActiveAdmin(in ComponentName policyReceiver, boolean refreshing); boolean isAdminActive(in ComponentName policyReceiver); List<ComponentName> getActiveAdmins(); diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index ff817c1bb1d4..33c2937aa983 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -893,6 +893,38 @@ public abstract class PackageManager { /** * Feature for {@link #getSystemAvailableFeatures} and + * {@link #hasSystemFeature}: The device does not have a touch screen, but + * does support touch emulation for basic events that supports distinct + * tracking of two or more fingers. This is an extension of + * {@link #FEATURE_FAKETOUCH} for input devices with this capability. Note + * that unlike a distinct multitouch screen as defined by + * {@link #FEATURE_TOUCHSCREEN_MULTITOUCH_DISTINCT}, these kinds of input + * devices will not actually provide full two-finger gestures since the + * input is being transformed to cursor movement on the screen. That is, + * single finger gestures will move a cursor; two-finger swipes will + * result in single-finger touch events; other two-finger gestures will + * result in the corresponding two-finger touch event. + */ + @SdkConstant(SdkConstantType.FEATURE) + public static final String FEATURE_FAKETOUCH_MULTITOUCH_DISTINCT = "android.hardware.faketouch.multitouch.distinct"; + + /** + * Feature for {@link #getSystemAvailableFeatures} and + * {@link #hasSystemFeature}: The device does not have a touch screen, but + * does support touch emulation for basic events that supports tracking + * a hand of fingers (5 or more fingers) fully independently. + * This is an extension of + * {@link #FEATURE_FAKETOUCH} for input devices with this capability. Note + * that unlike a multitouch screen as defined by + * {@link #FEATURE_TOUCHSCREEN_MULTITOUCH_JAZZHAND}, not all two finger + * gestures can be detected due to the limitations described for + * {@link #FEATURE_FAKETOUCH_MULTITOUCH_DISTINCT}. + */ + @SdkConstant(SdkConstantType.FEATURE) + public static final String FEATURE_FAKETOUCH_MULTITOUCH_JAZZHAND = "android.hardware.faketouch.multitouch.jazzhand"; + + /** + * Feature for {@link #getSystemAvailableFeatures} and * {@link #hasSystemFeature}: The device supports live wallpapers. */ @SdkConstant(SdkConstantType.FEATURE) diff --git a/core/java/android/content/res/CompatibilityInfo.java b/core/java/android/content/res/CompatibilityInfo.java index b686e54c03f7..acf2f2f17d0c 100644 --- a/core/java/android/content/res/CompatibilityInfo.java +++ b/core/java/android/content/res/CompatibilityInfo.java @@ -456,6 +456,9 @@ public class CompatibilityInfo implements Parcelable { inoutConfig.screenLayout = (inoutConfig.screenLayout&~Configuration.SCREENLAYOUT_SIZE_MASK) | Configuration.SCREENLAYOUT_SIZE_NORMAL; + inoutConfig.screenWidthDp = inoutConfig.compatScreenWidthDp; + inoutConfig.screenHeightDp = inoutConfig.compatScreenHeightDp; + inoutConfig.smallestScreenWidthDp = inoutConfig.compatSmallestScreenWidthDp; } } diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java index 6409aac441e7..906a5649880f 100644 --- a/core/java/android/content/res/Configuration.java +++ b/core/java/android/content/res/Configuration.java @@ -269,6 +269,33 @@ public final class Configuration implements Parcelable, Comparable<Configuration */ public int smallestScreenWidthDp; + /** @hide Hack to get this information from WM to app running in compat mode. */ + public int compatScreenWidthDp; + /** @hide Hack to get this information from WM to app running in compat mode. */ + public int compatScreenHeightDp; + /** @hide Hack to get this information from WM to app running in compat mode. */ + public int compatSmallestScreenWidthDp; + + /** + * @hide + */ + public static final int LAYOUT_DIRECTION_UNDEFINED = -1; + + /** + * @hide + */ + public static final int LAYOUT_DIRECTION_LTR = 0; + + /** + * @hide + */ + public static final int LAYOUT_DIRECTION_RTL = 1; + + /** + * @hide The layout direction associated to the current Locale + */ + public int layoutDirection; + /** * @hide Internal book-keeping. */ @@ -295,6 +322,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration mnc = o.mnc; if (o.locale != null) { locale = (Locale) o.locale.clone(); + layoutDirection = o.layoutDirection; } userSetLocale = o.userSetLocale; touchscreen = o.touchscreen; @@ -309,6 +337,9 @@ public final class Configuration implements Parcelable, Comparable<Configuration screenWidthDp = o.screenWidthDp; screenHeightDp = o.screenHeightDp; smallestScreenWidthDp = o.smallestScreenWidthDp; + compatScreenWidthDp = o.compatScreenWidthDp; + compatScreenHeightDp = o.compatScreenHeightDp; + compatSmallestScreenWidthDp = o.compatSmallestScreenWidthDp; seq = o.seq; } @@ -419,6 +450,11 @@ public final class Configuration implements Parcelable, Comparable<Configuration case NAVIGATIONHIDDEN_YES: sb.append("/h"); break; default: sb.append("/"); sb.append(navigationHidden); break; } + switch (layoutDirection) { + case LAYOUT_DIRECTION_UNDEFINED: sb.append(" ?layoutdir"); break; + case LAYOUT_DIRECTION_LTR: sb.append(" ltr"); break; + case LAYOUT_DIRECTION_RTL: sb.append(" rtl"); break; + } if (seq != 0) { sb.append(" s."); sb.append(seq); @@ -444,10 +480,11 @@ public final class Configuration implements Parcelable, Comparable<Configuration orientation = ORIENTATION_UNDEFINED; screenLayout = SCREENLAYOUT_SIZE_UNDEFINED; uiMode = UI_MODE_TYPE_UNDEFINED; - screenWidthDp = SCREEN_WIDTH_DP_UNDEFINED; - screenHeightDp = SCREEN_HEIGHT_DP_UNDEFINED; - smallestScreenWidthDp = SMALLEST_SCREEN_WIDTH_DP_UNDEFINED; + screenWidthDp = compatScreenWidthDp = SCREEN_WIDTH_DP_UNDEFINED; + screenHeightDp = compatScreenHeightDp = SCREEN_HEIGHT_DP_UNDEFINED; + smallestScreenWidthDp = compatSmallestScreenWidthDp = SMALLEST_SCREEN_WIDTH_DP_UNDEFINED; seq = 0; + layoutDirection = LAYOUT_DIRECTION_LTR; } /** {@hide} */ @@ -482,6 +519,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration changed |= ActivityInfo.CONFIG_LOCALE; locale = delta.locale != null ? (Locale) delta.locale.clone() : null; + layoutDirection = getLayoutDirectionFromLocale(locale); } if (delta.userSetLocale && (!userSetLocale || ((changed & ActivityInfo.CONFIG_LOCALE) != 0))) { @@ -550,11 +588,18 @@ public final class Configuration implements Parcelable, Comparable<Configuration changed |= ActivityInfo.CONFIG_SCREEN_SIZE; screenHeightDp = delta.screenHeightDp; } - if (delta.smallestScreenWidthDp != SMALLEST_SCREEN_WIDTH_DP_UNDEFINED - && smallestScreenWidthDp != delta.smallestScreenWidthDp) { - changed |= ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE; + if (delta.smallestScreenWidthDp != SMALLEST_SCREEN_WIDTH_DP_UNDEFINED) { smallestScreenWidthDp = delta.smallestScreenWidthDp; } + if (delta.compatScreenWidthDp != SCREEN_WIDTH_DP_UNDEFINED) { + compatScreenWidthDp = delta.compatScreenWidthDp; + } + if (delta.compatScreenHeightDp != SCREEN_HEIGHT_DP_UNDEFINED) { + compatScreenHeightDp = delta.compatScreenHeightDp; + } + if (delta.compatSmallestScreenWidthDp != SMALLEST_SCREEN_WIDTH_DP_UNDEFINED) { + compatSmallestScreenWidthDp = delta.compatSmallestScreenWidthDp; + } if (delta.seq != 0) { seq = delta.seq; @@ -564,6 +609,29 @@ public final class Configuration implements Parcelable, Comparable<Configuration } /** + * Return the layout direction for a given Locale + * @param locale the Locale for which we want the layout direction. Can be null. + * @return the layout direction. This may be one of {@link #LAYOUT_DIRECTION_UNDEFINED}, + * {@link #LAYOUT_DIRECTION_LTR} or {@link #LAYOUT_DIRECTION_RTL}. + * + * @hide + */ + public static int getLayoutDirectionFromLocale(Locale locale) { + if (locale == null || locale.equals(Locale.ROOT)) return LAYOUT_DIRECTION_UNDEFINED; + // Be careful: this code will need to be changed when vertical scripts will be supported + // OR if ICU4C is updated to have the "likelySubtags" file + switch(Character.getDirectionality(locale.getDisplayName(locale).charAt(0))) { + case Character.DIRECTIONALITY_LEFT_TO_RIGHT: + return LAYOUT_DIRECTION_LTR; + case Character.DIRECTIONALITY_RIGHT_TO_LEFT: + case Character.DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC: + return LAYOUT_DIRECTION_RTL; + default: + return LAYOUT_DIRECTION_UNDEFINED; + } + } + + /** * Return a bit mask of the differences between this Configuration * object and the given one. Does not change the values of either. Any * undefined fields in <var>delta</var> are ignored. @@ -739,6 +807,10 @@ public final class Configuration implements Parcelable, Comparable<Configuration dest.writeInt(screenWidthDp); dest.writeInt(screenHeightDp); dest.writeInt(smallestScreenWidthDp); + dest.writeInt(compatScreenWidthDp); + dest.writeInt(compatScreenHeightDp); + dest.writeInt(compatSmallestScreenWidthDp); + dest.writeInt(layoutDirection); dest.writeInt(seq); } @@ -763,6 +835,10 @@ public final class Configuration implements Parcelable, Comparable<Configuration screenWidthDp = source.readInt(); screenHeightDp = source.readInt(); smallestScreenWidthDp = source.readInt(); + compatScreenWidthDp = source.readInt(); + compatScreenHeightDp = source.readInt(); + compatSmallestScreenWidthDp = source.readInt(); + layoutDirection = source.readInt(); seq = source.readInt(); } diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java index 70bf5245a805..bd8b1a4af936 100755 --- a/core/java/android/content/res/Resources.java +++ b/core/java/android/content/res/Resources.java @@ -1414,18 +1414,6 @@ public class Resources { if (compat != null) { mCompatibilityInfo = compat; } - int configChanges = 0xfffffff; - if (config != null) { - mTmpConfig.setTo(config); - if (mCompatibilityInfo != null) { - mCompatibilityInfo.applyToConfiguration(mTmpConfig); - } - configChanges = mConfiguration.updateFrom(mTmpConfig); - configChanges = ActivityInfo.activityInfoConfigToNative(configChanges); - } - if (mConfiguration.locale == null) { - mConfiguration.locale = Locale.getDefault(); - } if (metrics != null) { mMetrics.setTo(metrics); // NOTE: We should re-arrange this code to create a Display @@ -1441,7 +1429,25 @@ public class Resources { mCompatibilityInfo.applyToDisplayMetrics(mMetrics); } } + if (mCompatibilityInfo != null) { + mCompatibilityInfo.applyToDisplayMetrics(mMetrics); + } mMetrics.scaledDensity = mMetrics.density * mConfiguration.fontScale; + int configChanges = 0xfffffff; + if (config != null) { + mTmpConfig.setTo(config); + if (mCompatibilityInfo != null) { + mCompatibilityInfo.applyToConfiguration(mTmpConfig); + } + if (mTmpConfig.locale == null) { + mTmpConfig.locale = Locale.getDefault(); + } + configChanges = mConfiguration.updateFrom(mTmpConfig); + configChanges = ActivityInfo.activityInfoConfigToNative(configChanges); + } + if (mConfiguration.locale == null) { + mConfiguration.locale = Locale.getDefault(); + } String locale = null; if (mConfiguration.locale != null) { @@ -1476,7 +1482,7 @@ public class Resources { mConfiguration.screenLayout, mConfiguration.uiMode, Build.VERSION.RESOURCES_SDK_INT); - if (false) { + if (DEBUG_CONFIG) { Slog.i(TAG, "**** Updating config of " + this + ": final config is " + mConfiguration + " final compat is " + mCompatibilityInfo); } @@ -1558,6 +1564,8 @@ public class Resources { * @return The resource's current display metrics. */ public DisplayMetrics getDisplayMetrics() { + if (DEBUG_CONFIG) Slog.v(TAG, "Returning DisplayMetrics: " + mMetrics.widthPixels + + "x" + mMetrics.heightPixels + " " + mMetrics.density); return mMetrics; } diff --git a/core/java/android/net/INetworkStatsService.aidl b/core/java/android/net/INetworkStatsService.aidl index d38d16c4e759..d05c9d3969b9 100644 --- a/core/java/android/net/INetworkStatsService.aidl +++ b/core/java/android/net/INetworkStatsService.aidl @@ -28,6 +28,6 @@ interface INetworkStatsService { NetworkStatsHistory getHistoryForUid(int uid, int networkTemplate); /** Return usage summary per UID for traffic that matches template. */ - NetworkStats getSummaryPerUid(long start, long end, int networkTemplate); + NetworkStats getSummaryForAllUid(long start, long end, int networkTemplate); } diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index ee415fa6bc65..6354e9a65e83 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -158,10 +158,37 @@ public class NetworkStats implements Parcelable { * between two snapshots in time. Assumes that statistics rows collect over * time, and that none of them have disappeared. * + * @throws IllegalArgumentException when given {@link NetworkStats} is + * non-monotonic. + */ + public NetworkStats subtract(NetworkStats value) { + return subtract(value, true, false); + } + + /** + * Subtract the given {@link NetworkStats}, effectively leaving the delta + * between two snapshots in time. Assumes that statistics rows collect over + * time, and that none of them have disappeared. + * <p> + * Instead of throwing when counters are non-monotonic, this variant clamps + * results to never be negative. + */ + public NetworkStats subtractClamped(NetworkStats value) { + return subtract(value, false, true); + } + + /** + * Subtract the given {@link NetworkStats}, effectively leaving the delta + * between two snapshots in time. Assumes that statistics rows collect over + * time, and that none of them have disappeared. + * * @param enforceMonotonic Validate that incoming value is strictly * monotonic compared to this object. + * @param clampNegative Instead of throwing like {@code enforceMonotonic}, + * clamp resulting counters at 0 to prevent negative values. */ - public NetworkStats subtract(NetworkStats value, boolean enforceMonotonic) { + private NetworkStats subtract( + NetworkStats value, boolean enforceMonotonic, boolean clampNegative) { final long deltaRealtime = this.elapsedRealtime - value.elapsedRealtime; if (enforceMonotonic && deltaRealtime < 0) { throw new IllegalArgumentException("found non-monotonic realtime"); @@ -181,11 +208,15 @@ public class NetworkStats implements Parcelable { result.addEntry(iface, uid, this.rx[i], this.tx[i]); } else { // existing row, subtract remote value - final long rx = this.rx[i] - value.rx[j]; - final long tx = this.tx[i] - value.tx[j]; + long rx = this.rx[i] - value.rx[j]; + long tx = this.tx[i] - value.tx[j]; if (enforceMonotonic && (rx < 0 || tx < 0)) { throw new IllegalArgumentException("found non-monotonic values"); } + if (clampNegative) { + rx = Math.max(0, rx); + tx = Math.max(0, tx); + } result.addEntry(iface, uid, rx, tx); } } diff --git a/core/java/android/net/NetworkStatsHistory.java b/core/java/android/net/NetworkStatsHistory.java index 5edbf5830dfe..a697e96989d1 100644 --- a/core/java/android/net/NetworkStatsHistory.java +++ b/core/java/android/net/NetworkStatsHistory.java @@ -218,7 +218,7 @@ public class NetworkStatsHistory implements Parcelable { * Return interpolated data usage across the requested range. Interpolates * across buckets, so values may be rounded slightly. */ - public void getTotalData(long start, long end, long[] outTotal) { + public long[] getTotalData(long start, long end, long[] outTotal) { long rx = 0; long tx = 0; @@ -238,8 +238,12 @@ public class NetworkStatsHistory implements Parcelable { } } + if (outTotal == null || outTotal.length != 2) { + outTotal = new long[2]; + } outTotal[0] = rx; outTotal[1] = tx; + return outTotal; } /** diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java index a0738c1da2d6..8a688d55f70c 100644 --- a/core/java/android/net/TrafficStats.java +++ b/core/java/android/net/TrafficStats.java @@ -177,8 +177,8 @@ public class TrafficStats { // subtract starting values and return delta final NetworkStats profilingStop = getNetworkStatsForUid(context); - final NetworkStats profilingDelta = profilingStop.subtract( - sActiveProfilingStart, false); + final NetworkStats profilingDelta = profilingStop.subtractClamped( + sActiveProfilingStart); sActiveProfilingStart = null; return profilingDelta; } diff --git a/core/java/android/nfc/INfcAdapter.aidl b/core/java/android/nfc/INfcAdapter.aidl index d11fea0a11c4..dcbe9dab117c 100644 --- a/core/java/android/nfc/INfcAdapter.aidl +++ b/core/java/android/nfc/INfcAdapter.aidl @@ -62,6 +62,4 @@ interface INfcAdapter int createLlcpSocket(int sap, int miu, int rw, int linearBufferLength); boolean disable(); boolean enable(); - String getProperties(String param); - int setProperties(String param, String value); } diff --git a/core/java/android/nfc/INfcAdapterExtras.aidl b/core/java/android/nfc/INfcAdapterExtras.aidl index 8677a503b270..3f8b8563b6af 100755 --- a/core/java/android/nfc/INfcAdapterExtras.aidl +++ b/core/java/android/nfc/INfcAdapterExtras.aidl @@ -29,6 +29,4 @@ interface INfcAdapterExtras { Bundle transceive(in byte[] data_in); int getCardEmulationRoute(); void setCardEmulationRoute(int route); - void registerTearDownApdus(String packageName, in ApduList apdu); - void unregisterTearDownApdus(String packageName); } diff --git a/core/java/android/nfc/INfcTag.aidl b/core/java/android/nfc/INfcTag.aidl index 31d004e73463..b66035ff881e 100644 --- a/core/java/android/nfc/INfcTag.aidl +++ b/core/java/android/nfc/INfcTag.aidl @@ -17,6 +17,7 @@ package android.nfc; import android.nfc.NdefMessage; +import android.nfc.Tag; import android.nfc.TransceiveResult; /** @@ -40,6 +41,7 @@ interface INfcTag int ndefMakeReadOnly(int nativeHandle); boolean ndefIsWritable(int nativeHandle); int formatNdef(int nativeHandle, in byte[] key); + Tag rediscover(int nativehandle); void setIsoDepTimeout(int timeout); void setFelicaTimeout(int timeout); diff --git a/core/java/android/nfc/Tag.java b/core/java/android/nfc/Tag.java index b676975b297f..54583d61f4f9 100644 --- a/core/java/android/nfc/Tag.java +++ b/core/java/android/nfc/Tag.java @@ -30,7 +30,9 @@ import android.nfc.tech.TagTechnology; import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; +import android.os.RemoteException; +import java.io.IOException; import java.util.Arrays; /** @@ -233,6 +235,50 @@ public final class Tag implements Parcelable { return mTechStringList; } + /** + * Rediscover the technologies available on this tag. + * <p> + * The technologies that are available on a tag may change due to + * operations being performed on a tag. For example, formatting a + * tag as NDEF adds the {@link Ndef} technology. The {@link rediscover} + * method reenumerates the available technologies on the tag + * and returns a new {@link Tag} object containing these technologies. + * <p> + * You may not be connected to any of this {@link Tag}'s technologies + * when calling this method. + * This method guarantees that you will be returned the same Tag + * if it is still in the field. + * <p>May cause RF activity and may block. Must not be called + * from the main application thread. A blocked call will be canceled with + * {@link IOException} by calling {@link #close} from another thread. + * <p>Does not remove power from the RF field, so a tag having a random + * ID should not change its ID. + * @return the rediscovered tag object. + * @throws IOException if the tag cannot be rediscovered + * @hide + */ + // TODO See if we need TagLostException + // TODO Unhide for ICS + // TODO Update documentation to make sure it matches with the final + // implementation. + public Tag rediscover() throws IOException { + if (getConnectedTechnology() != -1) { + throw new IllegalStateException("Close connection to the technology first!"); + } + + try { + Tag newTag = mTagService.rediscover(getServiceHandle()); + if (newTag != null) { + return newTag; + } else { + throw new IOException("Failed to rediscover tag"); + } + } catch (RemoteException e) { + throw new IOException("NFC service dead"); + } + } + + /** @hide */ public boolean hasTech(int techType) { for (int tech : mTechList) { diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java index d7bbab66176d..8ff5beb035cc 100644 --- a/core/java/android/os/Build.java +++ b/core/java/android/os/Build.java @@ -232,7 +232,7 @@ public class Build { public static final int HONEYCOMB_MR1 = 12; /** - * Current development version. + * June 2011: Android 3.2. * * <p>Update to Honeycomb MR1 to support 7 inch tablets, improve * screen compatibility mode, etc.</p> @@ -244,7 +244,7 @@ public class Build { * large as the current screen will provide the user with a UI to * switch them in to screen size compatibility mode.</p> */ - public static final int HONEYCOMB_MR2 = CUR_DEVELOPMENT; + public static final int HONEYCOMB_MR2 = 13; /** * Current version under development. diff --git a/core/java/android/preference/CheckBoxPreference.java b/core/java/android/preference/CheckBoxPreference.java index 2bf6c7b74408..437e55332a81 100644 --- a/core/java/android/preference/CheckBoxPreference.java +++ b/core/java/android/preference/CheckBoxPreference.java @@ -16,20 +16,11 @@ package android.preference; -import android.app.Service; import android.content.Context; -import android.content.SharedPreferences; import android.content.res.TypedArray; -import android.os.Parcel; -import android.os.Parcelable; import android.util.AttributeSet; import android.view.View; -import android.view.ViewGroup; -import android.view.accessibility.AccessibilityEvent; -import android.view.accessibility.AccessibilityManager; -import android.widget.CheckBox; import android.widget.Checkable; -import android.widget.TextView; /** * A {@link Preference} that provides checkbox widget @@ -41,31 +32,18 @@ import android.widget.TextView; * @attr ref android.R.styleable#CheckBoxPreference_summaryOn * @attr ref android.R.styleable#CheckBoxPreference_disableDependentsState */ -public class CheckBoxPreference extends Preference { +public class CheckBoxPreference extends TwoStatePreference { - private CharSequence mSummaryOn; - private CharSequence mSummaryOff; - - private boolean mChecked; - private boolean mSendAccessibilityEventViewClickedType; - - private AccessibilityManager mAccessibilityManager; - - private boolean mDisableDependentsState; - public CheckBoxPreference(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); TypedArray a = context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.CheckBoxPreference, defStyle, 0); - mSummaryOn = a.getString(com.android.internal.R.styleable.CheckBoxPreference_summaryOn); - mSummaryOff = a.getString(com.android.internal.R.styleable.CheckBoxPreference_summaryOff); - mDisableDependentsState = a.getBoolean( - com.android.internal.R.styleable.CheckBoxPreference_disableDependentsState, false); + setSummaryOn(a.getString(com.android.internal.R.styleable.CheckBoxPreference_summaryOn)); + setSummaryOff(a.getString(com.android.internal.R.styleable.CheckBoxPreference_summaryOff)); + setDisableDependentsState(a.getBoolean( + com.android.internal.R.styleable.CheckBoxPreference_disableDependentsState, false)); a.recycle(); - - mAccessibilityManager = - (AccessibilityManager) getContext().getSystemService(Service.ACCESSIBILITY_SERVICE); } public CheckBoxPreference(Context context, AttributeSet attrs) { @@ -84,246 +62,9 @@ public class CheckBoxPreference extends Preference { if (checkboxView != null && checkboxView instanceof Checkable) { ((Checkable) checkboxView).setChecked(mChecked); - // send an event to announce the value change of the CheckBox and is done here - // because clicking a preference does not immediately change the checked state - // for example when enabling the WiFi - if (mSendAccessibilityEventViewClickedType && - mAccessibilityManager.isEnabled() && - checkboxView.isEnabled()) { - mSendAccessibilityEventViewClickedType = false; - - // we send an event on behalf of the check box because in onBind the latter - // is detached from its parent and such views do not send accessibility events - AccessibilityEvent event = AccessibilityEvent.obtain( - AccessibilityEvent.TYPE_VIEW_CLICKED); - event.setClassName(checkboxView.getClass().getName()); - event.setPackageName(getContext().getPackageName()); - event.setEnabled(checkboxView.isEnabled()); - event.setContentDescription(checkboxView.getContentDescription()); - event.setChecked(((Checkable) checkboxView).isChecked()); - mAccessibilityManager.sendAccessibilityEvent(event); - } - } - - // Sync the summary view - TextView summaryView = (TextView) view.findViewById(com.android.internal.R.id.summary); - if (summaryView != null) { - boolean useDefaultSummary = true; - if (mChecked && mSummaryOn != null) { - summaryView.setText(mSummaryOn); - useDefaultSummary = false; - } else if (!mChecked && mSummaryOff != null) { - summaryView.setText(mSummaryOff); - useDefaultSummary = false; - } - - if (useDefaultSummary) { - final CharSequence summary = getSummary(); - if (summary != null) { - summaryView.setText(summary); - useDefaultSummary = false; - } - } - - int newVisibility = View.GONE; - if (!useDefaultSummary) { - // Someone has written to it - newVisibility = View.VISIBLE; - } - if (newVisibility != summaryView.getVisibility()) { - summaryView.setVisibility(newVisibility); - } - } - } - - @Override - protected void onClick() { - super.onClick(); - - boolean newValue = !isChecked(); - - // in onBindView() an AccessibilityEventViewClickedType is sent to announce the change - // not sending - mSendAccessibilityEventViewClickedType = true; - - if (!callChangeListener(newValue)) { - return; - } - - setChecked(newValue); - } - - /** - * Sets the checked state and saves it to the {@link SharedPreferences}. - * - * @param checked The checked state. - */ - public void setChecked(boolean checked) { - if (mChecked != checked) { - mChecked = checked; - persistBoolean(checked); - notifyDependencyChange(shouldDisableDependents()); - notifyChanged(); - } - } - - /** - * Returns the checked state. - * - * @return The checked state. - */ - public boolean isChecked() { - return mChecked; - } - - @Override - public boolean shouldDisableDependents() { - boolean shouldDisable = mDisableDependentsState ? mChecked : !mChecked; - return shouldDisable || super.shouldDisableDependents(); - } - - /** - * Sets the summary to be shown when checked. - * - * @param summary The summary to be shown when checked. - */ - public void setSummaryOn(CharSequence summary) { - mSummaryOn = summary; - if (isChecked()) { - notifyChanged(); - } - } - - /** - * @see #setSummaryOn(CharSequence) - * @param summaryResId The summary as a resource. - */ - public void setSummaryOn(int summaryResId) { - setSummaryOn(getContext().getString(summaryResId)); - } - - /** - * Returns the summary to be shown when checked. - * @return The summary. - */ - public CharSequence getSummaryOn() { - return mSummaryOn; - } - - /** - * Sets the summary to be shown when unchecked. - * - * @param summary The summary to be shown when unchecked. - */ - public void setSummaryOff(CharSequence summary) { - mSummaryOff = summary; - if (!isChecked()) { - notifyChanged(); - } - } - - /** - * @see #setSummaryOff(CharSequence) - * @param summaryResId The summary as a resource. - */ - public void setSummaryOff(int summaryResId) { - setSummaryOff(getContext().getString(summaryResId)); - } - - /** - * Returns the summary to be shown when unchecked. - * @return The summary. - */ - public CharSequence getSummaryOff() { - return mSummaryOff; - } - - /** - * Returns whether dependents are disabled when this preference is on ({@code true}) - * or when this preference is off ({@code false}). - * - * @return Whether dependents are disabled when this preference is on ({@code true}) - * or when this preference is off ({@code false}). - */ - public boolean getDisableDependentsState() { - return mDisableDependentsState; - } - - /** - * Sets whether dependents are disabled when this preference is on ({@code true}) - * or when this preference is off ({@code false}). - * - * @param disableDependentsState The preference state that should disable dependents. - */ - public void setDisableDependentsState(boolean disableDependentsState) { - mDisableDependentsState = disableDependentsState; - } - - @Override - protected Object onGetDefaultValue(TypedArray a, int index) { - return a.getBoolean(index, false); - } - - @Override - protected void onSetInitialValue(boolean restoreValue, Object defaultValue) { - setChecked(restoreValue ? getPersistedBoolean(mChecked) - : (Boolean) defaultValue); - } - - @Override - protected Parcelable onSaveInstanceState() { - final Parcelable superState = super.onSaveInstanceState(); - if (isPersistent()) { - // No need to save instance state since it's persistent - return superState; - } - - final SavedState myState = new SavedState(superState); - myState.checked = isChecked(); - return myState; - } - - @Override - protected void onRestoreInstanceState(Parcelable state) { - if (state == null || !state.getClass().equals(SavedState.class)) { - // Didn't save state for us in onSaveInstanceState - super.onRestoreInstanceState(state); - return; - } - - SavedState myState = (SavedState) state; - super.onRestoreInstanceState(myState.getSuperState()); - setChecked(myState.checked); - } - - private static class SavedState extends BaseSavedState { - boolean checked; - - public SavedState(Parcel source) { - super(source); - checked = source.readInt() == 1; - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - super.writeToParcel(dest, flags); - dest.writeInt(checked ? 1 : 0); + sendAccessibilityEventForView(checkboxView); } - public SavedState(Parcelable superState) { - super(superState); - } - - public static final Parcelable.Creator<SavedState> CREATOR = - new Parcelable.Creator<SavedState>() { - public SavedState createFromParcel(Parcel in) { - return new SavedState(in); - } - - public SavedState[] newArray(int size) { - return new SavedState[size]; - } - }; + syncSummaryView(view); } - } diff --git a/core/java/android/preference/SwitchPreference.java b/core/java/android/preference/SwitchPreference.java new file mode 100644 index 000000000000..f681526a3ce4 --- /dev/null +++ b/core/java/android/preference/SwitchPreference.java @@ -0,0 +1,180 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.preference; + +import android.content.Context; +import android.content.res.TypedArray; +import android.util.AttributeSet; +import android.view.View; +import android.widget.Checkable; +import android.widget.CompoundButton; +import android.widget.Switch; + +/** + * A {@link Preference} that provides a two-state toggleable option. + * <p> + * This preference will store a boolean into the SharedPreferences. + * + * @attr ref android.R.styleable#SwitchPreference_summaryOff + * @attr ref android.R.styleable#SwitchPreference_summaryOn + * @attr ref android.R.styleable#SwitchPreference_switchTextOff + * @attr ref android.R.styleable#SwitchPreference_switchTextOn + * @attr ref android.R.styleable#SwitchPreference_disableDependentsState + */ +public class SwitchPreference extends TwoStatePreference { + // Switch text for on and off states + private CharSequence mSwitchOn; + private CharSequence mSwitchOff; + private final Listener mListener = new Listener(); + + private class Listener implements View.OnClickListener, CompoundButton.OnCheckedChangeListener { + @Override + public void onClick(View v) { + SwitchPreference.this.onClick(); + } + + @Override + public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { + SwitchPreference.this.setChecked(isChecked); + } + } + + /** + * Construct a new SwitchPreference with the given style options. + * + * @param context The Context that will style this preference + * @param attrs Style attributes that differ from the default + * @param defStyle Theme attribute defining the default style options + */ + public SwitchPreference(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + + TypedArray a = context.obtainStyledAttributes(attrs, + com.android.internal.R.styleable.SwitchPreference, defStyle, 0); + setSummaryOn(a.getString(com.android.internal.R.styleable.SwitchPreference_summaryOn)); + setSummaryOff(a.getString(com.android.internal.R.styleable.SwitchPreference_summaryOff)); + setSwitchTextOn(a.getString( + com.android.internal.R.styleable.SwitchPreference_switchTextOn)); + setSwitchTextOff(a.getString( + com.android.internal.R.styleable.SwitchPreference_switchTextOff)); + setDisableDependentsState(a.getBoolean( + com.android.internal.R.styleable.SwitchPreference_disableDependentsState, false)); + a.recycle(); + } + + /** + * Construct a new SwitchPreference with the given style options. + * + * @param context The Context that will style this preference + * @param attrs Style attributes that differ from the default + */ + public SwitchPreference(Context context, AttributeSet attrs) { + this(context, attrs, com.android.internal.R.attr.switchPreferenceStyle); + } + + /** + * Construct a new SwitchPreference with default style options. + * + * @param context The Context that will style this preference + */ + public SwitchPreference(Context context) { + this(context, null); + } + + @Override + protected void onBindView(View view) { + super.onBindView(view); + + View checkableView = view.findViewById(com.android.internal.R.id.switchWidget); + if (checkableView != null && checkableView instanceof Checkable) { + ((Checkable) checkableView).setChecked(mChecked); + + sendAccessibilityEventForView(checkableView); + + if (checkableView instanceof Switch) { + final Switch switchView = (Switch) checkableView; + switchView.setTextOn(mSwitchOn); + switchView.setTextOff(mSwitchOff); + switchView.setOnCheckedChangeListener(mListener); + } + + if (checkableView.hasFocusable()) { + // This is a focusable list item. Attach a click handler to toggle the button + // for the rest of the item. + view.setOnClickListener(mListener); + } + } + + syncSummaryView(view); + } + + /** + * Set the text displayed on the switch widget in the on state. + * This should be a very short string; one word if possible. + * + * @param onText Text to display in the on state + */ + public void setSwitchTextOn(CharSequence onText) { + mSwitchOn = onText; + notifyChanged(); + } + + /** + * Set the text displayed on the switch widget in the off state. + * This should be a very short string; one word if possible. + * + * @param offText Text to display in the off state + */ + public void setSwitchTextOff(CharSequence offText) { + mSwitchOff = offText; + notifyChanged(); + } + + /** + * Set the text displayed on the switch widget in the on state. + * This should be a very short string; one word if possible. + * + * @param resId The text as a string resource ID + */ + public void setSwitchTextOn(int resId) { + setSwitchTextOn(getContext().getString(resId)); + } + + /** + * Set the text displayed on the switch widget in the off state. + * This should be a very short string; one word if possible. + * + * @param resId The text as a string resource ID + */ + public void setSwitchTextOff(int resId) { + setSwitchTextOff(getContext().getString(resId)); + } + + /** + * @return The text that will be displayed on the switch widget in the on state + */ + public CharSequence getSwitchTextOn() { + return mSwitchOn; + } + + /** + * @return The text that will be displayed on the switch widget in the off state + */ + public CharSequence getSwitchTextOff() { + return mSwitchOff; + } +} diff --git a/core/java/android/preference/TwoStatePreference.java b/core/java/android/preference/TwoStatePreference.java new file mode 100644 index 000000000000..8e21c4c493a5 --- /dev/null +++ b/core/java/android/preference/TwoStatePreference.java @@ -0,0 +1,309 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.preference; + +import android.app.Service; +import android.content.Context; +import android.content.SharedPreferences; +import android.content.res.TypedArray; +import android.os.Parcel; +import android.os.Parcelable; +import android.util.AttributeSet; +import android.view.View; +import android.view.accessibility.AccessibilityEvent; +import android.view.accessibility.AccessibilityManager; +import android.widget.TextView; + +/** + * Common base class for preferences that have two selectable states, persist a + * boolean value in SharedPreferences, and may have dependent preferences that are + * enabled/disabled based on the current state. + */ +public abstract class TwoStatePreference extends Preference { + + private CharSequence mSummaryOn; + private CharSequence mSummaryOff; + boolean mChecked; + private boolean mSendAccessibilityEventViewClickedType; + private AccessibilityManager mAccessibilityManager; + private boolean mDisableDependentsState; + + public TwoStatePreference(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + + mAccessibilityManager = + (AccessibilityManager) getContext().getSystemService(Service.ACCESSIBILITY_SERVICE); + } + + public TwoStatePreference(Context context, AttributeSet attrs) { + super(context, attrs); + + mAccessibilityManager = + (AccessibilityManager) getContext().getSystemService(Service.ACCESSIBILITY_SERVICE); + } + + public TwoStatePreference(Context context) { + super(context); + + mAccessibilityManager = + (AccessibilityManager) getContext().getSystemService(Service.ACCESSIBILITY_SERVICE); + } + + @Override + protected void onClick() { + super.onClick(); + + boolean newValue = !isChecked(); + + // in onBindView() an AccessibilityEventViewClickedType is sent to announce the change + // not sending + mSendAccessibilityEventViewClickedType = true; + + if (!callChangeListener(newValue)) { + return; + } + + setChecked(newValue); + } + + /** + * Sets the checked state and saves it to the {@link SharedPreferences}. + * + * @param checked The checked state. + */ + public void setChecked(boolean checked) { + if (mChecked != checked) { + mChecked = checked; + persistBoolean(checked); + notifyDependencyChange(shouldDisableDependents()); + notifyChanged(); + } + } + + /** + * Returns the checked state. + * + * @return The checked state. + */ + public boolean isChecked() { + return mChecked; + } + + @Override + public boolean shouldDisableDependents() { + boolean shouldDisable = mDisableDependentsState ? mChecked : !mChecked; + return shouldDisable || super.shouldDisableDependents(); + } + + /** + * Sets the summary to be shown when checked. + * + * @param summary The summary to be shown when checked. + */ + public void setSummaryOn(CharSequence summary) { + mSummaryOn = summary; + if (isChecked()) { + notifyChanged(); + } + } + + /** + * @see #setSummaryOn(CharSequence) + * @param summaryResId The summary as a resource. + */ + public void setSummaryOn(int summaryResId) { + setSummaryOn(getContext().getString(summaryResId)); + } + + /** + * Returns the summary to be shown when checked. + * @return The summary. + */ + public CharSequence getSummaryOn() { + return mSummaryOn; + } + + /** + * Sets the summary to be shown when unchecked. + * + * @param summary The summary to be shown when unchecked. + */ + public void setSummaryOff(CharSequence summary) { + mSummaryOff = summary; + if (!isChecked()) { + notifyChanged(); + } + } + + /** + * @see #setSummaryOff(CharSequence) + * @param summaryResId The summary as a resource. + */ + public void setSummaryOff(int summaryResId) { + setSummaryOff(getContext().getString(summaryResId)); + } + + /** + * Returns the summary to be shown when unchecked. + * @return The summary. + */ + public CharSequence getSummaryOff() { + return mSummaryOff; + } + + /** + * Returns whether dependents are disabled when this preference is on ({@code true}) + * or when this preference is off ({@code false}). + * + * @return Whether dependents are disabled when this preference is on ({@code true}) + * or when this preference is off ({@code false}). + */ + public boolean getDisableDependentsState() { + return mDisableDependentsState; + } + + /** + * Sets whether dependents are disabled when this preference is on ({@code true}) + * or when this preference is off ({@code false}). + * + * @param disableDependentsState The preference state that should disable dependents. + */ + public void setDisableDependentsState(boolean disableDependentsState) { + mDisableDependentsState = disableDependentsState; + } + + @Override + protected Object onGetDefaultValue(TypedArray a, int index) { + return a.getBoolean(index, false); + } + + @Override + protected void onSetInitialValue(boolean restoreValue, Object defaultValue) { + setChecked(restoreValue ? getPersistedBoolean(mChecked) + : (Boolean) defaultValue); + } + + /** + * Send an accessibility event for the given view if appropriate + * @param view View that should send the event + */ + void sendAccessibilityEventForView(View view) { + // send an event to announce the value change of the state. It is done here + // because clicking a preference does not immediately change the checked state + // for example when enabling the WiFi + if (mSendAccessibilityEventViewClickedType && + mAccessibilityManager.isEnabled() && + view.isEnabled()) { + mSendAccessibilityEventViewClickedType = false; + + int eventType = AccessibilityEvent.TYPE_VIEW_CLICKED; + view.sendAccessibilityEventUnchecked(AccessibilityEvent.obtain(eventType)); + } + } + + /** + * Sync a summary view contained within view's subhierarchy with the correct summary text. + * @param view View where a summary should be located + */ + void syncSummaryView(View view) { + // Sync the summary view + TextView summaryView = (TextView) view.findViewById(com.android.internal.R.id.summary); + if (summaryView != null) { + boolean useDefaultSummary = true; + if (mChecked && mSummaryOn != null) { + summaryView.setText(mSummaryOn); + useDefaultSummary = false; + } else if (!mChecked && mSummaryOff != null) { + summaryView.setText(mSummaryOff); + useDefaultSummary = false; + } + + if (useDefaultSummary) { + final CharSequence summary = getSummary(); + if (summary != null) { + summaryView.setText(summary); + useDefaultSummary = false; + } + } + + int newVisibility = View.GONE; + if (!useDefaultSummary) { + // Someone has written to it + newVisibility = View.VISIBLE; + } + if (newVisibility != summaryView.getVisibility()) { + summaryView.setVisibility(newVisibility); + } + } + } + + @Override + protected Parcelable onSaveInstanceState() { + final Parcelable superState = super.onSaveInstanceState(); + if (isPersistent()) { + // No need to save instance state since it's persistent + return superState; + } + + final SavedState myState = new SavedState(superState); + myState.checked = isChecked(); + return myState; + } + + @Override + protected void onRestoreInstanceState(Parcelable state) { + if (state == null || !state.getClass().equals(SavedState.class)) { + // Didn't save state for us in onSaveInstanceState + super.onRestoreInstanceState(state); + return; + } + + SavedState myState = (SavedState) state; + super.onRestoreInstanceState(myState.getSuperState()); + setChecked(myState.checked); + } + + static class SavedState extends BaseSavedState { + boolean checked; + + public SavedState(Parcel source) { + super(source); + checked = source.readInt() == 1; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + super.writeToParcel(dest, flags); + dest.writeInt(checked ? 1 : 0); + } + + public SavedState(Parcelable superState) { + super(superState); + } + + public static final Parcelable.Creator<SavedState> CREATOR = + new Parcelable.Creator<SavedState>() { + public SavedState createFromParcel(Parcel in) { + return new SavedState(in); + } + + public SavedState[] newArray(int size) { + return new SavedState[size]; + } + }; + } +} diff --git a/core/java/android/provider/Calendar.java b/core/java/android/provider/Calendar.java index a06d0f6af732..bb6ed9c82b7c 100644 --- a/core/java/android/provider/Calendar.java +++ b/core/java/android/provider/Calendar.java @@ -85,10 +85,10 @@ public final class Calendar { * {@link ContentResolver#notifyChange(android.net.Uri, android.database.ContentObserver, boolean)} * , the third parameter "syncToNetwork" is set to false. Furthermore, if * set to true, the caller must also include - * {@link SyncColumns#ACCOUNT_NAME} and {@link SyncColumns#ACCOUNT_TYPE} as + * {@link Calendars#ACCOUNT_NAME} and {@link Calendars#ACCOUNT_TYPE} as * query parameters. * - * @See Uri.Builder#appendQueryParameter(java.lang.String, java.lang.String) + * @see Uri.Builder#appendQueryParameter(java.lang.String, java.lang.String) */ public static final String CALLER_IS_SYNCADAPTER = "caller_is_syncadapter"; @@ -111,18 +111,66 @@ public final class Calendar { */ protected interface CalendarSyncColumns { - /** Generic column for use by sync adapters. */ + + /** + * Generic column for use by sync adapters. Column name. + * <P>Type: TEXT</P> + */ public static final String CAL_SYNC1 = "cal_sync1"; - /** Generic column for use by sync adapters. */ + + /** + * Generic column for use by sync adapters. Column name. + * <P>Type: TEXT</P> + */ public static final String CAL_SYNC2 = "cal_sync2"; - /** Generic column for use by sync adapters. */ + + /** + * Generic column for use by sync adapters. Column name. + * <P>Type: TEXT</P> + */ public static final String CAL_SYNC3 = "cal_sync3"; - /** Generic column for use by sync adapters. */ + + /** + * Generic column for use by sync adapters. Column name. + * <P>Type: TEXT</P> + */ public static final String CAL_SYNC4 = "cal_sync4"; - /** Generic column for use by sync adapters. */ + + /** + * Generic column for use by sync adapters. Column name. + * <P>Type: TEXT</P> + */ public static final String CAL_SYNC5 = "cal_sync5"; - /** Generic column for use by sync adapters. */ + + /** + * Generic column for use by sync adapters. Column name. + * <P>Type: TEXT</P> + */ public static final String CAL_SYNC6 = "cal_sync6"; + + /** + * Generic column for use by sync adapters. Column name. + * <P>Type: TEXT</P> + */ + public static final String CAL_SYNC7 = "cal_sync7"; + + /** + * Generic column for use by sync adapters. Column name. + * <P>Type: TEXT</P> + */ + public static final String CAL_SYNC8 = "cal_sync8"; + + /** + * Generic column for use by sync adapters. Column name. + * <P>Type: TEXT</P> + */ + public static final String CAL_SYNC9 = "cal_sync9"; + + /** + * Generic column for use by sync adapters. Column name. + * <P>Type: TEXT</P> + */ + public static final String CAL_SYNC10 = "cal_sync10"; } /** @@ -159,35 +207,26 @@ public final class Calendar { public static final String _SYNC_ID = "_sync_id"; /** - * The last time, from the sync source's point of view, that this row - * has been synchronized. - * <P>Type: INTEGER (long)</P> - */ - public static final String _SYNC_TIME = "_sync_time"; - - /** - * The version of the row, as assigned by the server. - * <P>Type: TEXT</P> - */ - public static final String _SYNC_VERSION = "_sync_version"; - - /** - * Used only in persistent providers, and only during merging. + * Used to indicate that local, unsynced, changes are present. * <P>Type: INTEGER (long)</P> */ - public static final String _SYNC_MARK = "_sync_mark"; + public static final String DIRTY = "dirty"; /** - * Used to indicate that local, unsynced, changes are present. - * <P>Type: INTEGER (long)</P> + * Whether the row has been deleted but not synced to the server. A + * deleted row should be ignored. + * <P> + * Type: INTEGER (boolean) + * </P> */ - public static final String DIRTY = "dirty"; + public static final String DELETED = "deleted"; /** * If set to 1 this causes events on this calendar to be duplicated with - * {@link EventsColumns#LAST_SYNCED} set to 1 whenever the event transitions from non-dirty - * to dirty. The duplicated event will not be expanded in the instances table and will only - * show up in sync adapter queries of the events table. It will also be deleted when the + * {@link EventsColumns#LAST_SYNCED} set to 1 whenever the event + * transitions from non-dirty to dirty. The duplicated event will not be + * expanded in the instances table and will only show up in sync adapter + * queries of the events table. It will also be deleted when the * originating event has its dirty flag cleared by the sync adapter. * <P>Type: INTEGER (boolean)</P> */ @@ -205,33 +244,39 @@ public final class Calendar { public static final String CALENDAR_COLOR = "calendar_color"; /** + * The display name of the calendar. Column name. + * <P>Type: TEXT</P> + */ + public static final String CALENDAR_DISPLAY_NAME = "calendar_displayName"; + + /** * The level of access that the user has for the calendar * <P>Type: INTEGER (one of the values below)</P> */ - public static final String ACCESS_LEVEL = "access_level"; + public static final String CALENDAR_ACCESS_LEVEL = "calendar_access_level"; /** Cannot access the calendar */ - public static final int NO_ACCESS = 0; + public static final int CAL_ACCESS_NONE = 0; /** Can only see free/busy information about the calendar */ - public static final int FREEBUSY_ACCESS = 100; + public static final int CAL_ACCESS_FREEBUSY = 100; /** Can read all event details */ - public static final int READ_ACCESS = 200; + public static final int CAL_ACCESS_READ = 200; /** Can reply yes/no/maybe to an event */ - public static final int RESPOND_ACCESS = 300; + public static final int CAL_ACCESS_RESPOND = 300; /** not used */ - public static final int OVERRIDE_ACCESS = 400; + public static final int CAL_ACCESS_OVERRIDE = 400; /** Full access to modify the calendar, but not the access control * settings */ - public static final int CONTRIBUTOR_ACCESS = 500; + public static final int CAL_ACCESS_CONTRIBUTOR = 500; /** Full access to modify the calendar, but not the access control * settings */ - public static final int EDITOR_ACCESS = 600; + public static final int CAL_ACCESS_EDITOR = 600; /** Full access to the calendar */ - public static final int OWNER_ACCESS = 700; + public static final int CAL_ACCESS_OWNER = 700; /** Domain admin */ - public static final int ROOT_ACCESS = 800; + public static final int CAL_ACCESS_ROOT = 800; /** * Is the calendar selected to be displayed? @@ -245,7 +290,7 @@ public final class Calendar { * The time zone the calendar is associated with. * <P>Type: TEXT</P> */ - public static final String CALENDAR_TIMEZONE = "calendar_timezone"; + public static final String CALENDAR_TIME_ZONE = "calendar_timezone"; /** * Is this calendar synced and are its events stored on the device? @@ -256,17 +301,41 @@ public final class Calendar { public static final String SYNC_EVENTS = "sync_events"; /** - * Sync state data. Usable by the sync adapter. - * <p>Type: String (blob)</p> + * The owner account for this calendar, based on the calendar feed. + * This will be different from the _SYNC_ACCOUNT for delegated calendars. + * Column name. + * <P>Type: String</P> */ - public static final String SYNC_STATE = "sync_state"; + public static final String OWNER_ACCOUNT = "ownerAccount"; /** - * Whether the row has been deleted but not synced to the server. A - * deleted row should be ignored. + * Can the organizer respond to the event? If no, the status of the + * organizer should not be shown by the UI. Defaults to 1. Column name. * <P>Type: INTEGER (boolean)</P> */ - public static final String DELETED = "deleted"; + public static final String CAN_ORGANIZER_RESPOND = "canOrganizerRespond"; + + /** + * Can the organizer modify the time zone of the event? Column name. + * <P>Type: INTEGER (boolean)</P> + */ + public static final String CAN_MODIFY_TIME_ZONE = "canModifyTimeZone"; + + /** + * The maximum number of reminders allowed for an event. Column name. + * <P>Type: INTEGER</P> + */ + public static final String MAX_REMINDERS = "maxReminders"; + + /** + * A comma separated list of reminder methods supported for this + * calendar in the format "#,#,#". Valid types are + * {@link Reminders#METHOD_DEFAULT}, {@link Reminders#METHOD_ALERT}, + * {@link Reminders#METHOD_EMAIL}, {@link Reminders#METHOD_SMS}. Column + * name. + * <P>Type: TEXT</P> + */ + public static final String ALLOWED_REMINDERS = "allowedReminders"; } /** @@ -312,28 +381,30 @@ public final class Calendar { DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, ACCOUNT_TYPE); DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, _SYNC_ID); - DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, _SYNC_VERSION); - DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, _SYNC_TIME); DatabaseUtils.cursorLongToContentValuesIfPresent(cursor, cv, DIRTY); - DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, Calendars.CAL_SYNC1); - DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, Calendars.CAL_SYNC2); - DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, Calendars.CAL_SYNC3); - DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, Calendars.CAL_SYNC4); - DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, Calendars.CAL_SYNC5); - DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, Calendars.CAL_SYNC6); + DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, CAL_SYNC1); + DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, CAL_SYNC2); + DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, CAL_SYNC3); + DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, CAL_SYNC4); + DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, CAL_SYNC5); + DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, CAL_SYNC6); + DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, CAL_SYNC7); + DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, CAL_SYNC8); + DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, CAL_SYNC9); + DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, CAL_SYNC10); DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, Calendars.NAME); DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, - Calendars.DISPLAY_NAME); + Calendars.CALENDAR_DISPLAY_NAME); DatabaseUtils.cursorIntToContentValuesIfPresent(cursor, cv, Calendars.CALENDAR_COLOR); - DatabaseUtils.cursorIntToContentValuesIfPresent(cursor, cv, ACCESS_LEVEL); + DatabaseUtils.cursorIntToContentValuesIfPresent(cursor, cv, CALENDAR_ACCESS_LEVEL); DatabaseUtils.cursorIntToContentValuesIfPresent(cursor, cv, VISIBLE); DatabaseUtils.cursorIntToContentValuesIfPresent(cursor, cv, SYNC_EVENTS); DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, Calendars.CALENDAR_LOCATION); - DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, CALENDAR_TIMEZONE); + DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, CALENDAR_TIME_ZONE); DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, Calendars.OWNER_ACCOUNT); DatabaseUtils.cursorIntToContentValuesIfPresent(cursor, cv, @@ -344,6 +415,8 @@ public final class Calendar { Calendars.MAX_REMINDERS); DatabaseUtils.cursorIntToContentValuesIfPresent(cursor, cv, Calendars.CAN_PARTIALLY_UPDATE); + DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, + Calendars.ALLOWED_REMINDERS); DatabaseUtils.cursorIntToContentValuesIfPresent(cursor, cv, DELETED); @@ -429,96 +502,27 @@ public final class Calendar { public static final String DEFAULT_SORT_ORDER = "displayName"; /** - * The URL to the calendar. Column name. - * <P>Type: TEXT (URL)</P> - */ - public static final String URL = "url"; - - /** - * The URL for the calendar itself. Column name. - * <P>Type: TEXT (URL)</P> - */ - public static final String SELF_URL = "selfUrl"; - - /** - * The URL for the calendar to be edited. Column name. - * <P>Type: TEXT (URL)</P> - */ - public static final String EDIT_URL = "editUrl"; - - /** - * The URL for the calendar events. Column name. - * <P>Type: TEXT (URL)</P> - */ - public static final String EVENTS_URL = "eventsUrl"; - - /** * The name of the calendar. Column name. * <P>Type: TEXT</P> */ public static final String NAME = "name"; /** - * The display name of the calendar. Column name. - * <P>Type: TEXT</P> - */ - public static final String DISPLAY_NAME = "displayName"; - - /** * The default location for the calendar. Column name. * <P>Type: TEXT</P> */ public static final String CALENDAR_LOCATION = "calendar_location"; /** - * The owner account for this calendar, based on the calendar feed. - * This will be different from the _SYNC_ACCOUNT for delegated calendars. - * Column name. - * <P>Type: String</P> - */ - public static final String OWNER_ACCOUNT = "ownerAccount"; - - /** - * Can the organizer respond to the event? If no, the status of the - * organizer should not be shown by the UI. Defaults to 1. Column name. - * <P>Type: INTEGER (boolean)</P> - */ - public static final String CAN_ORGANIZER_RESPOND = "canOrganizerRespond"; - - /** - * Can the organizer modify the time zone of the event? Column name. - * <P>Type: INTEGER (boolean)</P> - */ - public static final String CAN_MODIFY_TIME_ZONE = "canModifyTimeZone"; - - /** - * The maximum number of reminders allowed for an event. Column name. - * <P>Type: INTEGER</P> - */ - public static final String MAX_REMINDERS = "maxReminders"; - - /** - * A comma separated list of reminder methods supported for this - * calendar in the format "#,#,#". Valid types are - * {@link Reminders#METHOD_DEFAULT}, {@link Reminders#METHOD_ALERT}, - * {@link Reminders#METHOD_EMAIL}, {@link Reminders#METHOD_SMS}. Column - * name. - * <P>Type: TEXT</P> - */ - public static final String ALLOWED_REMINDERS = "allowedReminders"; - - /** * These fields are only writable by a sync adapter. To modify them the * caller must include {@link #CALLER_IS_SYNCADAPTER}, - * {@link #ACCOUNT_NAME}, and {@link #ACCOUNT_TYPE} in the query + * {@link #ACCOUNT_NAME}, and {@link #ACCOUNT_TYPE} in the Uri's query * parameters. */ public static final String[] SYNC_WRITABLE_COLUMNS = new String[] { ACCOUNT_NAME, ACCOUNT_TYPE, _SYNC_ID, - _SYNC_TIME, - _SYNC_VERSION, DIRTY, OWNER_ACCOUNT, MAX_REMINDERS, @@ -526,8 +530,8 @@ public final class Calendar { CAN_ORGANIZER_RESPOND, CAN_PARTIALLY_UPDATE, CALENDAR_LOCATION, - CALENDAR_TIMEZONE, - ACCESS_LEVEL, + CALENDAR_TIME_ZONE, + CALENDAR_ACCESS_LEVEL, DELETED, CAL_SYNC1, CAL_SYNC2, @@ -535,7 +539,10 @@ public final class Calendar { CAL_SYNC4, CAL_SYNC5, CAL_SYNC6, - SYNC_STATE, + CAL_SYNC7, + CAL_SYNC8, + CAL_SYNC9, + CAL_SYNC10, }; } @@ -633,12 +640,6 @@ public final class Calendar { * Columns from the Events table that other tables join into themselves. */ private interface EventsColumns { - /** - * For use by sync adapter at its discretion. Column name. - * TODO change to sync_data2 - * <P>Type: INTEGER (long)</P> - */ - public static final String _SYNC_DATA = "_sync_local_id"; /** * The {@link Calendars#_ID} of the calendar the event belongs to. @@ -648,13 +649,6 @@ public final class Calendar { public static final String CALENDAR_ID = "calendar_id"; /** - * The URI for an HTML version of this event. Column name. - * TODO change to sync_data3 - * <P>Type: TEXT</P> - */ - public static final String HTML_URI = "htmlUri"; - - /** * The title of the event. Column name. * <P>Type: TEXT</P> */ @@ -673,6 +667,12 @@ public final class Calendar { public static final String EVENT_LOCATION = "eventLocation"; /** + * A secondary color for the individual event. Column name. + * <P>Type: INTEGER</P> + */ + public static final String EVENT_COLOR = "eventColor"; + + /** * The event status. Column name. * <P>Type: INTEGER (one of {@link #STATUS_TENTATIVE}...)</P> */ @@ -699,12 +699,60 @@ public final class Calendar { public static final String SYNC_DATA1 = "sync_data1"; /** - * This column is available for use by sync adapters + * This column is available for use by sync adapters. Column name. + * <P>Type: TEXT</P> + */ + public static final String SYNC_DATA2 = "sync_data2"; + + /** + * This column is available for use by sync adapters. Column name. + * <P>Type: TEXT</P> + */ + public static final String SYNC_DATA3 = "sync_data3"; + + /** + * This column is available for use by sync adapters. Column name. + * <P>Type: TEXT</P> + */ + public static final String SYNC_DATA4 = "sync_data4"; + + /** + * This column is available for use by sync adapters. Column name. + * <P>Type: TEXT</P> + */ + public static final String SYNC_DATA5 = "sync_data5"; + + /** + * This column is available for use by sync adapters. Column name. + * <P>Type: TEXT</P> + */ + public static final String SYNC_DATA6 = "sync_data6"; + + /** + * This column is available for use by sync adapters. Column name. * <P>Type: TEXT</P> */ public static final String SYNC_DATA7 = "sync_data7"; /** + * This column is available for use by sync adapters. Column name. + * <P>Type: TEXT</P> + */ + public static final String SYNC_DATA8 = "sync_data8"; + + /** + * This column is available for use by sync adapters. Column name. + * <P>Type: TEXT</P> + */ + public static final String SYNC_DATA9 = "sync_data9"; + + /** + * This column is available for use by sync adapters. Column name. + * <P>Type: TEXT</P> + */ + public static final String SYNC_DATA10 = "sync_data10"; + + /** * Used to indicate that a row is not a real event but an original copy of a locally * modified event. A copy is made when an event changes from non-dirty to dirty and the * event is on a calendar with {@link Calendars#CAN_PARTIALLY_UPDATE} set to 1. This copy @@ -716,13 +764,6 @@ public final class Calendar { public static final String LAST_SYNCED = "lastSynced"; /** - * The comments feed uri. Column name. - * TODO change to sync_data6 - * <P>Type: TEXT</P> - */ - public static final String COMMENTS_URI = "commentsUri"; - - /** * The time the event starts in UTC millis since epoch. Column name. * <P>Type: INTEGER (long; millis since epoch)</P> */ @@ -916,20 +957,6 @@ public final class Calendar { * <P>Type: INTEGER (boolean, readonly)</P> */ public static final String CAN_INVITE_OTHERS = "canInviteOthers"; - - /** - * The owner account for this calendar, based on the calendar (foreign - * key into the calendars table). Column name. - * <P>Type: String</P> - */ - public static final String OWNER_ACCOUNT = "ownerAccount"; - - /** - * Whether the row has been deleted. A deleted row should be ignored. - * Column name. - * <P>Type: INTEGER (boolean)</P> - */ - public static final String DELETED = "deleted"; } /** @@ -1024,13 +1051,11 @@ public final class Calendar { ContentValues cv = new ContentValues(); cv.put(Events._ID, eventId); DatabaseUtils.cursorIntToContentValuesIfPresent(cursor, cv, CALENDAR_ID); - DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, HTML_URI); DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, TITLE); DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, DESCRIPTION); DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, EVENT_LOCATION); DatabaseUtils.cursorIntToContentValuesIfPresent(cursor, cv, STATUS); DatabaseUtils.cursorIntToContentValuesIfPresent(cursor, cv, SELF_ATTENDEE_STATUS); - DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, COMMENTS_URI); DatabaseUtils.cursorLongToContentValuesIfPresent(cursor, cv, DTSTART); DatabaseUtils.cursorLongToContentValuesIfPresent(cursor, cv, DTEND); DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, DURATION); @@ -1059,20 +1084,29 @@ public final class Calendar { DatabaseUtils.cursorIntToContentValuesIfPresent(cursor, cv, GUESTS_CAN_SEE_GUESTS); DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, ORGANIZER); DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, _SYNC_ID); - DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, _SYNC_DATA); - DatabaseUtils.cursorLongToContentValuesIfPresent(cursor, cv, SYNC_DATA7); DatabaseUtils.cursorLongToContentValuesIfPresent(cursor, cv, DIRTY); DatabaseUtils.cursorLongToContentValuesIfPresent(cursor, cv, LAST_SYNCED); - DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, _SYNC_VERSION); DatabaseUtils.cursorIntToContentValuesIfPresent(cursor, cv, DELETED); + DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, SYNC_DATA1); + DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, SYNC_DATA2); + DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, SYNC_DATA3); + DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, SYNC_DATA4); + DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, SYNC_DATA5); + DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, SYNC_DATA6); + DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, SYNC_DATA7); + DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, SYNC_DATA8); + DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, SYNC_DATA9); + DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, SYNC_DATA10); DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, CAL_SYNC1); DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, CAL_SYNC2); DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, CAL_SYNC3); DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, CAL_SYNC4); DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, CAL_SYNC5); DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, CAL_SYNC6); - DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, - Events.SYNC_DATA1); + DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, CAL_SYNC7); + DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, CAL_SYNC8); + DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, CAL_SYNC9); + DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, CAL_SYNC10); Entity entity = new Entity(cv); Cursor subCursor; @@ -1163,7 +1197,8 @@ public final class Calendar { /** * Fields and helpers for interacting with Events. */ - public static final class Events implements BaseColumns, SyncColumns, EventsColumns { + public static final class Events implements BaseColumns, SyncColumns, EventsColumns, + CalendarsColumns { /** * Queries all events with the given projection. This is a blocking call @@ -1206,6 +1241,14 @@ public final class Calendar { Uri.parse("content://" + AUTHORITY + "/events"); /** + * The content:// style URI for recurring event exceptions. Insertions require an + * appended event ID. Deletion of exceptions requires both the original event ID and + * the exception event ID (see {@link Uri.Builder#appendPath}). + */ + public static final Uri EXCEPTION_CONTENT_URI = + Uri.parse("content://" + AUTHORITY + "/exception"); + + /** * The default sort order for this table */ private static final String DEFAULT_SORT_ORDER = ""; @@ -1224,7 +1267,20 @@ public final class Calendar { CAL_SYNC4, CAL_SYNC5, CAL_SYNC6, + CAL_SYNC7, + CAL_SYNC8, + CAL_SYNC9, + CAL_SYNC10, + ALLOWED_REMINDERS, + CALENDAR_ACCESS_LEVEL, + CALENDAR_COLOR, + CALENDAR_TIME_ZONE, + CAN_MODIFY_TIME_ZONE, + CAN_ORGANIZER_RESPOND, + CALENDAR_DISPLAY_NAME, CAN_PARTIALLY_UPDATE, + SYNC_EVENTS, + VISIBLE, }; /** @@ -1234,10 +1290,17 @@ public final class Calendar { */ public static final String[] SYNC_WRITABLE_COLUMNS = new String[] { _SYNC_ID, - _SYNC_TIME, - _SYNC_VERSION, DIRTY, - SYNC_DATA1 + SYNC_DATA1, + SYNC_DATA2, + SYNC_DATA3, + SYNC_DATA4, + SYNC_DATA5, + SYNC_DATA6, + SYNC_DATA7, + SYNC_DATA8, + SYNC_DATA9, + SYNC_DATA10, }; } diff --git a/core/java/android/provider/CallLog.java b/core/java/android/provider/CallLog.java index bf051f58a286..02faf496843e 100644 --- a/core/java/android/provider/CallLog.java +++ b/core/java/android/provider/CallLog.java @@ -77,9 +77,17 @@ public class CallLog { */ public static final String TYPE = "type"; + /** Call log type for incoming calls. */ public static final int INCOMING_TYPE = 1; + /** Call log type for outgoing calls. */ public static final int OUTGOING_TYPE = 2; + /** Call log type for missed calls. */ public static final int MISSED_TYPE = 3; + /** + * Call log type for voicemails. + * @hide + */ + public static final int VOICEMAIL_TYPE = 4; /** * The phone number as the user entered it. @@ -143,6 +151,13 @@ public class CallLog { public static final String CACHED_NUMBER_LABEL = "numberlabel"; /** + * URI of the voicemail entry. Populated only for {@link #VOICEMAIL_TYPE}. + * <P>Type: TEXT</P> + * @hide + */ + public static final String VOICEMAIL_URI = "voicemail_uri"; + + /** * Adds a call to the call log. * * @param ci the CallerInfo object to get the target contact from. Can be null diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java index 22b4c761d758..6c14119aba2f 100644 --- a/core/java/android/provider/ContactsContract.java +++ b/core/java/android/provider/ContactsContract.java @@ -122,6 +122,17 @@ public final class ContactsContract { public static final String CALLER_IS_SYNCADAPTER = "caller_is_syncadapter"; /** + * An optional URI parameter for selection queries that instructs the + * provider to include the user's personal profile contact entry (if any) + * in the contact results. If present, the user's profile will always be + * the first entry returned. The default value is false. + * + * Specifying this parameter will result in a security error if the calling + * application does not have android.permission.READ_PROFILE permission. + */ + public static final String INCLUDE_PROFILE = "include_profile"; + + /** * A query parameter key used to specify the package that is requesting a query. * This is used for restricting data based on package name. * @@ -763,12 +774,18 @@ public final class ContactsContract { public static final String PHOTO_THUMBNAIL_URI = "photo_thumb_uri"; /** - * Lookup value that reflects the {@link Groups#GROUP_VISIBLE} state of - * any {@link CommonDataKinds.GroupMembership} for this contact. + * Flag that reflects the {@link Groups#GROUP_VISIBLE} state of any + * {@link CommonDataKinds.GroupMembership} for this contact. */ public static final String IN_VISIBLE_GROUP = "in_visible_group"; /** + * Flag that reflects whether this contact represents the user's + * personal profile entry. + */ + public static final String IS_USER_PROFILE = "is_user_profile"; + + /** * An indicator of whether this contact has at least one phone number. "1" if there is * at least one phone number, "0" otherwise. * <P>Type: INTEGER</P> @@ -1285,7 +1302,7 @@ public final class ContactsContract { * Base {@link Uri} for referencing multiple {@link Contacts} entry, * created by appending {@link #LOOKUP_KEY} using * {@link Uri#withAppendedPath(Uri, String)}. The lookup keys have to be - * encoded and joined with the colon (":") seperator. The resulting string + * encoded and joined with the colon (":") separator. The resulting string * has to be encoded again. Provides * {@link OpenableColumns} columns when queried, or returns the * referenced contact formatted as a vCard when opened through @@ -1738,6 +1755,88 @@ public final class ContactsContract { } } + /** + * <p> + * Constants for the user's profile data, which is represented as a single contact on + * the device that represents the user. The profile contact is not aggregated + * together automatically in the same way that normal contacts are; instead, each + * account on the device may contribute a single raw contact representing the user's + * personal profile data from that source. + * </p> + * <p> + * Access to the profile entry through these URIs (or incidental access to parts of + * the profile if retrieved directly via ID) requires additional permissions beyond + * the read/write contact permissions required by the provider. Querying for profile + * data requires android.permission.READ_PROFILE permission, and inserting or + * updating profile data requires android.permission.WRITE_PROFILE permission. + * </p> + * <h3>Operations</h3> + * <dl> + * <dt><b>Insert</b></dt> + * <dd>The user's profile entry cannot be created explicitly (attempting to do so + * will throw an exception). When a raw contact is inserted into the profile, the + * provider will check for the existence of a profile on the device. If one is + * found, the raw contact's {@link RawContacts#CONTACT_ID} column gets the _ID of + * the profile Contact. If no match is found, the profile Contact is created and + * its _ID is put into the {@link RawContacts#CONTACT_ID} column of the newly + * inserted raw contact.</dd> + * <dt><b>Update</b></dt> + * <dd>The profile Contact has the same update restrictions as Contacts in general, + * but requires the android.permission.WRITE_PROFILE permission.</dd> + * <dt><b>Delete</b></dt> + * <dd>The profile Contact cannot be explicitly deleted. It will be removed + * automatically if all of its constituent raw contact entries are deleted.</dd> + * <dt><b>Query</b></dt> + * <dd> + * <ul> + * <li>The {@link #CONTENT_URI} for profiles behaves in much the same way as + * retrieving a contact by ID, except that it will only ever return the user's + * profile contact. + * </li> + * <li> + * The profile contact supports all of the same sub-paths as an individual contact + * does - the content of the profile contact can be retrieved as entities or + * data rows. Similarly, specific raw contact entries can be retrieved by appending + * the desired raw contact ID within the profile. + * </li> + * </ul> + * </dd> + * </dl> + */ + public static final class Profile implements BaseColumns, ContactsColumns, + ContactOptionsColumns, ContactNameColumns, ContactStatusColumns { + /** + * This utility class cannot be instantiated + */ + private Profile() { + } + + /** + * The content:// style URI for this table, which requests the contact entry + * representing the user's personal profile data. + */ + public static final Uri CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI, "profile"); + + /** + * {@link Uri} for referencing the user's profile {@link Contacts} entry, + * Provides {@link OpenableColumns} columns when queried, or returns the + * user's profile contact formatted as a vCard when opened through + * {@link ContentResolver#openAssetFileDescriptor(Uri, String)}. + */ + public static final Uri CONTENT_VCARD_URI = Uri.withAppendedPath(CONTENT_URI, + "as_vcard"); + + /** + * {@link Uri} for referencing the raw contacts that make up the user's profile + * {@link Contacts} entry. An individual raw contact entry within the profile + * can be addressed by appending the raw contact ID. The entities or data within + * that specific raw contact can be requested by appending the entity or data + * path as well. + */ + public static final Uri CONTENT_RAW_CONTACTS_URI = Uri.withAppendedPath(CONTENT_URI, + "raw_contacts"); + } + protected interface RawContactsColumns { /** * A reference to the {@link ContactsContract.Contacts#_ID} that this @@ -1806,6 +1905,12 @@ public final class ContactsContract { * <P>Type: INTEGER</P> */ public static final String RAW_CONTACT_IS_READ_ONLY = "raw_contact_is_read_only"; + + /** + * Flag that reflects whether this raw contact belongs to the user's + * personal profile entry. + */ + public static final String RAW_CONTACT_IS_USER_PROFILE = "raw_contact_is_user_profile"; } /** @@ -6156,6 +6261,95 @@ public final class ContactsContract { } /** + * <p> + * API allowing applications to send usage information for each {@link Data} row to the + * Contacts Provider. + * </p> + * <p> + * With the feedback, Contacts Provider may return more contextually appropriate results for + * Data listing, typically supplied with + * {@link ContactsContract.Contacts#CONTENT_FILTER_URI}, + * {@link ContactsContract.CommonDataKinds.Email#CONTENT_FILTER_URI}, + * {@link ContactsContract.CommonDataKinds.Phone#CONTENT_FILTER_URI}, and users can benefit + * from better ranked (sorted) lists in applications that show auto-complete list. + * </p> + * <p> + * There is no guarantee for how this feedback is used, or even whether it is used at all. + * The ranking algorithm will make best efforts to use the feedback data, but the exact + * implementation, the storage data structures as well as the resulting sort order is device + * and version specific and can change over time. + * </p> + * <p> + * When updating usage information, users of this API need to use + * {@link ContentResolver#update(Uri, ContentValues, String, String[])} with a Uri constructed + * from {@link DataUsageFeedback#FEEDBACK_URI}. The Uri must contain one or more data id(s) as + * its last path. They also need to append a query parameter to the Uri, to specify the type of + * the communication, which enables the Contacts Provider to differentiate between kinds of + * interactions using the same contact data field (for example a phone number can be used to + * make phone calls or send SMS). + * </p> + * <p> + * Selection and selectionArgs are ignored and must be set to null. To get data ids, + * you may need to call {@link ContentResolver#query(Uri, String[], String, String[], String)} + * toward {@link Data#CONTENT_URI}. + * </p> + * <p> + * {@link ContentResolver#update(Uri, ContentValues, String, String[])} returns a positive + * integer when successful, and returns 0 if no contact with that id was found. + * </p> + * <p> + * Example: + * <pre> + * Uri uri = DataUsageFeedback.UPDATE_URI.buildUpon() + * .appendPath(TextUtils.join(",", dataIds)) + * .appendQueryParameter(DataUsageFeedback.METHOD, DataUsageFeedback.METHOD_CALL) + * .build(); + * boolean successful = resolver.update(uri, new ContentValues(), null, null) > 0; + * </pre> + * </p> + * @hide + */ + public static final class DataUsageFeedback { + + /** + * The content:// style URI for sending usage feedback. + * Must be used with {@link ContentResolver#update(Uri, ContentValues, String, String[])}. + */ + public static final Uri FEEDBACK_URI = + Uri.withAppendedPath(Data.CONTENT_URI, "usagefeedback"); + + /** + * <p> + * Name for query parameter specifying the type of data usage. + * </p> + */ + public static final String USAGE_TYPE = "type"; + + /** + * <p> + * Type of usage for voice interaction, which includes phone call, voice chat, and + * video chat. + * </p> + */ + public static final String USAGE_TYPE_CALL = "call"; + + /** + * <p> + * Type of usage for text interaction involving longer messages, which includes email. + * </p> + */ + public static final String USAGE_TYPE_LONG_TEXT = "long_text"; + + /** + * <p> + * Type of usage for text interaction involving shorter messages, which includes SMS, + * text chat with email addresses. + * </p> + */ + public static final String USAGE_TYPE_SHORT_TEXT = "short_text"; + } + + /** * Helper methods to display QuickContact dialogs that allow users to pivot on * a specific {@link Contacts} entry. */ diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java index 91a72a50c23a..6585e8201d9a 100644 --- a/core/java/android/provider/Telephony.java +++ b/core/java/android/provider/Telephony.java @@ -547,7 +547,7 @@ public final class Telephony { * values:</p> * * <ul> - * <li><em>pdus</em> - An Object[] od byte[]s containing the PDUs + * <li><em>pdus</em> - An Object[] of byte[]s containing the PDUs * that make up the message.</li> * </ul> * @@ -591,6 +591,46 @@ public final class Telephony { "android.provider.Telephony.WAP_PUSH_RECEIVED"; /** + * Broadcast Action: A new Cell Broadcast message has been received + * by the device. The intent will have the following extra + * values:</p> + * + * <ul> + * <li><em>pdus</em> - An Object[] of byte[]s containing the PDUs + * that make up the message.</li> + * </ul> + * + * <p>The extra values can be extracted using + * {@link #getMessagesFromIntent(Intent)}.</p> + * + * <p>If a BroadcastReceiver encounters an error while processing + * this intent it should set the result code appropriately.</p> + */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String SMS_CB_RECEIVED_ACTION = + "android.provider.Telephony.SMS_CB_RECEIVED"; + + /** + * Broadcast Action: A new Emergency Broadcast message has been received + * by the device. The intent will have the following extra + * values:</p> + * + * <ul> + * <li><em>pdus</em> - An Object[] of byte[]s containing the PDUs + * that make up the message.</li> + * </ul> + * + * <p>The extra values can be extracted using + * {@link #getMessagesFromIntent(Intent)}.</p> + * + * <p>If a BroadcastReceiver encounters an error while processing + * this intent it should set the result code appropriately.</p> + */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String SMS_EMERGENCY_CB_RECEIVED_ACTION = + "android.provider.Telephony.SMS_EMERGENCY_CB_RECEIVED"; + + /** * Broadcast Action: The SIM storage for SMS messages is full. If * space is not freed, messages targeted for the SIM (class 2) may * not be saved. @@ -623,7 +663,7 @@ public final class Telephony { * @param intent the intent to read from * @return an array of SmsMessages for the PDUs */ - public static final SmsMessage[] getMessagesFromIntent( + public static SmsMessage[] getMessagesFromIntent( Intent intent) { Object[] messages = (Object[]) intent.getSerializableExtra("pdus"); byte[][] pduObjs = new byte[messages.length][]; diff --git a/core/java/android/provider/VoicemailContract.java b/core/java/android/provider/VoicemailContract.java new file mode 100644 index 000000000000..c397af9ca601 --- /dev/null +++ b/core/java/android/provider/VoicemailContract.java @@ -0,0 +1,139 @@ +/* + * 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 android.provider; + +import android.content.Intent; +import android.database.ContentObserver; +import android.net.Uri; +import android.provider.CallLog.Calls; +/** + * The contract between the voicemail provider and applications. Contains + * definitions for the supported URIs and columns. + * + * <P>Voicemails are inserted by what is called as a "voicemail source" + * application, which is responsible for syncing voicemail data between a remote + * server and the local voicemail content provider. "voicemail source" + * application should use the source specific {@link #CONTENT_URI_SOURCE} URI + * to insert and retrieve voicemails. + * + * <P>In addition to the {@link ContentObserver} notifications the voicemail + * provider also generates broadcast intents to notify change for applications + * that are not active and therefore cannot listen to ContentObserver + * notifications. Broadcast intents with following actions are generated: + * <ul> + * <li> {@link #ACTION_NEW_VOICEMAIL} is generated for each new voicemail + * inserted. + * </li> + * <li> {@link Intent#ACTION_PROVIDER_CHANGED} is generated for any change + * made into the database, including new voicemail. + * </li> + * </ul> + * @hide + */ +// TODO: unhide when the API is approved by android-api-council +public class VoicemailContract { + /** The authority used by the voicemail provider. */ + public static final String AUTHORITY = "com.android.voicemail"; + + /** URI to insert/retrieve all voicemails. */ + public static final Uri CONTENT_URI = + Uri.parse("content://" + AUTHORITY + "/voicemail"); + /** URI to insert/retrieve voicemails by a given voicemai source. */ + public static final Uri CONTENT_URI_SOURCE = + Uri.parse("content://" + AUTHORITY + "/voicemail/source/"); + + // TODO: Move ACTION_NEW_VOICEMAIL to the Intent class. + /** Broadcast intent when a new voicemail record is inserted. */ + public static final String ACTION_NEW_VOICEMAIL = "android.intent.action.NEW_VOICEMAIL"; + /** + * Extra included in {@value Intent#ACTION_PROVIDER_CHANGED} and + * {@value #ACTION_NEW_VOICEMAIL} broadcast intents to indicate the package + * that caused the change in content provider. + * <p>Receivers of the broadcast can use this field to determine if this is + * a self change. + */ + public static final String EXTRA_CHANGED_BY = "com.android.voicemail.extra.CHANGED_BY"; + + /** The mime type for a collection of voicemails. */ + public static final String DIR_TYPE = + "vnd.android.cursor.dir/voicemails"; + + public static final class Voicemails implements BaseColumns { + /** + * Phone number of the voicemail sender. + * <P>Type: TEXT</P> + */ + public static final String NUMBER = Calls.NUMBER; + /** + * The date the voicemail was sent, in milliseconds since the epoch + * <P>Type: INTEGER (long)</P> + */ + public static final String DATE = Calls.DATE; + /** + * The duration of the voicemail in seconds. + * <P>Type: INTEGER (long)</P> + */ + public static final String DURATION = Calls.DURATION; + /** + * Whether this is a new voicemail (i.e. has not been heard). + * <P>Type: INTEGER (boolean)</P> + */ + public static final String NEW = Calls.NEW; + /** + * The mail box state of the voicemail. + * <P> Possible values: {@link #STATE_INBOX}, {@link #STATE_DELETED}, + * {@link #STATE_UNDELETED}. + * <P>Type: INTEGER</P> + */ + public static final String STATE = "state"; + /** Value of {@link #STATE} when the voicemail is in inbox. */ + public static int STATE_INBOX = 0; + /** Value of {@link #STATE} when the voicemail has been marked as deleted. */ + public static int STATE_DELETED = 1; + /** Value of {@link #STATE} when the voicemail has marked as undeleted. */ + public static int STATE_UNDELETED = 2; + /** + * Package name of the source application that inserted the voicemail. + * <P>Type: TEXT</P> + */ + public static final String SOURCE_PACKAGE = "source_package"; + /** + * Application-specific data available to the source application that + * inserted the voicemail. This is typically used to store the source + * specific message id to identify this voicemail on the remote + * voicemail server. + * <P>Type: TEXT</P> + * <P> Note that this is NOT the voicemail media content data. + */ + public static final String SOURCE_DATA = "provider_data"; + /** + * Whether the media content for this voicemail is available for + * consumption. + * <P>Type: INTEGER (boolean)</P> + */ + public static final String HAS_CONTENT = "has_content"; + /** + * MIME type of the media content for the voicemail. + * <P>Type: TEXT</P> + */ + public static final String MIME_TYPE = "mime_type"; + /** + * Path to the media content file. Internal only field. + * @hide + */ + public static final String _DATA = "_data"; + } +} diff --git a/core/java/android/security/package.html b/core/java/android/security/package.html deleted file mode 100644 index dfc6303fe4ad..000000000000 --- a/core/java/android/security/package.html +++ /dev/null @@ -1,6 +0,0 @@ -<HTML> -<BODY> -Utilities for encrypting messages from hash functions. -{@hide} -</BODY> -</HTML> diff --git a/core/java/android/speech/tts/AbstractSynthesisCallback.java b/core/java/android/speech/tts/AbstractSynthesisCallback.java new file mode 100644 index 000000000000..c7a4af0bf533 --- /dev/null +++ b/core/java/android/speech/tts/AbstractSynthesisCallback.java @@ -0,0 +1,34 @@ +/* + * 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 android.speech.tts; + +/** + * Defines additional methods the synthesis callback must implement that + * are private to the TTS service implementation. + */ +abstract class AbstractSynthesisCallback implements SynthesisCallback { + /** + * Checks whether the synthesis request completed successfully. + */ + abstract boolean isDone(); + + /** + * Aborts the speech request. + * + * Can be called from multiple threads. + */ + abstract void stop(); +} diff --git a/core/java/android/speech/tts/AudioMessageParams.java b/core/java/android/speech/tts/AudioMessageParams.java index db4d6226df15..68d8738027a1 100644 --- a/core/java/android/speech/tts/AudioMessageParams.java +++ b/core/java/android/speech/tts/AudioMessageParams.java @@ -20,8 +20,9 @@ import android.speech.tts.TextToSpeechService.UtteranceCompletedDispatcher; class AudioMessageParams extends MessageParams { private final BlockingMediaPlayer mPlayer; - AudioMessageParams(UtteranceCompletedDispatcher dispatcher, BlockingMediaPlayer player) { - super(dispatcher); + AudioMessageParams(UtteranceCompletedDispatcher dispatcher, + String callingApp, BlockingMediaPlayer player) { + super(dispatcher, callingApp); mPlayer = player; } diff --git a/core/java/android/speech/tts/AudioPlaybackHandler.java b/core/java/android/speech/tts/AudioPlaybackHandler.java index 924bbbc05325..a3686b77d1b7 100644 --- a/core/java/android/speech/tts/AudioPlaybackHandler.java +++ b/core/java/android/speech/tts/AudioPlaybackHandler.java @@ -17,13 +17,13 @@ package android.speech.tts; import android.media.AudioFormat; import android.media.AudioTrack; -import android.os.Handler; -import android.os.Looper; -import android.os.Message; -import android.speech.tts.SynthesisMessageParams.ListEntry; import android.util.Log; -class AudioPlaybackHandler extends Handler { +import java.util.Iterator; +import java.util.concurrent.PriorityBlockingQueue; +import java.util.concurrent.atomic.AtomicLong; + +class AudioPlaybackHandler { private static final String TAG = "TTS.AudioPlaybackHandler"; private static final boolean DBG = false; @@ -37,33 +37,28 @@ class AudioPlaybackHandler extends Handler { private static final int PLAY_AUDIO = 5; private static final int PLAY_SILENCE = 6; - // Accessed by multiple threads, synchronized by "this". - private MessageParams mCurrentParams; + private static final int SHUTDOWN = -1; + + private static final int DEFAULT_PRIORITY = 1; + private static final int HIGH_PRIORITY = 0; + + private final PriorityBlockingQueue<ListEntry> mQueue = + new PriorityBlockingQueue<ListEntry>(); + private final Thread mHandlerThread; + + private volatile MessageParams mCurrentParams = null; // Used only for book keeping and error detection. - private SynthesisMessageParams mLastSynthesisRequest; + private volatile SynthesisMessageParams mLastSynthesisRequest = null; + // Used to order incoming messages in our priority queue. + private final AtomicLong mSequenceIdCtr = new AtomicLong(0); - AudioPlaybackHandler(Looper looper) { - super(looper); - } - @Override - public synchronized void handleMessage(Message msg) { - if (msg.what == SYNTHESIS_START) { - mCurrentParams = (SynthesisMessageParams) msg.obj; - handleSynthesisStart(msg); - } else if (msg.what == SYNTHESIS_DATA_AVAILABLE) { - handleSynthesisDataAvailable(msg); - } else if (msg.what == SYNTHESIS_DONE) { - handleSynthesisDone(msg); - } else if (msg.what == SYNTHESIS_COMPLETE_DATA_AVAILABLE) { - handleSynthesisCompleteDataAvailable(msg); - } else if (msg.what == PLAY_AUDIO) { - handleAudio(msg); - } else if (msg.what == PLAY_SILENCE) { - handleSilence(msg); - } + AudioPlaybackHandler() { + mHandlerThread = new Thread(new MessageLoop(), "TTS.AudioPlaybackThread"); + } - mCurrentParams = null; + public void start() { + mHandlerThread.start(); } /** @@ -72,63 +67,228 @@ class AudioPlaybackHandler extends Handler { * that is not guaranteed. */ synchronized public void stop(MessageParams token) { - removeCallbacksAndMessages(token); + if (token == null) { + return; + } + + removeMessages(token); if (token.getType() == MessageParams.TYPE_SYNTHESIS) { - sendMessageAtFrontOfQueue(obtainMessage(SYNTHESIS_DONE, token)); - } else if (token == mCurrentParams) { - if (token.getType() == MessageParams.TYPE_AUDIO) { - ((AudioMessageParams) mCurrentParams).getPlayer().stop(); - } else if (token.getType() == MessageParams.TYPE_SILENCE) { - ((SilenceMessageParams) mCurrentParams).getConditionVariable().open(); + mQueue.add(new ListEntry(SYNTHESIS_DONE, token, HIGH_PRIORITY)); + } else { + final MessageParams current = getCurrentParams(); + + if (current != null) { + if (token.getType() == MessageParams.TYPE_AUDIO) { + ((AudioMessageParams) current).getPlayer().stop(); + } else if (token.getType() == MessageParams.TYPE_SILENCE) { + ((SilenceMessageParams) current).getConditionVariable().open(); + } } } } + synchronized public void removePlaybackItems(String callingApp) { + removeMessages(callingApp); + stop(getCurrentParams()); + } + + synchronized public void removeAllItems() { + removeAllMessages(); + stop(getCurrentParams()); + } + /** * Shut down the audio playback thread. */ synchronized public void quit() { - if (mCurrentParams != null) { - stop(mCurrentParams); - } - getLooper().quit(); + stop(getCurrentParams()); + mQueue.add(new ListEntry(SHUTDOWN, null, HIGH_PRIORITY)); } void enqueueSynthesisStart(SynthesisMessageParams token) { - sendMessage(obtainMessage(SYNTHESIS_START, token)); + mQueue.add(new ListEntry(SYNTHESIS_START, token)); } void enqueueSynthesisDataAvailable(SynthesisMessageParams token) { - sendMessage(obtainMessage(SYNTHESIS_DATA_AVAILABLE, token)); + mQueue.add(new ListEntry(SYNTHESIS_DATA_AVAILABLE, token)); } void enqueueSynthesisCompleteDataAvailable(SynthesisMessageParams token) { - sendMessage(obtainMessage(SYNTHESIS_COMPLETE_DATA_AVAILABLE, token)); + mQueue.add(new ListEntry(SYNTHESIS_COMPLETE_DATA_AVAILABLE, token)); } void enqueueSynthesisDone(SynthesisMessageParams token) { - sendMessage(obtainMessage(SYNTHESIS_DONE, token)); + mQueue.add(new ListEntry(SYNTHESIS_DONE, token)); } void enqueueAudio(AudioMessageParams token) { - sendMessage(obtainMessage(PLAY_AUDIO, token)); + mQueue.add(new ListEntry(PLAY_AUDIO, token)); } void enqueueSilence(SilenceMessageParams token) { - sendMessage(obtainMessage(PLAY_SILENCE, token)); + mQueue.add(new ListEntry(PLAY_SILENCE, token)); } // ----------------------------------------- // End of public API methods. // ----------------------------------------- + // ----------------------------------------- + // Methods for managing the message queue. + // ----------------------------------------- + + /* + * The MessageLoop is a handler like implementation that + * processes messages from a priority queue. + */ + private final class MessageLoop implements Runnable { + @Override + public void run() { + while (true) { + ListEntry entry = null; + try { + entry = mQueue.take(); + } catch (InterruptedException ie) { + return; + } + + if (entry.mWhat == SHUTDOWN) { + if (DBG) Log.d(TAG, "MessageLoop : Shutting down"); + return; + } + + if (DBG) { + Log.d(TAG, "MessageLoop : Handling message :" + entry.mWhat + + " ,seqId : " + entry.mSequenceId); + } + + setCurrentParams(entry.mMessage); + handleMessage(entry); + setCurrentParams(null); + } + } + } + + /* + * Remove all messages from the queue that contain the supplied token. + * Note that the Iterator is thread safe, and other methods can safely + * continue adding to the queue at this point. + */ + synchronized private void removeMessages(MessageParams token) { + if (token == null) { + return; + } + + Iterator<ListEntry> it = mQueue.iterator(); + + while (it.hasNext()) { + final ListEntry current = it.next(); + if (current.mMessage == token) { + it.remove(); + } + } + } + + /* + * Atomically clear the queue of all messages. + */ + synchronized private void removeAllMessages() { + mQueue.clear(); + } + + /* + * Remove all messages that originate from a given calling app. + */ + synchronized private void removeMessages(String callingApp) { + Iterator<ListEntry> it = mQueue.iterator(); + + while (it.hasNext()) { + final ListEntry current = it.next(); + // The null check is to prevent us from removing control messages, + // such as a shutdown message. + if (current.mMessage != null && + callingApp.equals(current.mMessage.getCallingApp())) { + it.remove(); + } + } + } + + /* + * An element of our priority queue of messages. Each message has a priority, + * and a sequence id (defined by the order of enqueue calls). Among messages + * with the same priority, messages that were received earlier win out. + */ + private final class ListEntry implements Comparable<ListEntry> { + final int mWhat; + final MessageParams mMessage; + final int mPriority; + final long mSequenceId; + + private ListEntry(int what, MessageParams message) { + this(what, message, DEFAULT_PRIORITY); + } + + private ListEntry(int what, MessageParams message, int priority) { + mWhat = what; + mMessage = message; + mPriority = priority; + mSequenceId = mSequenceIdCtr.incrementAndGet(); + } + + @Override + public int compareTo(ListEntry that) { + if (that == this) { + return 0; + } + + // Note that this is always 0, 1 or -1. + int priorityDiff = mPriority - that.mPriority; + if (priorityDiff == 0) { + // The == case cannot occur. + return (mSequenceId < that.mSequenceId) ? -1 : 1; + } + + return priorityDiff; + } + } + + private void setCurrentParams(MessageParams p) { + mCurrentParams = p; + } + + private MessageParams getCurrentParams() { + return mCurrentParams; + } + + // ----------------------------------------- + // Methods for dealing with individual messages, the methods + // below do the actual work. + // ----------------------------------------- + + private void handleMessage(ListEntry entry) { + final MessageParams msg = entry.mMessage; + if (entry.mWhat == SYNTHESIS_START) { + handleSynthesisStart(msg); + } else if (entry.mWhat == SYNTHESIS_DATA_AVAILABLE) { + handleSynthesisDataAvailable(msg); + } else if (entry.mWhat == SYNTHESIS_DONE) { + handleSynthesisDone(msg); + } else if (entry.mWhat == SYNTHESIS_COMPLETE_DATA_AVAILABLE) { + handleSynthesisCompleteDataAvailable(msg); + } else if (entry.mWhat == PLAY_AUDIO) { + handleAudio(msg); + } else if (entry.mWhat == PLAY_SILENCE) { + handleSilence(msg); + } + } + // Currently implemented as blocking the audio playback thread for the // specified duration. If a call to stop() is made, the thread // unblocks. - private void handleSilence(Message msg) { + private void handleSilence(MessageParams msg) { if (DBG) Log.d(TAG, "handleSilence()"); - SilenceMessageParams params = (SilenceMessageParams) msg.obj; + SilenceMessageParams params = (SilenceMessageParams) msg; if (params.getSilenceDurationMs() > 0) { params.getConditionVariable().block(params.getSilenceDurationMs()); } @@ -137,9 +297,9 @@ class AudioPlaybackHandler extends Handler { } // Plays back audio from a given URI. No TTS engine involvement here. - private void handleAudio(Message msg) { + private void handleAudio(MessageParams msg) { if (DBG) Log.d(TAG, "handleAudio()"); - AudioMessageParams params = (AudioMessageParams) msg.obj; + AudioMessageParams params = (AudioMessageParams) msg; // Note that the BlockingMediaPlayer spawns a separate thread. // // TODO: This can be avoided. @@ -157,9 +317,9 @@ class AudioPlaybackHandler extends Handler { // handleSynthesisStart -> handleSynthesisDataAvailable(*) -> handleSynthesisDone // OR // handleSynthesisCompleteDataAvailable. - private void handleSynthesisStart(Message msg) { + private void handleSynthesisStart(MessageParams msg) { if (DBG) Log.d(TAG, "handleSynthesisStart()"); - final SynthesisMessageParams param = (SynthesisMessageParams) msg.obj; + final SynthesisMessageParams param = (SynthesisMessageParams) msg; // Oops, looks like the engine forgot to call done(). We go through // extra trouble to clean the data to prevent the AudioTrack resources @@ -177,12 +337,14 @@ class AudioPlaybackHandler extends Handler { param.mStreamType, param.mSampleRateInHz, param.mAudioFormat, param.mChannelCount, param.mVolume, param.mPan); + if (DBG) Log.d(TAG, "Created audio track [" + audioTrack.hashCode() + "]"); + param.setAudioTrack(audioTrack); } // More data available to be flushed to the audio track. - private void handleSynthesisDataAvailable(Message msg) { - final SynthesisMessageParams param = (SynthesisMessageParams) msg.obj; + private void handleSynthesisDataAvailable(MessageParams msg) { + final SynthesisMessageParams param = (SynthesisMessageParams) msg; if (param.getAudioTrack() == null) { Log.w(TAG, "Error : null audio track in handleDataAvailable."); return; @@ -194,7 +356,7 @@ class AudioPlaybackHandler extends Handler { } final AudioTrack audioTrack = param.getAudioTrack(); - final ListEntry bufferCopy = param.getNextBuffer(); + final SynthesisMessageParams.ListEntry bufferCopy = param.getNextBuffer(); if (bufferCopy == null) { Log.e(TAG, "No buffers available to play."); @@ -218,8 +380,8 @@ class AudioPlaybackHandler extends Handler { } } - private void handleSynthesisDone(Message msg) { - final SynthesisMessageParams params = (SynthesisMessageParams) msg.obj; + private void handleSynthesisDone(MessageParams msg) { + final SynthesisMessageParams params = (SynthesisMessageParams) msg; handleSynthesisDone(params); } @@ -233,6 +395,7 @@ class AudioPlaybackHandler extends Handler { if (audioTrack != null) { audioTrack.flush(); audioTrack.stop(); + if (DBG) Log.d(TAG, "Releasing audio track [" + audioTrack.hashCode() + "]"); audioTrack.release(); } } finally { @@ -242,8 +405,8 @@ class AudioPlaybackHandler extends Handler { } } - private void handleSynthesisCompleteDataAvailable(Message msg) { - final SynthesisMessageParams params = (SynthesisMessageParams) msg.obj; + private void handleSynthesisCompleteDataAvailable(MessageParams msg) { + final SynthesisMessageParams params = (SynthesisMessageParams) msg; if (DBG) Log.d(TAG, "completeAudioAvailable(" + params + ")"); // Channel config and bytes per frame are checked before @@ -251,7 +414,7 @@ class AudioPlaybackHandler extends Handler { int channelConfig = AudioPlaybackHandler.getChannelConfig(params.mChannelCount); int bytesPerFrame = AudioPlaybackHandler.getBytesPerFrame(params.mAudioFormat); - ListEntry entry = params.getNextBuffer(); + SynthesisMessageParams.ListEntry entry = params.getNextBuffer(); if (entry == null) { Log.w(TAG, "completeDataAvailable : No buffers available to play."); diff --git a/core/java/android/speech/tts/FileSynthesisRequest.java b/core/java/android/speech/tts/FileSynthesisCallback.java index 62be2bf7ca4b..4f4b3fb6f203 100644 --- a/core/java/android/speech/tts/FileSynthesisRequest.java +++ b/core/java/android/speech/tts/FileSynthesisCallback.java @@ -16,7 +16,6 @@ package android.speech.tts; import android.media.AudioFormat; -import android.os.Bundle; import android.util.Log; import java.io.File; @@ -29,7 +28,7 @@ import java.nio.ByteOrder; /** * Speech synthesis request that writes the audio to a WAV file. */ -class FileSynthesisRequest extends SynthesisRequest { +class FileSynthesisCallback extends AbstractSynthesisCallback { private static final String TAG = "FileSynthesisRequest"; private static final boolean DBG = false; @@ -48,8 +47,7 @@ class FileSynthesisRequest extends SynthesisRequest { private boolean mStopped = false; private boolean mDone = false; - FileSynthesisRequest(String text, Bundle params, File fileName) { - super(text, params); + FileSynthesisCallback(File fileName) { mFileName = fileName; } diff --git a/core/java/android/speech/tts/MessageParams.java b/core/java/android/speech/tts/MessageParams.java index 2d96df43b957..4c1b6d2bcf33 100644 --- a/core/java/android/speech/tts/MessageParams.java +++ b/core/java/android/speech/tts/MessageParams.java @@ -18,19 +18,25 @@ package android.speech.tts; import android.speech.tts.TextToSpeechService.UtteranceCompletedDispatcher; abstract class MessageParams { - private final UtteranceCompletedDispatcher mDispatcher; - static final int TYPE_SYNTHESIS = 1; static final int TYPE_AUDIO = 2; static final int TYPE_SILENCE = 3; - MessageParams(UtteranceCompletedDispatcher dispatcher) { + private final UtteranceCompletedDispatcher mDispatcher; + private final String mCallingApp; + + MessageParams(UtteranceCompletedDispatcher dispatcher, String callingApp) { mDispatcher = dispatcher; + mCallingApp = callingApp; } UtteranceCompletedDispatcher getDispatcher() { return mDispatcher; } + String getCallingApp() { + return mCallingApp; + } + abstract int getType(); } diff --git a/core/java/android/speech/tts/PlaybackSynthesisRequest.java b/core/java/android/speech/tts/PlaybackSynthesisCallback.java index 34b263cb74ef..bdaa1b825350 100644 --- a/core/java/android/speech/tts/PlaybackSynthesisRequest.java +++ b/core/java/android/speech/tts/PlaybackSynthesisCallback.java @@ -15,14 +15,13 @@ */ package android.speech.tts; -import android.os.Bundle; import android.speech.tts.TextToSpeechService.UtteranceCompletedDispatcher; import android.util.Log; /** * Speech synthesis request that plays the audio as it is received. */ -class PlaybackSynthesisRequest extends SynthesisRequest { +class PlaybackSynthesisCallback extends AbstractSynthesisCallback { private static final String TAG = "PlaybackSynthesisRequest"; private static final boolean DBG = false; @@ -65,15 +64,17 @@ class PlaybackSynthesisRequest extends SynthesisRequest { private volatile boolean mDone = false; private final UtteranceCompletedDispatcher mDispatcher; + private final String mCallingApp; - PlaybackSynthesisRequest(String text, Bundle params, int streamType, float volume, float pan, - AudioPlaybackHandler audioTrackHandler, UtteranceCompletedDispatcher dispatcher) { - super(text, params); + PlaybackSynthesisCallback(int streamType, float volume, float pan, + AudioPlaybackHandler audioTrackHandler, UtteranceCompletedDispatcher dispatcher, + String callingApp) { mStreamType = streamType; mVolume = volume; mPan = pan; mAudioTrackHandler = audioTrackHandler; mDispatcher = dispatcher; + mCallingApp = callingApp; } @Override @@ -123,7 +124,7 @@ class PlaybackSynthesisRequest extends SynthesisRequest { } SynthesisMessageParams params = new SynthesisMessageParams( mStreamType, sampleRateInHz, audioFormat, channelCount, mVolume, mPan, - mDispatcher); + mDispatcher, mCallingApp); mAudioTrackHandler.enqueueSynthesisStart(params); mToken = params; @@ -207,7 +208,7 @@ class PlaybackSynthesisRequest extends SynthesisRequest { } SynthesisMessageParams params = new SynthesisMessageParams( mStreamType, sampleRateInHz, audioFormat, channelCount, mVolume, mPan, - mDispatcher); + mDispatcher, mCallingApp); params.addBuffer(buffer, offset, length); mAudioTrackHandler.enqueueSynthesisCompleteDataAvailable(params); diff --git a/core/java/android/speech/tts/SilenceMessageParams.java b/core/java/android/speech/tts/SilenceMessageParams.java index eee8b6816438..7a4ff1c0cdeb 100644 --- a/core/java/android/speech/tts/SilenceMessageParams.java +++ b/core/java/android/speech/tts/SilenceMessageParams.java @@ -22,8 +22,9 @@ class SilenceMessageParams extends MessageParams { private final ConditionVariable mCondVar = new ConditionVariable(); private final long mSilenceDurationMs; - SilenceMessageParams(UtteranceCompletedDispatcher dispatcher, long silenceDurationMs) { - super(dispatcher); + SilenceMessageParams(UtteranceCompletedDispatcher dispatcher, + String callingApp, long silenceDurationMs) { + super(dispatcher, callingApp); mSilenceDurationMs = silenceDurationMs; } diff --git a/core/java/android/speech/tts/SynthesisCallback.java b/core/java/android/speech/tts/SynthesisCallback.java new file mode 100644 index 000000000000..1b80e40e2582 --- /dev/null +++ b/core/java/android/speech/tts/SynthesisCallback.java @@ -0,0 +1,107 @@ +/* + * 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 android.speech.tts; + +/** + * A callback to return speech data synthesized by a text to speech engine. + * + * The engine can provide streaming audio by calling + * {@link #start}, then {@link #audioAvailable} until all audio has been provided, then finally + * {@link #done}. + * + * Alternatively, the engine can provide all the audio at once, by using + * {@link #completeAudioAvailable}. + * + * {@link #error} can be called at any stage in the synthesis process to + * indicate that an error has occured, but if the call is made after a call + * to {@link #done} or {@link #completeAudioAvailable} it might be discarded. + */ +public interface SynthesisCallback { + /** + * @return the maximum number of bytes that the TTS engine can pass in a single call of + * {@link #audioAvailable}. This does not apply to {@link #completeAudioAvailable}. + * Calls to {@link #audioAvailable} with data lengths larger than this + * value will not succeed. + */ + public int getMaxBufferSize(); + + /** + * The service should call this when it starts to synthesize audio for this + * request. + * + * This method should only be called on the synthesis thread, + * while in {@link TextToSpeechService#onSynthesizeText}. + * + * @param sampleRateInHz Sample rate in HZ of the generated audio. + * @param audioFormat Audio format of the generated audio. Must be one of + * the ENCODING_ constants defined in {@link android.media.AudioFormat}. + * @param channelCount The number of channels. Must be {@code 1} or {@code 2}. + * @return {@link TextToSpeech#SUCCESS} or {@link TextToSpeech#ERROR}. + */ + public int start(int sampleRateInHz, int audioFormat, int channelCount); + + /** + * The service should call this method when synthesized audio is ready for consumption. + * + * This method should only be called on the synthesis thread, + * while in {@link TextToSpeechService#onSynthesizeText}. + * + * @param buffer The generated audio data. This method will not hold on to {@code buffer}, + * so the caller is free to modify it after this method returns. + * @param offset The offset into {@code buffer} where the audio data starts. + * @param length The number of bytes of audio data in {@code buffer}. This must be + * less than or equal to the return value of {@link #getMaxBufferSize}. + * @return {@link TextToSpeech#SUCCESS} or {@link TextToSpeech#ERROR}. + */ + public int audioAvailable(byte[] buffer, int offset, int length); + + /** + * The service can call this method instead of using {@link #start}, {@link #audioAvailable} + * and {@link #done} if all the audio data is available in a single buffer. + * + * @param sampleRateInHz Sample rate in HZ of the generated audio. + * @param audioFormat Audio format of the generated audio. Must be one of + * the ENCODING_ constants defined in {@link android.media.AudioFormat}. + * @param channelCount The number of channels. Must be {@code 1} or {@code 2}. + * @param buffer The generated audio data. This method will not hold on to {@code buffer}, + * so the caller is free to modify it after this method returns. + * @param offset The offset into {@code buffer} where the audio data starts. + * @param length The number of bytes of audio data in {@code buffer}. + * @return {@link TextToSpeech#SUCCESS} or {@link TextToSpeech#ERROR}. + */ + public int completeAudioAvailable(int sampleRateInHz, int audioFormat, + int channelCount, byte[] buffer, int offset, int length); + + /** + * The service should call this method when all the synthesized audio for a request has + * been passed to {@link #audioAvailable}. + * + * This method should only be called on the synthesis thread, + * while in {@link TextToSpeechService#onSynthesizeText}. + * + * @return {@link TextToSpeech#SUCCESS} or {@link TextToSpeech#ERROR}. + */ + public int done(); + + /** + * The service should call this method if the speech synthesis fails. + * + * This method should only be called on the synthesis thread, + * while in {@link TextToSpeechService#onSynthesizeText}. + */ + public void error(); + +}
\ No newline at end of file diff --git a/core/java/android/speech/tts/SynthesisMessageParams.java b/core/java/android/speech/tts/SynthesisMessageParams.java index aabaa5ae5efc..51f3d2e83a5b 100644 --- a/core/java/android/speech/tts/SynthesisMessageParams.java +++ b/core/java/android/speech/tts/SynthesisMessageParams.java @@ -37,8 +37,9 @@ final class SynthesisMessageParams extends MessageParams { SynthesisMessageParams(int streamType, int sampleRate, int audioFormat, int channelCount, - float volume, float pan, UtteranceCompletedDispatcher dispatcher) { - super(dispatcher); + float volume, float pan, UtteranceCompletedDispatcher dispatcher, + String callingApp) { + super(dispatcher, callingApp); mStreamType = streamType; mSampleRateInHz = sampleRate; diff --git a/core/java/android/speech/tts/SynthesisRequest.java b/core/java/android/speech/tts/SynthesisRequest.java index 57ae10d838b4..ef1704cae088 100644 --- a/core/java/android/speech/tts/SynthesisRequest.java +++ b/core/java/android/speech/tts/SynthesisRequest.java @@ -18,17 +18,22 @@ package android.speech.tts; import android.os.Bundle; /** - * A request for speech synthesis given to a TTS engine for processing. + * Contains data required by engines to synthesize speech. This data is : + * <ul> + * <li>The text to synthesize</li> + * <li>The synthesis locale, represented as a language, country and a variant. + * The language is an ISO 639-3 letter language code, and the country is an + * ISO 3166 alpha 3 code. The variant is not specified.</li> + * <li>The synthesis speech rate, with 100 being the normal, and + * higher values representing higher speech rates.</li> + * <li>The voice pitch, with 100 being the default pitch.</li> + * </ul> * - * The engine can provide streaming audio by calling - * {@link #start}, then {@link #audioAvailable} until all audio has been provided, then finally - * {@link #done}. - * - * Alternatively, the engine can provide all the audio at once, by using - * {@link #completeAudioAvailable}. + * Any additional parameters sent to the text to speech service are passed in + * uninterpreted, see the @code{params} argument in {@link TextToSpeech#speak} + * and {@link TextToSpeech#synthesizeToFile}. */ -public abstract class SynthesisRequest { - +public final class SynthesisRequest { private final String mText; private final Bundle mParams; private String mLanguage; @@ -37,35 +42,13 @@ public abstract class SynthesisRequest { private int mSpeechRate; private int mPitch; - public SynthesisRequest(String text, Bundle params) { + SynthesisRequest(String text, Bundle params) { mText = text; + // Makes a copy of params. mParams = new Bundle(params); } /** - * Sets the locale for the request. - */ - void setLanguage(String language, String country, String variant) { - mLanguage = language; - mCountry = country; - mVariant = variant; - } - - /** - * Sets the speech rate. - */ - void setSpeechRate(int speechRate) { - mSpeechRate = speechRate; - } - - /** - * Sets the pitch. - */ - void setPitch(int pitch) { - mPitch = pitch; - } - - /** * Gets the text which should be synthesized. */ public String getText() { @@ -115,86 +98,25 @@ public abstract class SynthesisRequest { } /** - * Gets the maximum number of bytes that the TTS engine can pass in a single call of - * {@link #audioAvailable}. This does not apply to {@link #completeAudioAvailable}. - */ - public abstract int getMaxBufferSize(); - - /** - * Checks whether the synthesis request completed successfully. - */ - abstract boolean isDone(); - - /** - * Aborts the speech request. - * - * Can be called from multiple threads. - */ - abstract void stop(); - - /** - * The service should call this when it starts to synthesize audio for this - * request. - * - * This method should only be called on the synthesis thread, - * while in {@link TextToSpeechService#onSynthesizeText}. - * - * @param sampleRateInHz Sample rate in HZ of the generated audio. - * @param audioFormat Audio format of the generated audio. Must be one of - * the ENCODING_ constants defined in {@link android.media.AudioFormat}. - * @param channelCount The number of channels. Must be {@code 1} or {@code 2}. - * @return {@link TextToSpeech#SUCCESS} or {@link TextToSpeech#ERROR}. - */ - public abstract int start(int sampleRateInHz, int audioFormat, int channelCount); - - /** - * The service should call this method when synthesized audio is ready for consumption. - * - * This method should only be called on the synthesis thread, - * while in {@link TextToSpeechService#onSynthesizeText}. - * - * @param buffer The generated audio data. This method will not hold on to {@code buffer}, - * so the caller is free to modify it after this method returns. - * @param offset The offset into {@code buffer} where the audio data starts. - * @param length The number of bytes of audio data in {@code buffer}. This must be - * less than or equal to the return value of {@link #getMaxBufferSize}. - * @return {@link TextToSpeech#SUCCESS} or {@link TextToSpeech#ERROR}. - */ - public abstract int audioAvailable(byte[] buffer, int offset, int length); - - /** - * The service should call this method when all the synthesized audio for a request has - * been passed to {@link #audioAvailable}. - * - * This method should only be called on the synthesis thread, - * while in {@link TextToSpeechService#onSynthesizeText}. - * - * @return {@link TextToSpeech#SUCCESS} or {@link TextToSpeech#ERROR}. + * Sets the locale for the request. */ - public abstract int done(); + void setLanguage(String language, String country, String variant) { + mLanguage = language; + mCountry = country; + mVariant = variant; + } /** - * The service should call this method if the speech synthesis fails. - * - * This method should only be called on the synthesis thread, - * while in {@link TextToSpeechService#onSynthesizeText}. + * Sets the speech rate. */ - public abstract void error(); + void setSpeechRate(int speechRate) { + mSpeechRate = speechRate; + } /** - * The service can call this method instead of using {@link #start}, {@link #audioAvailable} - * and {@link #done} if all the audio data is available in a single buffer. - * - * @param sampleRateInHz Sample rate in HZ of the generated audio. - * @param audioFormat Audio format of the generated audio. Must be one of - * the ENCODING_ constants defined in {@link android.media.AudioFormat}. - * @param channelCount The number of channels. Must be {@code 1} or {@code 2}. - * @param buffer The generated audio data. This method will not hold on to {@code buffer}, - * so the caller is free to modify it after this method returns. - * @param offset The offset into {@code buffer} where the audio data starts. - * @param length The number of bytes of audio data in {@code buffer}. - * @return {@link TextToSpeech#SUCCESS} or {@link TextToSpeech#ERROR}. + * Sets the pitch. */ - public abstract int completeAudioAvailable(int sampleRateInHz, int audioFormat, - int channelCount, byte[] buffer, int offset, int length); -}
\ No newline at end of file + void setPitch(int pitch) { + mPitch = pitch; + } +} diff --git a/core/java/android/speech/tts/TextToSpeech.java b/core/java/android/speech/tts/TextToSpeech.java index 4b194692f195..23fd96fbdd70 100755 --- a/core/java/android/speech/tts/TextToSpeech.java +++ b/core/java/android/speech/tts/TextToSpeech.java @@ -22,9 +22,6 @@ import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; -import android.content.pm.PackageManager; -import android.content.pm.ResolveInfo; -import android.content.pm.ServiceInfo; import android.media.AudioManager; import android.net.Uri; import android.os.Bundle; @@ -34,8 +31,6 @@ import android.provider.Settings; import android.text.TextUtils; import android.util.Log; -import java.util.ArrayList; -import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Locale; @@ -67,12 +62,22 @@ public class TextToSpeech { /** * Queue mode where all entries in the playback queue (media to be played * and text to be synthesized) are dropped and replaced by the new entry. + * Queues are flushed with respect to a given calling app. Entries in the queue + * from other callees are not discarded. */ public static final int QUEUE_FLUSH = 0; /** * Queue mode where the new entry is added at the end of the playback queue. */ public static final int QUEUE_ADD = 1; + /** + * Queue mode where the entire playback queue is purged. This is different + * from {@link #QUEUE_FLUSH} in that all entries are purged, not just entries + * from a given caller. + * + * @hide + */ + static final int QUEUE_DESTROY = 2; /** * Denotes the language is available exactly as specified by the locale. @@ -174,10 +179,14 @@ public class TextToSpeech { /** * Package name of the default TTS engine. * - * TODO: This should come from a system property - * * @hide + * @deprecated No longer in use, the default engine is determined by + * the sort order defined in {@link EngineInfoComparator}. Note that + * this doesn't "break" anything because there is no guarantee that + * the engine specified below is installed on a given build, let + * alone be the default. */ + @Deprecated public static final String DEFAULT_ENGINE = "com.svox.pico"; /** @@ -424,6 +433,7 @@ public class TextToSpeech { private final Map<String, Uri> mEarcons; private final Map<String, Uri> mUtterances; private final Bundle mParams = new Bundle(); + private final TtsEngines mEnginesHelper; private String mCurrentEngine = null; /** @@ -459,6 +469,7 @@ public class TextToSpeech { mEarcons = new HashMap<String, Uri>(); mUtterances = new HashMap<String, Uri>(); + mEnginesHelper = new TtsEngines(mContext); initTts(); } @@ -488,7 +499,7 @@ public class TextToSpeech { String defaultEngine = getDefaultEngine(); String engine = defaultEngine; if (!areDefaultsEnforced() && !TextUtils.isEmpty(mRequestedEngine) - && isEngineEnabled(engine)) { + && mEnginesHelper.isEngineEnabled(engine)) { engine = mRequestedEngine; } @@ -504,10 +515,11 @@ public class TextToSpeech { } } + final String highestRanked = mEnginesHelper.getHighestRankedEngineName(); // Fall back to the hardcoded default if different from the two above - if (!defaultEngine.equals(Engine.DEFAULT_ENGINE) - && !engine.equals(Engine.DEFAULT_ENGINE)) { - if (connectToEngine(Engine.DEFAULT_ENGINE)) { + if (!defaultEngine.equals(highestRanked) + && !engine.equals(highestRanked)) { + if (connectToEngine(highestRanked)) { return SUCCESS; } } @@ -1055,12 +1067,11 @@ public class TextToSpeech { /** * Gets the package name of the default speech synthesis engine. * - * @return Package name of the TTS engine that the user has chosen as their default. + * @return Package name of the TTS engine that the user has chosen + * as their default. */ public String getDefaultEngine() { - String engine = Settings.Secure.getString(mContext.getContentResolver(), - Settings.Secure.TTS_DEFAULT_SYNTH); - return engine != null ? engine : Engine.DEFAULT_ENGINE; + return mEnginesHelper.getDefaultEngine(); } /** @@ -1072,55 +1083,16 @@ public class TextToSpeech { Settings.Secure.TTS_USE_DEFAULTS, Engine.USE_DEFAULTS) == 1; } - private boolean isEngineEnabled(String engine) { - if (Engine.DEFAULT_ENGINE.equals(engine)) { - return true; - } - for (String enabled : getEnabledEngines()) { - if (engine.equals(enabled)) { - return true; - } - } - return false; - } - - private String[] getEnabledEngines() { - String str = Settings.Secure.getString(mContext.getContentResolver(), - Settings.Secure.TTS_ENABLED_PLUGINS); - if (TextUtils.isEmpty(str)) { - return new String[0]; - } - return str.split(" "); - } - /** * Gets a list of all installed TTS engines. * - * @return A list of engine info objects. The list can be empty, but will never by {@code null}. + * @return A list of engine info objects. The list can be empty, but never {@code null}. */ public List<EngineInfo> getEngines() { - PackageManager pm = mContext.getPackageManager(); - Intent intent = new Intent(Engine.INTENT_ACTION_TTS_SERVICE); - List<ResolveInfo> resolveInfos = - pm.queryIntentServices(intent, PackageManager.MATCH_DEFAULT_ONLY); - if (resolveInfos == null) return Collections.emptyList(); - List<EngineInfo> engines = new ArrayList<EngineInfo>(resolveInfos.size()); - for (ResolveInfo resolveInfo : resolveInfos) { - ServiceInfo service = resolveInfo.serviceInfo; - if (service != null) { - EngineInfo engine = new EngineInfo(); - // Using just the package name isn't great, since it disallows having - // multiple engines in the same package, but that's what the existing API does. - engine.name = service.packageName; - CharSequence label = service.loadLabel(pm); - engine.label = TextUtils.isEmpty(label) ? engine.name : label.toString(); - engine.icon = service.getIconResource(); - engines.add(engine); - } - } - return engines; + return mEnginesHelper.getEngines(); } + private class Connection implements ServiceConnection { private ITextToSpeechService mService; @@ -1193,6 +1165,20 @@ public class TextToSpeech { * Icon for the engine. */ public int icon; + /** + * Whether this engine is a part of the system + * image. + * + * @hide + */ + public boolean system; + /** + * The priority the engine declares for the the intent filter + * {@code android.intent.action.TTS_SERVICE} + * + * @hide + */ + public int priority; @Override public String toString() { @@ -1200,4 +1186,5 @@ public class TextToSpeech { } } + } diff --git a/core/java/android/speech/tts/TextToSpeechService.java b/core/java/android/speech/tts/TextToSpeechService.java index e553f7735b35..3eea6b7ac683 100644 --- a/core/java/android/speech/tts/TextToSpeechService.java +++ b/core/java/android/speech/tts/TextToSpeechService.java @@ -19,7 +19,6 @@ import android.app.Service; import android.content.Intent; import android.net.Uri; import android.os.Bundle; -import android.os.ConditionVariable; import android.os.Handler; import android.os.HandlerThread; import android.os.IBinder; @@ -40,8 +39,34 @@ import java.util.Locale; /** - * Abstract base class for TTS engine implementations. + * Abstract base class for TTS engine implementations. The following methods + * need to be implemented. + * + * <ul> + * <li>{@link #onIsLanguageAvailable}</li> + * <li>{@link #onLoadLanguage}</li> + * <li>{@link #onGetLanguage}</li> + * <li>{@link #onSynthesizeText}</li> + * <li>{@link #onStop}</li> + * </ul> + * + * The first three deal primarily with language management, and are used to + * query the engine for it's support for a given language and indicate to it + * that requests in a given language are imminent. + * + * {@link #onSynthesizeText} is central to the engine implementation. The + * implementation should synthesize text as per the request parameters and + * return synthesized data via the supplied callback. This class and its helpers + * will then consume that data, which might mean queueing it for playback or writing + * it to a file or similar. All calls to this method will be on a single + * thread, which will be different from the main thread of the service. Synthesis + * must be synchronous which means the engine must NOT hold on the callback or call + * any methods on it after the method returns + * + * {@link #onStop} tells the engine that it should stop all ongoing synthesis, if + * any. Any pending data from the current synthesis will be discarded. */ +// TODO: Add a link to the sample TTS engine once it's done. public abstract class TextToSpeechService extends Service { private static final boolean DBG = false; @@ -69,9 +94,8 @@ public abstract class TextToSpeechService extends Service { synthThread.start(); mSynthHandler = new SynthHandler(synthThread.getLooper()); - HandlerThread audioTrackThread = new HandlerThread("TTS.audioTrackThread"); - audioTrackThread.start(); - mAudioPlaybackHandler = new AudioPlaybackHandler(audioTrackThread.getLooper()); + mAudioPlaybackHandler = new AudioPlaybackHandler(); + mAudioPlaybackHandler.start(); mCallbacks = new CallbackMap(); @@ -160,10 +184,12 @@ public abstract class TextToSpeechService extends Service { * * Called on the synthesis thread. * - * @param request The synthesis request. The method should use the methods in the request - * object to communicate the results of the synthesis. + * @param request The synthesis request. + * @param callback The callback the the engine must use to make data available for + * playback or for writing to a file. */ - protected abstract void onSynthesizeText(SynthesisRequest request); + protected abstract void onSynthesizeText(SynthesisRequest request, + SynthesisCallback callback); private boolean areDefaultsEnforced() { return getSecureSettingInt(Settings.Secure.TTS_USE_DEFAULTS, @@ -272,11 +298,16 @@ public abstract class TextToSpeechService extends Service { if (!speechItem.isValid()) { return TextToSpeech.ERROR; } - // TODO: The old code also supported the undocumented queueMode == 2, - // which clears out all pending items from the calling app, as well as all - // non-file items from other apps. + if (queueMode == TextToSpeech.QUEUE_FLUSH) { stop(speechItem.getCallingApp()); + } else if (queueMode == TextToSpeech.QUEUE_DESTROY) { + // Stop the current speech item. + stop(speechItem.getCallingApp()); + // Remove all other items from the queue. + removeCallbacksAndMessages(null); + // Remove all pending playback as well. + mAudioPlaybackHandler.removeAllItems(); } Runnable runnable = new Runnable() { @Override @@ -288,6 +319,8 @@ public abstract class TextToSpeechService extends Service { }; Message msg = Message.obtain(this, runnable); // The obj is used to remove all callbacks from the given app in stop(String). + // + // Note that this string is interned, so the == comparison works. msg.obj = speechItem.getCallingApp(); if (sendMessage(msg)) { return TextToSpeech.SUCCESS; @@ -307,12 +340,16 @@ public abstract class TextToSpeechService extends Service { if (TextUtils.isEmpty(callingApp)) { return TextToSpeech.ERROR; } + removeCallbacksAndMessages(callingApp); SpeechItem current = setCurrentSpeechItem(null); if (current != null && TextUtils.equals(callingApp, current.getCallingApp())) { current.stop(); } + // Remove any enqueued audio too. + mAudioPlaybackHandler.removePlaybackItems(callingApp); + return TextToSpeech.SUCCESS; } } @@ -421,11 +458,16 @@ public abstract class TextToSpeechService extends Service { class SynthesisSpeechItem extends SpeechItem { private final String mText; - private SynthesisRequest mSynthesisRequest; + private final SynthesisRequest mSynthesisRequest; + // Non null after synthesis has started, and all accesses + // guarded by 'this'. + private AbstractSynthesisCallback mSynthesisCallback; public SynthesisSpeechItem(String callingApp, Bundle params, String text) { super(callingApp, params); mText = text; + mSynthesisRequest = new SynthesisRequest(mText, mParams); + setRequestParams(mSynthesisRequest); } public String getText() { @@ -447,20 +489,18 @@ public abstract class TextToSpeechService extends Service { @Override protected int playImpl() { - SynthesisRequest synthesisRequest; + AbstractSynthesisCallback synthesisCallback; synchronized (this) { - mSynthesisRequest = createSynthesisRequest(); - synthesisRequest = mSynthesisRequest; + mSynthesisCallback = createSynthesisCallback(); + synthesisCallback = mSynthesisCallback; } - setRequestParams(synthesisRequest); - TextToSpeechService.this.onSynthesizeText(synthesisRequest); - return synthesisRequest.isDone() ? TextToSpeech.SUCCESS : TextToSpeech.ERROR; + TextToSpeechService.this.onSynthesizeText(mSynthesisRequest, synthesisCallback); + return synthesisCallback.isDone() ? TextToSpeech.SUCCESS : TextToSpeech.ERROR; } - protected SynthesisRequest createSynthesisRequest() { - return new PlaybackSynthesisRequest(mText, mParams, - getStreamType(), getVolume(), getPan(), mAudioPlaybackHandler, - this); + protected AbstractSynthesisCallback createSynthesisCallback() { + return new PlaybackSynthesisCallback(getStreamType(), getVolume(), getPan(), + mAudioPlaybackHandler, this, getCallingApp()); } private void setRequestParams(SynthesisRequest request) { @@ -476,11 +516,11 @@ public abstract class TextToSpeechService extends Service { @Override protected void stopImpl() { - SynthesisRequest synthesisRequest; + AbstractSynthesisCallback synthesisCallback; synchronized (this) { - synthesisRequest = mSynthesisRequest; + synthesisCallback = mSynthesisCallback; } - synthesisRequest.stop(); + synthesisCallback.stop(); TextToSpeechService.this.onStop(); } @@ -529,8 +569,8 @@ public abstract class TextToSpeechService extends Service { } @Override - protected SynthesisRequest createSynthesisRequest() { - return new FileSynthesisRequest(getText(), mParams, mFile); + protected AbstractSynthesisCallback createSynthesisCallback() { + return new FileSynthesisCallback(mFile); } @Override @@ -587,7 +627,7 @@ public abstract class TextToSpeechService extends Service { @Override protected int playImpl() { - mToken = new AudioMessageParams(this, mPlayer); + mToken = new AudioMessageParams(this, getCallingApp(), mPlayer); mAudioPlaybackHandler.enqueueAudio(mToken); return TextToSpeech.SUCCESS; } @@ -616,7 +656,7 @@ public abstract class TextToSpeechService extends Service { @Override protected int playImpl() { - mToken = new SilenceMessageParams(this, mDuration); + mToken = new SilenceMessageParams(this, getCallingApp(), mDuration); mAudioPlaybackHandler.enqueueSilence(mToken); return TextToSpeech.SUCCESS; } @@ -641,27 +681,46 @@ public abstract class TextToSpeechService extends Service { * Binder returned from {@code #onBind(Intent)}. The methods in this class can be * called called from several different threads. */ + // NOTE: All calls that are passed in a calling app are interned so that + // they can be used as message objects (which are tested for equality using ==). private final ITextToSpeechService.Stub mBinder = new ITextToSpeechService.Stub() { public int speak(String callingApp, String text, int queueMode, Bundle params) { - SpeechItem item = new SynthesisSpeechItem(callingApp, params, text); + if (!checkNonNull(callingApp, text, params)) { + return TextToSpeech.ERROR; + } + + SpeechItem item = new SynthesisSpeechItem(intern(callingApp), params, text); return mSynthHandler.enqueueSpeechItem(queueMode, item); } public int synthesizeToFile(String callingApp, String text, String filename, Bundle params) { + if (!checkNonNull(callingApp, text, filename, params)) { + return TextToSpeech.ERROR; + } + File file = new File(filename); - SpeechItem item = new SynthesisToFileSpeechItem(callingApp, params, text, file); + SpeechItem item = new SynthesisToFileSpeechItem(intern(callingApp), + params, text, file); return mSynthHandler.enqueueSpeechItem(TextToSpeech.QUEUE_ADD, item); } public int playAudio(String callingApp, Uri audioUri, int queueMode, Bundle params) { - SpeechItem item = new AudioSpeechItem(callingApp, params, audioUri); + if (!checkNonNull(callingApp, audioUri, params)) { + return TextToSpeech.ERROR; + } + + SpeechItem item = new AudioSpeechItem(intern(callingApp), params, audioUri); return mSynthHandler.enqueueSpeechItem(queueMode, item); } public int playSilence(String callingApp, long duration, int queueMode, Bundle params) { - SpeechItem item = new SilenceSpeechItem(callingApp, params, duration); + if (!checkNonNull(callingApp, params)) { + return TextToSpeech.ERROR; + } + + SpeechItem item = new SilenceSpeechItem(intern(callingApp), params, duration); return mSynthHandler.enqueueSpeechItem(queueMode, item); } @@ -670,7 +729,11 @@ public abstract class TextToSpeechService extends Service { } public int stop(String callingApp) { - return mSynthHandler.stop(callingApp); + if (!checkNonNull(callingApp)) { + return TextToSpeech.ERROR; + } + + return mSynthHandler.stop(intern(callingApp)); } public String[] getLanguage() { @@ -682,6 +745,10 @@ public abstract class TextToSpeechService extends Service { * perhaps the default language selected by the user. */ public int isLanguageAvailable(String lang, String country, String variant) { + if (!checkNonNull(lang)) { + return TextToSpeech.ERROR; + } + if (areDefaultsEnforced()) { if (isDefault(lang, country, variant)) { return mDefaultAvailability; @@ -697,6 +764,10 @@ public abstract class TextToSpeechService extends Service { * are enforced. */ public int loadLanguage(String lang, String country, String variant) { + if (!checkNonNull(lang)) { + return TextToSpeech.ERROR; + } + if (areDefaultsEnforced()) { if (isDefault(lang, country, variant)) { return mDefaultAvailability; @@ -708,12 +779,29 @@ public abstract class TextToSpeechService extends Service { } public void setCallback(String packageName, ITextToSpeechCallback cb) { + // Note that passing in a null callback is a valid use case. + if (!checkNonNull(packageName)) { + return; + } + mCallbacks.setCallback(packageName, cb); } private boolean isDefault(String lang, String country, String variant) { return Locale.getDefault().equals(new Locale(lang, country, variant)); } + + private String intern(String in) { + // The input parameter will be non null. + return in.intern(); + } + + private boolean checkNonNull(Object... args) { + for (Object o : args) { + if (o == null) return false; + } + return true; + } }; private class CallbackMap extends RemoteCallbackList<ITextToSpeechCallback> { diff --git a/core/java/android/speech/tts/TtsEngines.java b/core/java/android/speech/tts/TtsEngines.java new file mode 100644 index 000000000000..e8d74eb32893 --- /dev/null +++ b/core/java/android/speech/tts/TtsEngines.java @@ -0,0 +1,200 @@ +/* + * 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 android.speech.tts; + +import android.content.Context; +import android.content.Intent; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.content.pm.ServiceInfo; +import android.provider.Settings; +import android.speech.tts.TextToSpeech.Engine; +import android.speech.tts.TextToSpeech.EngineInfo; +import android.text.TextUtils; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +/** + * Support class for querying the list of available engines + * on the device and deciding which one to use etc. + * + * Comments in this class the use the shorthand "system engines" for engines that + * are a part of the system image. + * + * @hide + */ +public class TtsEngines { + private final Context mContext; + + public TtsEngines(Context ctx) { + mContext = ctx; + } + + /** + * @return the default TTS engine. If the user has set a default, that + * value is returned else the highest ranked engine is returned, + * as per {@link EngineInfoComparator}. + */ + public String getDefaultEngine() { + String engine = Settings.Secure.getString(mContext.getContentResolver(), + Settings.Secure.TTS_DEFAULT_SYNTH); + return engine != null ? engine : getHighestRankedEngineName(); + } + + /** + * @return the package name of the highest ranked system engine, {@code null} + * if no TTS engines were present in the system image. + */ + public String getHighestRankedEngineName() { + final List<EngineInfo> engines = getEngines(); + + if (engines.size() > 0 && engines.get(0).system) { + return engines.get(0).name; + } + + return null; + } + + /** + * Returns the engine info for a given engine name. Note that engines are + * identified by their package name. + */ + public EngineInfo getEngineInfo(String packageName) { + PackageManager pm = mContext.getPackageManager(); + Intent intent = new Intent(Engine.INTENT_ACTION_TTS_SERVICE); + intent.setPackage(packageName); + List<ResolveInfo> resolveInfos = pm.queryIntentServices(intent, + PackageManager.MATCH_DEFAULT_ONLY); + // Note that the current API allows only one engine per + // package name. Since the "engine name" is the same as + // the package name. + if (resolveInfos != null && resolveInfos.size() == 1) { + return getEngineInfo(resolveInfos.get(0), pm); + } + + return null; + } + + /** + * Gets a list of all installed TTS engines. + * + * @return A list of engine info objects. The list can be empty, but never {@code null}. + */ + public List<EngineInfo> getEngines() { + PackageManager pm = mContext.getPackageManager(); + Intent intent = new Intent(Engine.INTENT_ACTION_TTS_SERVICE); + List<ResolveInfo> resolveInfos = + pm.queryIntentServices(intent, PackageManager.MATCH_DEFAULT_ONLY); + if (resolveInfos == null) return Collections.emptyList(); + + List<EngineInfo> engines = new ArrayList<EngineInfo>(resolveInfos.size()); + + for (ResolveInfo resolveInfo : resolveInfos) { + EngineInfo engine = getEngineInfo(resolveInfo, pm); + if (engine != null) { + engines.add(engine); + } + } + Collections.sort(engines, EngineInfoComparator.INSTANCE); + + return engines; + } + + /** + * Checks whether a given engine is enabled or not. Note that all system + * engines are enabled by default. + */ + public boolean isEngineEnabled(String engine) { + // System engines are enabled by default always. + EngineInfo info = getEngineInfo(engine); + if (info != null && info.system) { + return true; + } + + for (String enabled : getUserEnabledEngines()) { + if (engine.equals(enabled)) { + return true; + } + } + return false; + } + + private boolean isSystemEngine(ServiceInfo info) { + final ApplicationInfo appInfo = info.applicationInfo; + return appInfo != null && (appInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0; + } + + private EngineInfo getEngineInfo(ResolveInfo resolve, PackageManager pm) { + ServiceInfo service = resolve.serviceInfo; + if (service != null) { + EngineInfo engine = new EngineInfo(); + // Using just the package name isn't great, since it disallows having + // multiple engines in the same package, but that's what the existing API does. + engine.name = service.packageName; + CharSequence label = service.loadLabel(pm); + engine.label = TextUtils.isEmpty(label) ? engine.name : label.toString(); + engine.icon = service.getIconResource(); + engine.priority = resolve.priority; + engine.system = isSystemEngine(service); + return engine; + } + + return null; + } + + // Note that in addition to this list, all engines that are a part + // of the system are enabled by default. + private String[] getUserEnabledEngines() { + String str = Settings.Secure.getString(mContext.getContentResolver(), + Settings.Secure.TTS_ENABLED_PLUGINS); + if (TextUtils.isEmpty(str)) { + return new String[0]; + } + return str.split(" "); + } + + private static class EngineInfoComparator implements Comparator<EngineInfo> { + private EngineInfoComparator() { } + + static EngineInfoComparator INSTANCE = new EngineInfoComparator(); + + /** + * Engines that are a part of the system image are always lesser + * than those that are not. Within system engines / non system engines + * the engines are sorted in order of their declared priority. + */ + @Override + public int compare(EngineInfo lhs, EngineInfo rhs) { + if (lhs.system && !rhs.system) { + return -1; + } else if (rhs.system && !lhs.system) { + return 1; + } else { + // Either both system engines, or both non system + // engines. + // + // Note, this isn't a typo. Higher priority numbers imply + // higher priority, but are "lower" in the sort order. + return rhs.priority - lhs.priority; + } + } + } + +} diff --git a/core/java/android/util/CalendarUtils.java b/core/java/android/util/CalendarUtils.java deleted file mode 100644 index b2b48972c508..000000000000 --- a/core/java/android/util/CalendarUtils.java +++ /dev/null @@ -1,348 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.util; - -import android.content.AsyncQueryHandler; -import android.content.ContentResolver; -import android.content.ContentValues; -import android.content.Context; -import android.content.SharedPreferences; -import android.database.Cursor; -import android.provider.Calendar.CalendarCache; -import android.text.TextUtils; -import android.text.format.DateUtils; -import android.text.format.Time; - -import java.util.Formatter; -import java.util.HashSet; -import java.util.Locale; - -/** - * A class containing utility methods related to Calendar apps. - * - * @hide - */ -public class CalendarUtils { - private static final boolean DEBUG = false; - private static final String TAG = "CalendarUtils"; - - /** - * This class contains methods specific to reading and writing time zone - * values. - */ - public static class TimeZoneUtils { - private static final String[] TIMEZONE_TYPE_ARGS = { CalendarCache.TIMEZONE_KEY_TYPE }; - private static final String[] TIMEZONE_INSTANCES_ARGS = - { CalendarCache.TIMEZONE_KEY_INSTANCES }; - - private static StringBuilder mSB = new StringBuilder(50); - private static Formatter mF = new Formatter(mSB, Locale.getDefault()); - private volatile static boolean mFirstTZRequest = true; - private volatile static boolean mTZQueryInProgress = false; - - private volatile static boolean mUseHomeTZ = false; - private volatile static String mHomeTZ = Time.getCurrentTimezone(); - - private static HashSet<Runnable> mTZCallbacks = new HashSet<Runnable>(); - private static int mToken = 1; - private static AsyncTZHandler mHandler; - - // The name of the shared preferences file. This name must be maintained for historical - // reasons, as it's what PreferenceManager assigned the first time the file was created. - private final String mPrefsName; - - /** - * This is the key used for writing whether or not a home time zone should - * be used in the Calendar app to the Calendar Preferences. - */ - public static final String KEY_HOME_TZ_ENABLED = "preferences_home_tz_enabled"; - /** - * This is the key used for writing the time zone that should be used if - * home time zones are enabled for the Calendar app. - */ - public static final String KEY_HOME_TZ = "preferences_home_tz"; - - /** - * This is a helper class for handling the async queries and updates for the - * time zone settings in Calendar. - */ - private class AsyncTZHandler extends AsyncQueryHandler { - public AsyncTZHandler(ContentResolver cr) { - super(cr); - } - - @Override - protected void onQueryComplete(int token, Object cookie, Cursor cursor) { - synchronized (mTZCallbacks) { - if (cursor == null) { - mTZQueryInProgress = false; - mFirstTZRequest = true; - return; - } - - boolean writePrefs = false; - // Check the values in the db - int keyColumn = cursor.getColumnIndexOrThrow(CalendarCache.KEY); - int valueColumn = cursor.getColumnIndexOrThrow(CalendarCache.VALUE); - while(cursor.moveToNext()) { - String key = cursor.getString(keyColumn); - String value = cursor.getString(valueColumn); - if (TextUtils.equals(key, CalendarCache.TIMEZONE_KEY_TYPE)) { - boolean useHomeTZ = !TextUtils.equals( - value, CalendarCache.TIMEZONE_TYPE_AUTO); - if (useHomeTZ != mUseHomeTZ) { - writePrefs = true; - mUseHomeTZ = useHomeTZ; - } - } else if (TextUtils.equals( - key, CalendarCache.TIMEZONE_KEY_INSTANCES_PREVIOUS)) { - if (!TextUtils.isEmpty(value) && !TextUtils.equals(mHomeTZ, value)) { - writePrefs = true; - mHomeTZ = value; - } - } - } - cursor.close(); - if (writePrefs) { - SharedPreferences prefs = getSharedPreferences((Context)cookie, mPrefsName); - // Write the prefs - setSharedPreference(prefs, KEY_HOME_TZ_ENABLED, mUseHomeTZ); - setSharedPreference(prefs, KEY_HOME_TZ, mHomeTZ); - } - - mTZQueryInProgress = false; - for (Runnable callback : mTZCallbacks) { - if (callback != null) { - callback.run(); - } - } - mTZCallbacks.clear(); - } - } - } - - /** - * The name of the file where the shared prefs for Calendar are stored - * must be provided. All activities within an app should provide the - * same preferences name or behavior may become erratic. - * - * @param prefsName - */ - public TimeZoneUtils(String prefsName) { - mPrefsName = prefsName; - } - - /** - * Formats a date or a time range according to the local conventions. - * - * This formats a date/time range using Calendar's time zone and the - * local conventions for the region of the device. - * - * If the {@link DateUtils#FORMAT_UTC} flag is used it will pass in - * the UTC time zone instead. - * - * @param context the context is required only if the time is shown - * @param startMillis the start time in UTC milliseconds - * @param endMillis the end time in UTC milliseconds - * @param flags a bit mask of options See - * {@link DateUtils#formatDateRange(Context, Formatter, long, long, int, String) formatDateRange} - * @return a string containing the formatted date/time range. - */ - public String formatDateRange(Context context, long startMillis, - long endMillis, int flags) { - String date; - String tz; - if ((flags & DateUtils.FORMAT_UTC) != 0) { - tz = Time.TIMEZONE_UTC; - } else { - tz = getTimeZone(context, null); - } - synchronized (mSB) { - mSB.setLength(0); - date = DateUtils.formatDateRange(context, mF, startMillis, endMillis, flags, - tz).toString(); - } - return date; - } - - /** - * Writes a new home time zone to the db. - * - * Updates the home time zone in the db asynchronously and updates - * the local cache. Sending a time zone of - * {@link CalendarCache#TIMEZONE_TYPE_AUTO} will cause it to be set - * to the device's time zone. null or empty tz will be ignored. - * - * @param context The calling activity - * @param timeZone The time zone to set Calendar to, or - * {@link CalendarCache#TIMEZONE_TYPE_AUTO} - */ - public void setTimeZone(Context context, String timeZone) { - if (TextUtils.isEmpty(timeZone)) { - if (DEBUG) { - Log.d(TAG, "Empty time zone, nothing to be done."); - } - return; - } - boolean updatePrefs = false; - synchronized (mTZCallbacks) { - if (CalendarCache.TIMEZONE_TYPE_AUTO.equals(timeZone)) { - if (mUseHomeTZ) { - updatePrefs = true; - } - mUseHomeTZ = false; - } else { - if (!mUseHomeTZ || !TextUtils.equals(mHomeTZ, timeZone)) { - updatePrefs = true; - } - mUseHomeTZ = true; - mHomeTZ = timeZone; - } - } - if (updatePrefs) { - // Write the prefs - SharedPreferences prefs = getSharedPreferences(context, mPrefsName); - setSharedPreference(prefs, KEY_HOME_TZ_ENABLED, mUseHomeTZ); - setSharedPreference(prefs, KEY_HOME_TZ, mHomeTZ); - - // Update the db - ContentValues values = new ContentValues(); - if (mHandler != null) { - mHandler.cancelOperation(mToken); - } - - mHandler = new AsyncTZHandler(context.getContentResolver()); - - // skip 0 so query can use it - if (++mToken == 0) { - mToken = 1; - } - - // Write the use home tz setting - values.put(CalendarCache.VALUE, mUseHomeTZ ? CalendarCache.TIMEZONE_TYPE_HOME - : CalendarCache.TIMEZONE_TYPE_AUTO); - mHandler.startUpdate(mToken, null, CalendarCache.URI, values, CalendarCache.WHERE, - TIMEZONE_TYPE_ARGS); - - // If using a home tz write it to the db - if (mUseHomeTZ) { - ContentValues values2 = new ContentValues(); - values2.put(CalendarCache.VALUE, mHomeTZ); - mHandler.startUpdate(mToken, null, CalendarCache.URI, values2, - CalendarCache.WHERE, TIMEZONE_INSTANCES_ARGS); - } - } - } - - /** - * Gets the time zone that Calendar should be displayed in - * - * This is a helper method to get the appropriate time zone for Calendar. If this - * is the first time this method has been called it will initiate an asynchronous - * query to verify that the data in preferences is correct. The callback supplied - * will only be called if this query returns a value other than what is stored in - * preferences and should cause the calling activity to refresh anything that - * depends on calling this method. - * - * @param context The calling activity - * @param callback The runnable that should execute if a query returns new values - * @return The string value representing the time zone Calendar should display - */ - public String getTimeZone(Context context, Runnable callback) { - synchronized (mTZCallbacks){ - if (mFirstTZRequest) { - mTZQueryInProgress = true; - mFirstTZRequest = false; - - SharedPreferences prefs = getSharedPreferences(context, mPrefsName); - mUseHomeTZ = prefs.getBoolean(KEY_HOME_TZ_ENABLED, false); - mHomeTZ = prefs.getString(KEY_HOME_TZ, Time.getCurrentTimezone()); - - // When the async query returns it should synchronize on - // mTZCallbacks, update mUseHomeTZ, mHomeTZ, and the - // preferences, set mTZQueryInProgress to false, and call all - // the runnables in mTZCallbacks. - if (mHandler == null) { - mHandler = new AsyncTZHandler(context.getContentResolver()); - } - mHandler.startQuery(0, context, CalendarCache.URI, CalendarCache.POJECTION, - null, null, null); - } - if (mTZQueryInProgress) { - mTZCallbacks.add(callback); - } - } - return mUseHomeTZ ? mHomeTZ : Time.getCurrentTimezone(); - } - - /** - * Forces a query of the database to check for changes to the time zone. - * This should be called if another app may have modified the db. If a - * query is already in progress the callback will be added to the list - * of callbacks to be called when it returns. - * - * @param context The calling activity - * @param callback The runnable that should execute if a query returns - * new values - */ - public void forceDBRequery(Context context, Runnable callback) { - synchronized (mTZCallbacks){ - if (mTZQueryInProgress) { - mTZCallbacks.add(callback); - return; - } - mFirstTZRequest = true; - getTimeZone(context, callback); - } - } - } - - /** - * A helper method for writing a String value to the preferences - * asynchronously. - * - * @param context A context with access to the correct preferences - * @param key The preference to write to - * @param value The value to write - */ - public static void setSharedPreference(SharedPreferences prefs, String key, String value) { -// SharedPreferences prefs = getSharedPreferences(context); - SharedPreferences.Editor editor = prefs.edit(); - editor.putString(key, value); - editor.apply(); - } - - /** - * A helper method for writing a boolean value to the preferences - * asynchronously. - * - * @param context A context with access to the correct preferences - * @param key The preference to write to - * @param value The value to write - */ - public static void setSharedPreference(SharedPreferences prefs, String key, boolean value) { -// SharedPreferences prefs = getSharedPreferences(context, prefsName); - SharedPreferences.Editor editor = prefs.edit(); - editor.putBoolean(key, value); - editor.apply(); - } - - /** Return a properly configured SharedPreferences instance */ - public static SharedPreferences getSharedPreferences(Context context, String prefsName) { - return context.getSharedPreferences(prefsName, Context.MODE_PRIVATE); - } -} diff --git a/core/java/android/util/Property.java b/core/java/android/util/Property.java index 458e4c37b690..146db80b83fb 100644 --- a/core/java/android/util/Property.java +++ b/core/java/android/util/Property.java @@ -78,11 +78,11 @@ public abstract class Property<T, V> { /** * Sets the value on <code>object</code> which this property represents. If the method is unable - * to set the value on the target object, it will throw a {@link NoSuchPropertyException} + * to set the value on the target object it will throw an {@link UnsupportedOperationException} * exception. */ public void set(T object, V value) { - throw new NoSuchPropertyException("Property is read-only; set() is not implemented"); + throw new UnsupportedOperationException("Property " + getName() +" is read-only"); } /** diff --git a/core/java/android/util/ReflectiveProperty.java b/core/java/android/util/ReflectiveProperty.java index 7bd7428e9da8..6832240f385b 100644 --- a/core/java/android/util/ReflectiveProperty.java +++ b/core/java/android/util/ReflectiveProperty.java @@ -128,7 +128,7 @@ class ReflectiveProperty<T, V> extends Property<T, V> { throw new AssertionError(); } } else { - throw new NoSuchPropertyException("Property is read-only; set() is not implemented"); + throw new UnsupportedOperationException("Property " + getName() +" is read-only"); } } diff --git a/core/java/android/view/CompatibilityInfoHolder.java b/core/java/android/view/CompatibilityInfoHolder.java new file mode 100644 index 000000000000..fc8d6841ac8f --- /dev/null +++ b/core/java/android/view/CompatibilityInfoHolder.java @@ -0,0 +1,45 @@ +/* + * 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 android.view; + +import android.content.res.CompatibilityInfo; + +/** @hide */ +public class CompatibilityInfoHolder { + private volatile CompatibilityInfo mCompatInfo = CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO; + + public void set(CompatibilityInfo compatInfo) { + if (compatInfo != null && (compatInfo.isScalingRequired() + || !compatInfo.supportsScreen())) { + mCompatInfo = compatInfo; + } else { + mCompatInfo = CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO; + } + } + + public CompatibilityInfo get() { + return mCompatInfo; + } + + public CompatibilityInfo getIfNeeded() { + CompatibilityInfo ci = mCompatInfo; + if (ci == null || ci == CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO) { + return null; + } + return ci; + } +} diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java index 80325463545f..3fa8dfdb7c53 100644 --- a/core/java/android/view/Display.java +++ b/core/java/android/view/Display.java @@ -26,6 +26,9 @@ import android.util.DisplayMetrics; import android.util.Slog; public class Display { + static final String TAG = "Display"; + static final boolean DEBUG_COMPAT = false; + /** * Specify the default Display */ @@ -38,7 +41,7 @@ public class Display { * Display gives you access to some information about a particular display * connected to the device. */ - Display(int display, CompatibilityInfo compatInfo) { + Display(int display, CompatibilityInfoHolder compatInfo) { // initalize the statics when this class is first instansiated. This is // done here instead of in the static block because Zygote synchronized (sStaticInit) { @@ -47,14 +50,19 @@ public class Display { sInitialized = true; } } + mCompatibilityInfo = compatInfo != null ? compatInfo : new CompatibilityInfoHolder(); + mDisplay = display; + init(display); + } + + /** @hide */ + public static void setCompatibilityInfo(CompatibilityInfo compatInfo) { if (compatInfo != null && (compatInfo.isScalingRequired() || !compatInfo.supportsScreen())) { - mCompatibilityInfo = compatInfo; + sCompatibilityInfo = compatInfo; } else { - mCompatibilityInfo = null; + sCompatibilityInfo = null; } - mDisplay = display; - init(display); } /** @@ -96,12 +104,13 @@ public class Display { IWindowManager wm = getWindowManager(); if (wm != null) { wm.getDisplaySize(outSize); - if (doCompat && mCompatibilityInfo != null) { + CompatibilityInfo ci; + if (doCompat && (ci=mCompatibilityInfo.getIfNeeded()) != null) { synchronized (mTmpMetrics) { mTmpMetrics.unscaledWidthPixels = outSize.x; mTmpMetrics.unscaledHeightPixels = outSize.y; mTmpMetrics.density = mDensity; - mCompatibilityInfo.applyToDisplayMetrics(mTmpMetrics); + ci.applyToDisplayMetrics(mTmpMetrics); outSize.x = mTmpMetrics.widthPixels; outSize.y = mTmpMetrics.heightPixels; } @@ -111,6 +120,7 @@ public class Display { // system process before the window manager is up. outSize.y = getRealHeight(); } + if (DEBUG_COMPAT && doCompat) Slog.v(TAG, "Returning display size: " + outSize); } catch (RemoteException e) { Slog.w("Display", "Unable to get display size", e); } @@ -236,9 +246,13 @@ public class Display { } getNonSizeMetrics(outMetrics); - if (mCompatibilityInfo != null) { - mCompatibilityInfo.applyToDisplayMetrics(outMetrics); + CompatibilityInfo ci = mCompatibilityInfo.getIfNeeded(); + if (ci != null) { + ci.applyToDisplayMetrics(outMetrics); } + + if (DEBUG_COMPAT) Slog.v(TAG, "Returning DisplayMetrics: " + outMetrics.widthPixels + + "x" + outMetrics.heightPixels + " " + outMetrics.density); } /** @@ -282,7 +296,7 @@ public class Display { private native void init(int display); - private final CompatibilityInfo mCompatibilityInfo; + private final CompatibilityInfoHolder mCompatibilityInfo; private final int mDisplay; // Following fields are initialized from native code private int mPixelFormat; @@ -299,11 +313,13 @@ public class Display { private static boolean sInitialized = false; private static IWindowManager sWindowManager; + private static volatile CompatibilityInfo sCompatibilityInfo; + /** * Returns a display object which uses the metric's width/height instead. * @hide */ - public static Display createCompatibleDisplay(int displayId, CompatibilityInfo compat) { + public static Display createCompatibleDisplay(int displayId, CompatibilityInfoHolder compat) { return new Display(displayId, compat); } } diff --git a/core/java/android/view/GestureDetector.java b/core/java/android/view/GestureDetector.java index 1ccc66fdf63e..a496a9ea0c8c 100644 --- a/core/java/android/view/GestureDetector.java +++ b/core/java/android/view/GestureDetector.java @@ -610,6 +610,8 @@ public class GestureDetector { mVelocityTracker = null; mIsDoubleTapping = false; mStillDown = false; + mAlwaysInTapRegion = false; + mAlwaysInBiggerTapRegion = false; if (mInLongPress) { mInLongPress = false; } diff --git a/core/java/android/view/ScaleGestureDetector.java b/core/java/android/view/ScaleGestureDetector.java index 5e07e1a7c86d..5d2c1a713036 100644 --- a/core/java/android/view/ScaleGestureDetector.java +++ b/core/java/android/view/ScaleGestureDetector.java @@ -340,6 +340,15 @@ public class ScaleGestureDetector { // Set focus point to the remaining finger final int index = event.findPointerIndex(actionId == mActiveId0 ? mActiveId1 : mActiveId0); + if (index < 0) { + mInvalidGesture = true; + Log.e(TAG, "Invalid MotionEvent stream detected.", new Throwable()); + if (mGestureInProgress) { + mListener.onScaleEnd(this); + } + return false; + } + mActiveId0 = event.getPointerId(index); mActive0MostRecent = true; diff --git a/core/java/android/view/TextureView.java b/core/java/android/view/TextureView.java index 755ecf5a2c46..bc1ad3c8e92c 100644 --- a/core/java/android/view/TextureView.java +++ b/core/java/android/view/TextureView.java @@ -56,14 +56,7 @@ import android.util.Log; * setContentView(mTextureView); * } * - * protected void onDestroy() { - * super.onDestroy(); - * - * mCamera.stopPreview(); - * mCamera.release(); - * } - * - * public void onSurfaceTextureAvailable(SurfaceTexture surface) { + * public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) { * mCamera = Camera.open(); * * try { @@ -77,6 +70,11 @@ import android.util.Log; * public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) { * // Ignored, Camera does all the work for us * } + * + * public void onSurfaceTextureDestroyed(SurfaceTexture surface) { + * mCamera.stopPreview(); + * mCamera.release(); + * } * } * </pre> * @@ -155,6 +153,21 @@ public class TextureView extends View { } } + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + + if (isHardwareAccelerated() && mLayer != null) { + if (mListener != null) { + mListener.onSurfaceTextureDestroyed(mSurface); + } + + mLayer.destroy(); + mSurface = null; + mLayer = null; + } + } + /** * The layer type of a TextureView is ignored since a TextureView is always * considered to act as a hardware layer. The optional paint supplied to this @@ -217,6 +230,9 @@ public class TextureView extends View { super.onSizeChanged(w, h, oldw, oldh); if (mSurface != null) { nSetDefaultBufferSize(mSurface.mSurfaceTexture, getWidth(), getHeight()); + if (mListener != null) { + mListener.onSurfaceTextureSizeChanged(mSurface, getWidth(), getHeight()); + } } } @@ -242,7 +258,7 @@ public class TextureView extends View { mSurface.setOnFrameAvailableListener(mUpdateListener); if (mListener != null) { - mListener.onSurfaceTextureAvailable(mSurface); + mListener.onSurfaceTextureAvailable(mSurface, getWidth(), getHeight()); } } @@ -316,8 +332,10 @@ public class TextureView extends View { * * @param surface The surface returned by * {@link android.view.TextureView#getSurfaceTexture()} + * @param width The width of the surface + * @param height The height of the surface */ - public void onSurfaceTextureAvailable(SurfaceTexture surface); + public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height); /** * Invoked when the {@link SurfaceTexture}'s buffers size changed. @@ -328,6 +346,15 @@ public class TextureView extends View { * @param height The new height of the surface */ public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height); + + /** + * Invoked when the specified {@link SurfaceTexture} is about to be destroyed. + * After this method is invoked, no rendering should happen inside the surface + * texture. + * + * @param surface The surface about to be destroyed + */ + public void onSurfaceTextureDestroyed(SurfaceTexture surface); } private static native void nSetDefaultBufferSize(int surfaceTexture, int width, int height); diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 74926bb76ce0..441cdc14db8a 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -76,6 +76,7 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Arrays; +import java.util.Locale; import java.util.WeakHashMap; import java.util.concurrent.CopyOnWriteArrayList; @@ -8665,7 +8666,7 @@ public class View implements Drawable.Callback2, KeyEvent.Callback, Accessibilit /** * Resolving the layout direction. LTR is set initially. - * We are supposing here that the parent directionality will be resolved before its children + * We are supposing here that the parent directionality will be resolved before its children. */ private void resolveLayoutDirection() { mPrivateFlags2 &= ~RESOLVED_LAYOUT_RTL; @@ -8680,6 +8681,34 @@ public class View implements Drawable.Callback2, KeyEvent.Callback, Accessibilit case LAYOUT_DIRECTION_RTL: mPrivateFlags2 |= RESOLVED_LAYOUT_RTL; break; + case LAYOUT_DIRECTION_LOCALE: + if(isLayoutDirectionRtl(Locale.getDefault())) { + mPrivateFlags2 |= RESOLVED_LAYOUT_RTL; + } + break; + default: + // Nothing to do, LTR by default + } + } + + /** + * Check if a Locale is corresponding to a RTL script. + * + * @param locale Locale to check + * @return true if a Locale is corresponding to a RTL script. + */ + private static boolean isLayoutDirectionRtl(Locale locale) { + if (locale == null || locale.equals(Locale.ROOT)) return false; + // Be careful: this code will need to be changed when vertical scripts will be supported + // OR if ICU4C is updated to have the "likelySubtags" file + switch(Character.getDirectionality(locale.getDisplayName(locale).charAt(0))) { + case Character.DIRECTIONALITY_LEFT_TO_RIGHT: + return false; + case Character.DIRECTIONALITY_RIGHT_TO_LEFT: + case Character.DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC: + return true; + default: + return false; } } @@ -9176,7 +9205,7 @@ public class View implements Drawable.Callback2, KeyEvent.Callback, Accessibilit mLocalDirtyRect.setEmpty(); } - Canvas currentCanvas = mAttachInfo.mHardwareCanvas; + HardwareCanvas currentCanvas = mAttachInfo.mHardwareCanvas; final HardwareCanvas canvas = mHardwareLayer.start(currentCanvas); mAttachInfo.mHardwareCanvas = canvas; try { @@ -13054,7 +13083,7 @@ public class View implements Drawable.Callback2, KeyEvent.Callback, Accessibilit final Callbacks mRootCallbacks; - Canvas mHardwareCanvas; + HardwareCanvas mHardwareCanvas; /** * The top view of the hierarchy. diff --git a/core/java/android/view/ViewAncestor.java b/core/java/android/view/ViewAncestor.java index da26aba93421..17d745485130 100644 --- a/core/java/android/view/ViewAncestor.java +++ b/core/java/android/view/ViewAncestor.java @@ -46,6 +46,7 @@ import android.os.ParcelFileDescriptor; import android.os.Process; import android.os.RemoteException; import android.os.SystemClock; +import android.os.SystemProperties; import android.util.AndroidRuntimeException; import android.util.DisplayMetrics; import android.util.EventLog; @@ -107,6 +108,12 @@ public final class ViewAncestor extends Handler implements ViewParent, private static final boolean DEBUG_CONFIGURATION = false || LOCAL_LOGV; private static final boolean WATCH_POINTER = false; + /** + * Set this system property to true to force the view hierarchy to render + * at 60 Hz. This can be used to measure the potential framerate. + */ + private static final String PROPERTY_PROFILE_RENDERING = "viewancestor.profile_rendering"; + private static final boolean MEASURE_LATENCY = false; private static LatencyTimer lt; @@ -128,7 +135,7 @@ public final class ViewAncestor extends Handler implements ViewParent, static final ArrayList<ComponentCallbacks> sConfigCallbacks = new ArrayList<ComponentCallbacks>(); - + long mLastTrackballTime = 0; final TrackballAxis mTrackballAxisX = new TrackballAxis(); final TrackballAxis mTrackballAxisY = new TrackballAxis(); @@ -164,6 +171,8 @@ public final class ViewAncestor extends Handler implements ViewParent, // so the window should no longer be active. boolean mStopped = false; + boolean mLastInCompatMode = false; + SurfaceHolder.Callback2 mSurfaceHolderCallback; BaseSurfaceHolder mSurfaceHolder; boolean mIsCreating; @@ -211,6 +220,8 @@ public final class ViewAncestor extends Handler implements ViewParent, boolean mAdded; boolean mAddedTouchMode; + CompatibilityInfoHolder mCompatibilityInfo; + /*package*/ int mAddNesting; // These are accessed by multiple threads. @@ -223,7 +234,7 @@ public final class ViewAncestor extends Handler implements ViewParent, final Configuration mLastConfiguration = new Configuration(); final Configuration mPendingConfiguration = new Configuration(); - + class ResizedInfo { Rect coveredInsets; Rect visibleInsets; @@ -250,6 +261,10 @@ public final class ViewAncestor extends Handler implements ViewParent, volatile Object mLocalDragState; final PointF mDragPoint = new PointF(); final PointF mLastTouchPoint = new PointF(); + + private boolean mProfileRendering; + private Thread mRenderProfiler; + private volatile boolean mRenderProfilingEnabled; /** * see {@link #playSoundEffect(int)} @@ -325,6 +340,8 @@ public final class ViewAncestor extends Handler implements ViewParent, mViewConfiguration = ViewConfiguration.get(context); mDensity = context.getResources().getDisplayMetrics().densityDpi; mFallbackEventHandler = PolicyManager.makeNewFallbackEventHandler(context); + mProfileRendering = Boolean.parseBoolean( + SystemProperties.get(PROPERTY_PROFILE_RENDERING, "false")); } public static void addFirstDrawHandler(Runnable callback) { @@ -395,8 +412,7 @@ public final class ViewAncestor extends Handler implements ViewParent, enableHardwareAcceleration(attrs); } - Resources resources = mView.getContext().getResources(); - CompatibilityInfo compatibilityInfo = resources.getCompatibilityInfo(); + CompatibilityInfo compatibilityInfo = mCompatibilityInfo.get(); mTranslator = compatibilityInfo.getTranslator(); if (mTranslator != null) { @@ -413,6 +429,7 @@ public final class ViewAncestor extends Handler implements ViewParent, if (!compatibilityInfo.supportsScreen()) { attrs.flags |= WindowManager.LayoutParams.FLAG_COMPATIBLE_WINDOW; + mLastInCompatMode = true; } mSoftInputMode = attrs.softInputMode; @@ -783,6 +800,19 @@ public final class ViewAncestor extends Handler implements ViewParent, surfaceChanged = true; params = lp; } + CompatibilityInfo compatibilityInfo = mCompatibilityInfo.get(); + if (compatibilityInfo.supportsScreen() == mLastInCompatMode) { + params = lp; + fullRedrawNeeded = true; + mLayoutRequested = true; + if (mLastInCompatMode) { + params.flags &= ~WindowManager.LayoutParams.FLAG_COMPATIBLE_WINDOW; + mLastInCompatMode = false; + } else { + params.flags |= WindowManager.LayoutParams.FLAG_COMPATIBLE_WINDOW; + mLastInCompatMode = true; + } + } Rect frame = mWinFrame; if (mFirst) { fullRedrawNeeded = true; @@ -1595,11 +1625,45 @@ public final class ViewAncestor extends Handler implements ViewParent, */ void outputDisplayList(View view) { if (mAttachInfo != null && mAttachInfo.mHardwareCanvas != null) { - - HardwareCanvas canvas = (HardwareCanvas) mAttachInfo.mHardwareCanvas; DisplayList displayList = view.getDisplayList(); if (displayList != null) { - canvas.outputDisplayList(displayList); + mAttachInfo.mHardwareCanvas.outputDisplayList(displayList); + } + } + } + + /** + * @see #PROPERTY_PROFILE_RENDERING + */ + private void profileRendering(boolean enabled) { + if (mProfileRendering) { + mRenderProfilingEnabled = enabled; + if (mRenderProfiler == null) { + mRenderProfiler = new Thread(new Runnable() { + @Override + public void run() { + Log.d(TAG, "Starting profiling thread"); + while (mRenderProfilingEnabled) { + mAttachInfo.mHandler.post(new Runnable() { + @Override + public void run() { + mDirty.set(0, 0, mWidth, mHeight); + scheduleTraversals(); + } + }); + try { + // TODO: This should use vsync when we get an API + Thread.sleep(15); + } catch (InterruptedException e) { + Log.d(TAG, "Exiting profiling thread"); + } + } + } + }, "Rendering Profiler"); + mRenderProfiler.start(); + } else { + mRenderProfiler.interrupt(); + mRenderProfiler = null; } } } @@ -1619,7 +1683,7 @@ public final class ViewAncestor extends Handler implements ViewParent, } } } - + scrollToRectOrFocus(null, false); if (mAttachInfo.mViewScrollChanged) { @@ -2057,6 +2121,13 @@ public final class ViewAncestor extends Handler implements ViewParent, "Applying new config to window " + mWindowAttributes.getTitle() + ": " + config); + + CompatibilityInfo ci = mCompatibilityInfo.getIfNeeded(); + if (ci != null) { + config = new Configuration(config); + ci.applyToConfiguration(config); + } + synchronized (sConfigCallbacks) { for (int i=sConfigCallbacks.size()-1; i>=0; i--) { sConfigCallbacks.get(i).onConfigurationChanged(config); @@ -2116,10 +2187,11 @@ public final class ViewAncestor extends Handler implements ViewParent, public final static int DISPATCH_DRAG_LOCATION_EVENT = 1016; public final static int DISPATCH_SYSTEM_UI_VISIBILITY = 1017; public final static int DISPATCH_GENERIC_MOTION = 1018; - public final static int DO_PERFORM_ACCESSIBILITY_ACTION = 1019; - public final static int DO_FIND_ACCESSIBLITY_NODE_INFO_BY_ACCESSIBILITY_ID = 1020; - public final static int DO_FIND_ACCESSIBLITY_NODE_INFO_BY_VIEW_ID = 1021; - public final static int DO_FIND_ACCESSIBLITY_NODE_INFO_BY_VIEW_TEXT = 1022; + public final static int UPDATE_CONFIGURATION = 1019; + public final static int DO_PERFORM_ACCESSIBILITY_ACTION = 1020; + public final static int DO_FIND_ACCESSIBLITY_NODE_INFO_BY_ACCESSIBILITY_ID = 1021; + public final static int DO_FIND_ACCESSIBLITY_NODE_INFO_BY_VIEW_ID = 1022; + public final static int DO_FIND_ACCESSIBLITY_NODE_INFO_BY_VIEW_TEXT = 1023; @Override public void handleMessage(Message msg) { @@ -2217,6 +2289,9 @@ public final class ViewAncestor extends Handler implements ViewParent, if (mAdded) { boolean hasWindowFocus = msg.arg1 != 0; mAttachInfo.mHasWindowFocus = hasWindowFocus; + + profileRendering(hasWindowFocus); + if (hasWindowFocus) { boolean inTouchMode = msg.arg2 != 0; ensureTouchModeLocally(inTouchMode); @@ -2320,21 +2395,36 @@ public final class ViewAncestor extends Handler implements ViewParent, case DISPATCH_SYSTEM_UI_VISIBILITY: { handleDispatchSystemUiVisibilityChanged(msg.arg1); } break; + case UPDATE_CONFIGURATION: { + Configuration config = (Configuration)msg.obj; + if (config.isOtherSeqNewer(mLastConfiguration)) { + config = mLastConfiguration; + } + updateConfiguration(config, false); + } break; case DO_FIND_ACCESSIBLITY_NODE_INFO_BY_ACCESSIBILITY_ID: { - getAccessibilityInteractionController() - .findAccessibilityNodeInfoByAccessibilityIdUiThread(msg); + if (mView != null) { + getAccessibilityInteractionController() + .findAccessibilityNodeInfoByAccessibilityIdUiThread(msg); + } } break; case DO_PERFORM_ACCESSIBILITY_ACTION: { - getAccessibilityInteractionController() - .perfromAccessibilityActionUiThread(msg); + if (mView != null) { + getAccessibilityInteractionController() + .perfromAccessibilityActionUiThread(msg); + } } break; case DO_FIND_ACCESSIBLITY_NODE_INFO_BY_VIEW_ID: { - getAccessibilityInteractionController() - .findAccessibilityNodeInfoByViewIdUiThread(msg); + if (mView != null) { + getAccessibilityInteractionController() + .findAccessibilityNodeInfoByViewIdUiThread(msg); + } } break; case DO_FIND_ACCESSIBLITY_NODE_INFO_BY_VIEW_TEXT: { - getAccessibilityInteractionController() - .findAccessibilityNodeInfosByViewTextUiThread(msg); + if (mView != null) { + getAccessibilityInteractionController() + .findAccessibilityNodeInfosByViewTextUiThread(msg); + } } break; } } @@ -3405,6 +3495,11 @@ public final class ViewAncestor extends Handler implements ViewParent, } } + public void requestUpdateConfiguration(Configuration config) { + Message msg = obtainMessage(UPDATE_CONFIGURATION, config); + sendMessage(msg); + } + private void destroyHardwareRenderer() { if (mAttachInfo.mHardwareRenderer != null) { mAttachInfo.mHardwareRenderer.destroy(true); @@ -4149,44 +4244,37 @@ public final class ViewAncestor extends Handler implements ViewParent, public void findAccessibilityNodeInfoByAccessibilityId(int accessibilityId, int interactionId, IAccessibilityInteractionConnectionCallback callback) { - final ViewAncestor viewAncestor = mViewAncestor.get(); - if (viewAncestor == null) { - return; - } - getAccessibilityInteractionController() - .findAccessibilityNodeInfoByAccessibilityIdClientThread(accessibilityId, + if (mViewAncestor.get() != null) { + getAccessibilityInteractionController() + .findAccessibilityNodeInfoByAccessibilityIdClientThread(accessibilityId, interactionId, callback); + } } public void performAccessibilityAction(int accessibilityId, int action, int interactionId, IAccessibilityInteractionConnectionCallback callback) { - final ViewAncestor viewAncestor = mViewAncestor.get(); - if (viewAncestor == null) { - return; + if (mViewAncestor.get() != null) { + getAccessibilityInteractionController() + .performAccessibilityActionClientThread(accessibilityId, action, interactionId, + callback); } - getAccessibilityInteractionController() - .performAccessibilityActionClientThread(accessibilityId, action, interactionId, - callback); } public void findAccessibilityNodeInfoByViewId(int viewId, int interactionId, IAccessibilityInteractionConnectionCallback callback) { - final ViewAncestor viewAncestor = mViewAncestor.get(); - if (viewAncestor == null) { - return; + if (mViewAncestor.get() != null) { + getAccessibilityInteractionController() + .findAccessibilityNodeInfoByViewIdClientThread(viewId, interactionId, callback); } - getAccessibilityInteractionController() - .findAccessibilityNodeInfoByViewIdClientThread(viewId, interactionId, callback); } public void findAccessibilityNodeInfosByViewText(String text, int interactionId, IAccessibilityInteractionConnectionCallback callback) { - final ViewAncestor viewAncestor = mViewAncestor.get(); - if (viewAncestor == null) { - return; + if (mViewAncestor.get() != null) { + getAccessibilityInteractionController() + .findAccessibilityNodeInfosByViewTextClientThread(text, interactionId, + callback); } - getAccessibilityInteractionController() - .findAccessibilityNodeInfosByViewTextClientThread(text, interactionId, callback); } } @@ -4276,17 +4364,16 @@ public final class ViewAncestor extends Handler implements ViewParent, final IAccessibilityInteractionConnectionCallback callback = (IAccessibilityInteractionConnectionCallback) message.obj; - View root = ViewAncestor.this.mView; - if (root == null) { - return; - } - - FindByAccessibilitytIdPredicate predicate = mFindByAccessibilityIdPredicate; - predicate.init(accessibilityId); - - View target = root.findViewByPredicate(predicate); - if (target != null) { - AccessibilityNodeInfo info = target.createAccessibilityNodeInfo(); + AccessibilityNodeInfo info = null; + try { + FindByAccessibilitytIdPredicate predicate = mFindByAccessibilityIdPredicate; + predicate.init(accessibilityId); + View root = ViewAncestor.this.mView; + View target = root.findViewByPredicate(predicate); + if (target != null) { + info = target.createAccessibilityNodeInfo(); + } + } finally { try { callback.setFindAccessibilityNodeInfoResult(info, interactionId); } catch (RemoteException re) { @@ -4311,13 +4398,14 @@ public final class ViewAncestor extends Handler implements ViewParent, final IAccessibilityInteractionConnectionCallback callback = (IAccessibilityInteractionConnectionCallback) message.obj; - View root = ViewAncestor.this.mView; - if (root == null) { - return; - } - View target = root.findViewById(viewId); - if (target != null) { - AccessibilityNodeInfo info = target.createAccessibilityNodeInfo(); + AccessibilityNodeInfo info = null; + try { + View root = ViewAncestor.this.mView; + View target = root.findViewById(viewId); + if (target != null) { + info = target.createAccessibilityNodeInfo(); + } + } finally { try { callback.setFindAccessibilityNodeInfoResult(info, interactionId); } catch (RemoteException re) { @@ -4346,32 +4434,32 @@ public final class ViewAncestor extends Handler implements ViewParent, (IAccessibilityInteractionConnectionCallback) args.arg2; mPool.release(args); - View root = ViewAncestor.this.mView; - if (root == null) { - return; - } + List<AccessibilityNodeInfo> infos = null; + try { + View root = ViewAncestor.this.mView; - ArrayList<View> foundViews = mAttachInfo.mFocusablesTempList; - foundViews.clear(); + ArrayList<View> foundViews = mAttachInfo.mFocusablesTempList; + foundViews.clear(); - root.findViewsWithText(foundViews, text); - if (foundViews.isEmpty()) { - return; - } + root.findViewsWithText(foundViews, text); + if (foundViews.isEmpty()) { + return; + } - List<AccessibilityNodeInfo> infos = mTempAccessibilityNodeInfoList; - infos.clear(); + infos = mTempAccessibilityNodeInfoList; + infos.clear(); - final int viewCount = foundViews.size(); - for (int i = 0; i < viewCount; i++) { - View foundView = foundViews.get(i); - infos.add(foundView.createAccessibilityNodeInfo()); - } - - try { - callback.setFindAccessibilityNodeInfosResult(infos, interactionId); - } catch (RemoteException re) { - /* ignore - the other side will time out */ + final int viewCount = foundViews.size(); + for (int i = 0; i < viewCount; i++) { + View foundView = foundViews.get(i); + infos.add(foundView.createAccessibilityNodeInfo()); + } + } finally { + try { + callback.setFindAccessibilityNodeInfosResult(infos, interactionId); + } catch (RemoteException re) { + /* ignore - the other side will time out */ + } } } @@ -4397,30 +4485,28 @@ public final class ViewAncestor extends Handler implements ViewParent, (IAccessibilityInteractionConnectionCallback) args.arg1; mPool.release(args); - if (ViewAncestor.this.mView == null) { - return; - } - boolean succeeded = false; - switch (action) { - case AccessibilityNodeInfo.ACTION_FOCUS: { - succeeded = performActionFocus(accessibilityId); - } break; - case AccessibilityNodeInfo.ACTION_CLEAR_FOCUS: { - succeeded = performActionClearFocus(accessibilityId); - } break; - case AccessibilityNodeInfo.ACTION_SELECT: { - succeeded = performActionSelect(accessibilityId); - } break; - case AccessibilityNodeInfo.ACTION_CLEAR_SELECTION: { - succeeded = performActionClearSelection(accessibilityId); - } break; - } - try { - callback.setPerformAccessibilityActionResult(succeeded, interactionId); - } catch (RemoteException re) { - /* ignore - the other side will time out */ + switch (action) { + case AccessibilityNodeInfo.ACTION_FOCUS: { + succeeded = performActionFocus(accessibilityId); + } break; + case AccessibilityNodeInfo.ACTION_CLEAR_FOCUS: { + succeeded = performActionClearFocus(accessibilityId); + } break; + case AccessibilityNodeInfo.ACTION_SELECT: { + succeeded = performActionSelect(accessibilityId); + } break; + case AccessibilityNodeInfo.ACTION_CLEAR_SELECTION: { + succeeded = performActionClearSelection(accessibilityId); + } break; + } + } finally { + try { + callback.setPerformAccessibilityActionResult(succeeded, interactionId); + } catch (RemoteException re) { + /* ignore - the other side will time out */ + } } } diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java index 5236a9e16e37..e07085c94db7 100644 --- a/core/java/android/view/Window.java +++ b/core/java/android/view/Window.java @@ -16,6 +16,7 @@ package android.view; +import android.app.Application; import android.content.Context; import android.content.res.CompatibilityInfo; import android.content.res.Configuration; @@ -25,6 +26,7 @@ import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.Bundle; import android.os.IBinder; +import android.util.Slog; import android.view.accessibility.AccessibilityEvent; /** @@ -463,11 +465,16 @@ public abstract class Window { mWindowManager = new LocalWindowManager(wm, hardwareAccelerated); } + static CompatibilityInfoHolder getCompatInfo(Context context) { + Application app = (Application)context.getApplicationContext(); + return app != null ? app.mLoadedApk.mCompatibilityInfo : new CompatibilityInfoHolder(); + } + private class LocalWindowManager extends WindowManagerImpl.CompatModeWrapper { private final boolean mHardwareAccelerated; LocalWindowManager(WindowManager wm, boolean hardwareAccelerated) { - super(wm, mContext.getResources().getCompatibilityInfo()); + super(wm, getCompatInfo(mContext)); mHardwareAccelerated = hardwareAccelerated; } diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java index d18ae0ed4672..54e7c04a4636 100644 --- a/core/java/android/view/WindowManagerImpl.java +++ b/core/java/android/view/WindowManagerImpl.java @@ -19,10 +19,12 @@ package android.view; import java.util.HashMap; import android.content.res.CompatibilityInfo; +import android.content.res.Configuration; import android.graphics.PixelFormat; import android.os.IBinder; import android.util.AndroidRuntimeException; import android.util.Log; +import android.util.Slog; import android.view.WindowManager; import android.view.inputmethod.InputMethodManager; @@ -87,29 +89,32 @@ public class WindowManagerImpl implements WindowManager { = new HashMap<CompatibilityInfo, WindowManager>(); static class CompatModeWrapper implements WindowManager { - private final WindowManager mWindowManager; + private final WindowManagerImpl mWindowManager; private final Display mDefaultDisplay; + private final CompatibilityInfoHolder mCompatibilityInfo; - CompatModeWrapper(WindowManager wm, CompatibilityInfo ci) { - mWindowManager = wm; + CompatModeWrapper(WindowManager wm, CompatibilityInfoHolder ci) { + mWindowManager = wm instanceof CompatModeWrapper + ? ((CompatModeWrapper)wm).mWindowManager : (WindowManagerImpl)wm; // Use the original display if there is no compatibility mode // to apply, or the underlying window manager is already a // compatibility mode wrapper. (We assume that if it is a // wrapper, it is applying the same compatibility mode.) - if (ci == null || wm instanceof CompatModeWrapper - || (!ci.isScalingRequired() && ci.supportsScreen())) { + if (ci == null) { mDefaultDisplay = mWindowManager.getDefaultDisplay(); } else { //mDefaultDisplay = mWindowManager.getDefaultDisplay(); mDefaultDisplay = Display.createCompatibleDisplay( mWindowManager.getDefaultDisplay().getDisplayId(), ci); } + + mCompatibilityInfo = ci; } @Override public void addView(View view, android.view.ViewGroup.LayoutParams params) { - mWindowManager.addView(view, params); + mWindowManager.addView(view, params, mCompatibilityInfo); } @Override @@ -145,8 +150,9 @@ public class WindowManagerImpl implements WindowManager { } public static WindowManager getDefault(CompatibilityInfo compatInfo) { - if (compatInfo == null || (!compatInfo.isScalingRequired() - && compatInfo.supportsScreen())) { + CompatibilityInfoHolder cih = new CompatibilityInfoHolder(); + cih.set(compatInfo); + if (cih.getIfNeeded() == null) { return sWindowManager; } @@ -158,35 +164,36 @@ public class WindowManagerImpl implements WindowManager { // having to make wrappers. WindowManager wm = sCompatWindowManagers.get(compatInfo); if (wm == null) { - wm = new CompatModeWrapper(sWindowManager, compatInfo); + wm = new CompatModeWrapper(sWindowManager, cih); sCompatWindowManagers.put(compatInfo, wm); } return wm; } } + + public static WindowManager getDefault(CompatibilityInfoHolder compatInfo) { + return new CompatModeWrapper(sWindowManager, compatInfo); + } public boolean isHardwareAccelerated() { return false; } - public void addView(View view) - { + public void addView(View view) { addView(view, new WindowManager.LayoutParams( WindowManager.LayoutParams.TYPE_APPLICATION, 0, PixelFormat.OPAQUE)); } - public void addView(View view, ViewGroup.LayoutParams params) - { - addView(view, params, false); + public void addView(View view, ViewGroup.LayoutParams params) { + addView(view, params, null, false); } - public void addViewNesting(View view, ViewGroup.LayoutParams params) - { - addView(view, params, false); + public void addView(View view, ViewGroup.LayoutParams params, CompatibilityInfoHolder cih) { + addView(view, params, cih, false); } - private void addView(View view, ViewGroup.LayoutParams params, boolean nest) - { + private void addView(View view, ViewGroup.LayoutParams params, + CompatibilityInfoHolder cih, boolean nest) { if (false) Log.v("WindowManager", "addView view=" + view); if (!(params instanceof WindowManager.LayoutParams)) { @@ -236,6 +243,11 @@ public class WindowManagerImpl implements WindowManager { root = new ViewAncestor(view.getContext()); root.mAddNesting = 1; + if (cih == null) { + root.mCompatibilityInfo = new CompatibilityInfoHolder(); + } else { + root.mCompatibilityInfo = cih; + } view.setLayoutParams(wparams); @@ -325,9 +337,11 @@ public class WindowManagerImpl implements WindowManager { return view; } - InputMethodManager imm = InputMethodManager.getInstance(view.getContext()); - if (imm != null) { - imm.windowDismissed(mViews[index].getWindowToken()); + if (view != null) { + InputMethodManager imm = InputMethodManager.getInstance(view.getContext()); + if (imm != null) { + imm.windowDismissed(mViews[index].getWindowToken()); + } } root.die(false); finishRemoveViewLocked(view, index); @@ -351,9 +365,11 @@ public class WindowManagerImpl implements WindowManager { removeItem(tmpParams, mParams, index); mParams = tmpParams; - view.assignParent(null); - // func doesn't allow null... does it matter if we clear them? - //view.setLayoutParams(null); + if (view != null) { + view.assignParent(null); + // func doesn't allow null... does it matter if we clear them? + //view.setLayoutParams(null); + } } public void closeAll(IBinder token, String who, String what) { @@ -401,6 +417,17 @@ public class WindowManagerImpl implements WindowManager { } } + public void reportNewConfiguration(Configuration config) { + synchronized (this) { + int count = mViews.length; + config = new Configuration(config); + for (int i=0; i<count; i++) { + ViewAncestor root = mRoots[i]; + root.requestUpdateConfiguration(config); + } + } + } + public WindowManager.LayoutParams getRootViewLayoutParameter(View view) { ViewParent vp = view.getParent(); while (vp != null && !(vp instanceof ViewAncestor)) { diff --git a/core/java/android/view/accessibility/AccessibilityEvent.java b/core/java/android/view/accessibility/AccessibilityEvent.java index 32bfa2f7eaee..06e4827ae371 100644 --- a/core/java/android/view/accessibility/AccessibilityEvent.java +++ b/core/java/android/view/accessibility/AccessibilityEvent.java @@ -264,8 +264,8 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par private boolean mIsInPool; private int mEventType; - private int mSourceAccessibilityViewId; - private int mSourceAccessibilityWindowId; + private int mSourceAccessibilityViewId = View.NO_ID; + private int mSourceAccessibilityWindowId = View.NO_ID; private CharSequence mPackageName; private long mEventTime; diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java index 752f8648ad4a..5fa65b450e42 100644 --- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java +++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java @@ -93,9 +93,9 @@ public class AccessibilityNodeInfo implements Parcelable { private boolean mSealed; // Data. - private int mAccessibilityViewId; - private int mAccessibilityWindowId; - private int mParentAccessibilityViewId; + private int mAccessibilityViewId = View.NO_ID; + private int mAccessibilityWindowId = View.NO_ID; + private int mParentAccessibilityViewId = View.NO_ID; private int mBooleanProperties; private final Rect mBounds = new Rect(); @@ -723,6 +723,7 @@ public class AccessibilityNodeInfo implements Parcelable { sPoolSize--; info.mNext = null; info.mIsInPool = false; + return info; } return new AccessibilityNodeInfo(); } @@ -869,6 +870,27 @@ public class AccessibilityNodeInfo implements Parcelable { } @Override + public boolean equals(Object object) { + if (this == object) { + return true; + } + if (object == null) { + return false; + } + if (getClass() != object.getClass()) { + return false; + } + AccessibilityNodeInfo other = (AccessibilityNodeInfo) object; + if (mAccessibilityViewId != other.mAccessibilityViewId) { + return false; + } + if (mAccessibilityWindowId != other.mAccessibilityWindowId) { + return false; + } + return true; + } + + @Override public int hashCode() { final int prime = 31; int result = 1; diff --git a/core/java/android/view/inputmethod/InputMethodInfo.java b/core/java/android/view/inputmethod/InputMethodInfo.java index fee69e0f6566..4ec4ff9de30d 100644 --- a/core/java/android/view/inputmethod/InputMethodInfo.java +++ b/core/java/android/view/inputmethod/InputMethodInfo.java @@ -23,9 +23,9 @@ import android.content.ComponentName; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; +import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; -import android.content.pm.PackageManager.NameNotFoundException; import android.content.res.Resources; import android.content.res.TypedArray; import android.content.res.XmlResourceParser; @@ -38,6 +38,8 @@ import android.util.Xml; import java.io.IOException; import java.util.ArrayList; +import java.util.List; +import java.util.Map; /** * This class is used to specify meta information of an input method. @@ -77,13 +79,28 @@ public final class InputMethodInfo implements Parcelable { /** * Constructor. - * + * * @param context The Context in which we are parsing the input method. * @param service The ResolveInfo returned from the package manager about * this input method's component. */ public InputMethodInfo(Context context, ResolveInfo service) throws XmlPullParserException, IOException { + this(context, service, null); + } + + /** + * Constructor. + * + * @param context The Context in which we are parsing the input method. + * @param service The ResolveInfo returned from the package manager about + * this input method's component. + * @param additionalSubtypes additional subtypes being added to this InputMethodInfo + * @hide + */ + public InputMethodInfo(Context context, ResolveInfo service, + Map<String, List<InputMethodSubtype>> additionalSubtypesMap) + throws XmlPullParserException, IOException { mService = service; ServiceInfo si = service.serviceInfo; mId = new ComponentName(si.packageName, si.name).flattenToShortString(); @@ -157,6 +174,17 @@ public final class InputMethodInfo implements Parcelable { } finally { if (parser != null) parser.close(); } + + if (additionalSubtypesMap != null && additionalSubtypesMap.containsKey(mId)) { + final List<InputMethodSubtype> additionalSubtypes = additionalSubtypesMap.get(mId); + final int N = additionalSubtypes.size(); + for (int i = 0; i < N; ++i) { + final InputMethodSubtype subtype = additionalSubtypes.get(i); + if (!mSubtypes.contains(subtype)) { + mSubtypes.add(subtype); + } + } + } mSettingsActivityName = settingsActivityComponent; mIsDefaultResId = isDefaultResId; } diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java index 4df237b60783..47f5e4c4f9cb 100644 --- a/core/java/android/view/inputmethod/InputMethodManager.java +++ b/core/java/android/view/inputmethod/InputMethodManager.java @@ -1558,6 +1558,24 @@ public final class InputMethodManager { } } + /** + * Set additional input method subtypes. + * @param imeToken Supplies the identifying token given to an input method. + * @param subtypes subtypes will be added as additional subtypes of the current input method. + * @return true if the additional input method subtypes are successfully added. + */ + public boolean setAdditionalInputMethodSubtypes( + IBinder imeToken, InputMethodSubtype[] subtypes) { + synchronized (mH) { + try { + return mService.setAdditionalInputMethodSubtypes(imeToken, subtypes); + } catch (RemoteException e) { + Log.w(TAG, "IME died: " + mCurId, e); + return false; + } + } + } + public InputMethodSubtype getLastInputMethodSubtype() { synchronized (mH) { try { diff --git a/core/java/android/webkit/BrowserFrame.java b/core/java/android/webkit/BrowserFrame.java index 9f2fd12c99ca..2f4774f61e17 100644 --- a/core/java/android/webkit/BrowserFrame.java +++ b/core/java/android/webkit/BrowserFrame.java @@ -44,6 +44,9 @@ import java.io.IOException; import java.io.InputStream; import java.lang.ref.WeakReference; import java.net.URLEncoder; +import java.nio.charset.Charsets; +import java.security.PrivateKey; +import java.security.cert.CertificateEncodingException; import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.HashMap; @@ -1141,7 +1144,7 @@ class BrowserFrame extends Handler { } /** - * Called by JNI when the native HTTP(S) stack gets an invalid cert chain. + * Called by JNI when the native HTTPS stack gets an invalid cert chain. * * We delegate the request to CallbackProxy, and route its response to * {@link #nativeSslCertErrorProceed(int)} or @@ -1182,6 +1185,32 @@ class BrowserFrame extends Handler { } /** + * Called by JNI when the native HTTPS stack gets a client + * certificate request. + * + * We delegate the request to CallbackProxy, and route its response to + * {@link #nativeSslClientCert(int, X509Certificate)}. + */ + private void requestClientCert(int handle, byte[] host_and_port_bytes) { + String host_and_port = new String(host_and_port_bytes, Charsets.UTF_8); + SslClientCertLookupTable table = SslClientCertLookupTable.getInstance(); + if (table.IsAllowed(host_and_port)) { + // previously allowed + nativeSslClientCert(handle, + table.PrivateKey(host_and_port), + table.CertificateChain(host_and_port)); + } else if (table.IsDenied(host_and_port)) { + // previously denied + nativeSslClientCert(handle, null, null); + } else { + // previously ignored or new + mCallbackProxy.onReceivedClientCertRequest( + new ClientCertRequestHandler(this, handle, host_and_port, table), + host_and_port); + } + } + + /** * Called by JNI when the native HTTP stack needs to download a file. * * We delegate the request to CallbackProxy, which owns the current app's @@ -1366,4 +1395,8 @@ class BrowserFrame extends Handler { private native void nativeSslCertErrorProceed(int handle); private native void nativeSslCertErrorCancel(int handle, int cert_error); + + native void nativeSslClientCert(int handle, + byte[] pkcs8EncodedPrivateKey, + byte[][] asn1DerEncodedCertificateChain); } diff --git a/core/java/android/webkit/CallbackProxy.java b/core/java/android/webkit/CallbackProxy.java index 23fd12d99f0e..f7d55f6f00af 100644 --- a/core/java/android/webkit/CallbackProxy.java +++ b/core/java/android/webkit/CallbackProxy.java @@ -118,6 +118,7 @@ class CallbackProxy extends Handler { private static final int SET_INSTALLABLE_WEBAPP = 138; private static final int NOTIFY_SEARCHBOX_LISTENERS = 139; private static final int AUTO_LOGIN = 140; + private static final int CLIENT_CERT_REQUEST = 141; // Message triggered by the client to resume execution private static final int NOTIFY = 200; @@ -273,7 +274,7 @@ class CallbackProxy extends Handler { mWebViewClient.onPageFinished(mWebView, finishedUrl); } break; - + case RECEIVED_ICON: if (mWebChromeClient != null) { mWebChromeClient.onReceivedIcon(mWebView, (Bitmap) msg.obj); @@ -340,7 +341,7 @@ class CallbackProxy extends Handler { case SSL_ERROR: if (mWebViewClient != null) { - HashMap<String, Object> map = + HashMap<String, Object> map = (HashMap<String, Object>) msg.obj; mWebViewClient.onReceivedSslError(mWebView, (SslErrorHandler) map.get("handler"), @@ -348,6 +349,16 @@ class CallbackProxy extends Handler { } break; + case CLIENT_CERT_REQUEST: + if (mWebViewClient != null) { + HashMap<String, Object> map = + (HashMap<String, Object>) msg.obj; + mWebViewClient.onReceivedClientCertRequest(mWebView, + (ClientCertRequestHandler) map.get("handler"), + (String) map.get("host_and_port")); + } + break; + case PROGRESS: // Synchronize to ensure mLatestProgress is not modified after // setProgress is called and before mProgressUpdatePending is @@ -543,14 +554,14 @@ class CallbackProxy extends Handler { new AlertDialog.Builder(mContext) .setTitle(getJsDialogTitle(url)) .setMessage(message) - .setPositiveButton(R.string.ok, + .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() { public void onClick( DialogInterface dialog, int which) { res.confirm(); }}) - .setNegativeButton(R.string.cancel, + .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { public void onClick( DialogInterface dialog, @@ -904,7 +915,7 @@ class CallbackProxy extends Handler { if (PERF_PROBE) { // un-comment this if PERF_PROBE is true // Looper.myQueue().setWaitCallback(null); - Log.d("WebCore", "WebCore thread used " + + Log.d("WebCore", "WebCore thread used " + (SystemClock.currentThreadTimeMillis() - mWebCoreThreadTime) + " ms and idled " + mWebCoreIdleTime + " ms"); Network.getInstance(mContext).stopTiming(); @@ -934,7 +945,7 @@ class CallbackProxy extends Handler { sendMessage(msg); } - public void onFormResubmission(Message dontResend, + public void onFormResubmission(Message dontResend, Message resend) { // Do an unsynchronized quick check to avoid posting if no callback has // been set. @@ -998,7 +1009,6 @@ class CallbackProxy extends Handler { return; } Message msg = obtainMessage(SSL_ERROR); - //, handler); HashMap<String, Object> map = new HashMap(); map.put("handler", handler); map.put("error", error); @@ -1006,6 +1016,23 @@ class CallbackProxy extends Handler { sendMessage(msg); } /** + * @hide + */ + public void onReceivedClientCertRequest(ClientCertRequestHandler handler, String host_and_port) { + // Do an unsynchronized quick check to avoid posting if no callback has + // been set. + if (mWebViewClient == null) { + handler.cancel(); + return; + } + Message msg = obtainMessage(CLIENT_CERT_REQUEST); + HashMap<String, Object> map = new HashMap(); + map.put("handler", handler); + map.put("host_and_port", host_and_port); + msg.obj = map; + sendMessage(msg); + } + /** * @hide - hide this because it contains a parameter of type SslCertificate, * which is located in a hidden package. */ diff --git a/core/java/android/webkit/ClientCertRequestHandler.java b/core/java/android/webkit/ClientCertRequestHandler.java new file mode 100644 index 000000000000..3a71e7e5bc33 --- /dev/null +++ b/core/java/android/webkit/ClientCertRequestHandler.java @@ -0,0 +1,78 @@ +/* + * 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 android.webkit; + +import java.security.PrivateKey; +import java.security.cert.CertificateEncodingException; +import java.security.cert.X509Certificate; +import org.apache.harmony.xnet.provider.jsse.NativeCrypto; + +/** + * ClientCertRequestHandler: class responsible for handling client + * certificate requests. This class is passed as a parameter to + * BrowserCallback.displayClientCertRequestDialog and is meant to + * receive the user's response. + * + * @hide + */ +public final class ClientCertRequestHandler { + + private final BrowserFrame mBrowserFrame; + private final int mHandle; + private final String mHostAndPort; + private final SslClientCertLookupTable mTable; + ClientCertRequestHandler(BrowserFrame browserFrame, + int handle, + String host_and_port, + SslClientCertLookupTable table) { + mBrowserFrame = browserFrame; + mHandle = handle; + mHostAndPort = host_and_port; + mTable = table; + } + + /** + * Proceed with the specified private key and client certificate chain. + */ + public void proceed(PrivateKey privateKey, X509Certificate[] chain) { + byte[] privateKeyBytes = privateKey.getEncoded(); + byte[][] chainBytes; + try { + chainBytes = NativeCrypto.encodeCertificates(chain); + } catch (CertificateEncodingException e) { + mBrowserFrame.nativeSslClientCert(mHandle, null, null); + return; + } + mTable.Allow(mHostAndPort, privateKeyBytes, chainBytes); + mBrowserFrame.nativeSslClientCert(mHandle, privateKeyBytes, chainBytes); + } + + /** + * Igore the request for now, the user may be prompted again. + */ + public void ignore() { + mBrowserFrame.nativeSslClientCert(mHandle, null, null); + } + + /** + * Cancel this request, remember the users negative choice. + */ + public void cancel() { + mTable.Deny(mHostAndPort); + mBrowserFrame.nativeSslClientCert(mHandle, null, null); + } +} diff --git a/core/java/android/webkit/HTML5VideoFullScreen.java b/core/java/android/webkit/HTML5VideoFullScreen.java index 57cda97f8235..44229a42be9a 100644 --- a/core/java/android/webkit/HTML5VideoFullScreen.java +++ b/core/java/android/webkit/HTML5VideoFullScreen.java @@ -318,10 +318,12 @@ public class HTML5VideoFullScreen extends HTML5VideoView @Override protected void switchProgressView(boolean playerBuffering) { - if (playerBuffering) { - mProgressView.setVisibility(View.VISIBLE); - } else { - mProgressView.setVisibility(View.GONE); + if (mProgressView != null) { + if (playerBuffering) { + mProgressView.setVisibility(View.VISIBLE); + } else { + mProgressView.setVisibility(View.GONE); + } } return; } diff --git a/core/java/android/webkit/SslCertLookupTable.java b/core/java/android/webkit/SslCertLookupTable.java index abf612ef866b..faff110aae8a 100644 --- a/core/java/android/webkit/SslCertLookupTable.java +++ b/core/java/android/webkit/SslCertLookupTable.java @@ -19,11 +19,11 @@ package android.webkit; import android.os.Bundle; import android.net.http.SslError; -/* +/** * A simple class to store the wrong certificates that user is aware but * chose to proceed. */ -class SslCertLookupTable { +final class SslCertLookupTable { private static SslCertLookupTable sTable; private final Bundle table; diff --git a/core/java/android/webkit/SslClientCertLookupTable.java b/core/java/android/webkit/SslClientCertLookupTable.java new file mode 100644 index 000000000000..630debd9cace --- /dev/null +++ b/core/java/android/webkit/SslClientCertLookupTable.java @@ -0,0 +1,73 @@ +/* + * 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 android.webkit; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +/** + * A simple class to store client certificates that user has chosen. + */ +final class SslClientCertLookupTable { + private static SslClientCertLookupTable sTable; + private final Map<String, byte[]> privateKeys; + private final Map<String, byte[][]> certificateChains; + private final Set<String> denied; + + public static synchronized SslClientCertLookupTable getInstance() { + if (sTable == null) { + sTable = new SslClientCertLookupTable(); + } + return sTable; + } + + private SslClientCertLookupTable() { + privateKeys = new HashMap<String, byte[]>(); + certificateChains = new HashMap<String, byte[][]>(); + denied = new HashSet<String>(); + } + + public void Allow(String host_and_port, byte[] privateKey, byte[][] chain) { + privateKeys.put(host_and_port, privateKey); + certificateChains.put(host_and_port, chain); + denied.remove(host_and_port); + } + + public void Deny(String host_and_port) { + privateKeys.remove(host_and_port); + certificateChains.remove(host_and_port); + denied.add(host_and_port); + } + + public boolean IsAllowed(String host_and_port) { + return privateKeys.containsKey(host_and_port); + } + + public boolean IsDenied(String host_and_port) { + return denied.contains(host_and_port); + } + + public byte[] PrivateKey(String host_and_port) { + return privateKeys.get(host_and_port); + } + + public byte[][] CertificateChain(String host_and_port) { + return certificateChains.get(host_and_port); + } +} diff --git a/core/java/android/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java index 66fcc2775a8d..c361a4a8fba4 100644 --- a/core/java/android/webkit/WebSettings.java +++ b/core/java/android/webkit/WebSettings.java @@ -1234,7 +1234,7 @@ public class WebSettings { */ @Deprecated public synchronized void setPluginsEnabled(boolean flag) { - setPluginState(PluginState.ON); + setPluginState(flag ? PluginState.ON : PluginState.OFF); } /** diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java index 4aad02256fc9..95e48808665d 100644 --- a/core/java/android/webkit/WebView.java +++ b/core/java/android/webkit/WebView.java @@ -44,7 +44,6 @@ import android.graphics.Point; import android.graphics.Rect; import android.graphics.RectF; import android.graphics.Region; -import android.graphics.SurfaceTexture; import android.graphics.Shader; import android.graphics.drawable.Drawable; import android.net.Proxy; @@ -99,6 +98,8 @@ import android.widget.ListView; import android.widget.OverScroller; import android.widget.Toast; +import junit.framework.Assert; + import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; @@ -117,8 +118,6 @@ import java.util.Vector; import java.util.regex.Matcher; import java.util.regex.Pattern; -import junit.framework.Assert; - /** * <p>A View that displays web pages. This class is the basis upon which you * can roll your own web browser or simply display some online content within your Activity. @@ -173,7 +172,7 @@ import junit.framework.Assert; * * // OR, you can also load from an HTML string: * String summary = "<html><body>You scored <b>192</b> points.</body></html>"; - * webview.loadData(summary, "text/html", "utf-8"); + * webview.loadData(summary, "text/html", null); * // ... although note that there are restrictions on what this HTML can do. * // See the JavaDocs for {@link #loadData(String,String,String) loadData()} and {@link * #loadDataWithBaseURL(String,String,String,String,String) loadDataWithBaseURL()} for more info. @@ -423,6 +422,9 @@ public class WebView extends AbsoluteLayout */ private int mLastTouchX; private int mLastTouchY; + private int mStartTouchX; + private int mStartTouchY; + private float mAverageAngle; /** * Time of the last touch event. @@ -1190,7 +1192,6 @@ public class WebView extends AbsoluteLayout final ViewConfiguration configuration = ViewConfiguration.get(getContext()); int slop = configuration.getScaledTouchSlop(); mTouchSlopSquare = slop * slop; - mMinLockSnapReverseDistance = slop; slop = configuration.getScaledDoubleTapSlop(); mDoubleTapSlopSquare = slop * slop; final float density = getContext().getResources().getDisplayMetrics().density; @@ -1818,9 +1819,9 @@ public class WebView extends AbsoluteLayout */ public boolean loadViewState(InputStream stream) { try { - DrawData draw = ViewStateSerializer.deserializeViewState(stream, this); + mLoadedPicture = ViewStateSerializer.deserializeViewState(stream, this); mBlockWebkitViewMessages = true; - setNewPicture(draw); + setNewPicture(mLoadedPicture, true); return true; } catch (IOException e) { Log.w(LOGTAG, "Failed to loadViewState", e); @@ -1835,6 +1836,7 @@ public class WebView extends AbsoluteLayout */ public void clearViewState() { mBlockWebkitViewMessages = false; + mLoadedPicture = null; invalidate(); } @@ -1965,14 +1967,17 @@ public class WebView extends AbsoluteLayout } /** - * Load the given data into the WebView. This will load the data into - * WebView using the data: scheme. Content loaded through this mechanism - * does not have the ability to load content from the network. - * @param data A String of data in the given encoding. The date must - * be URI-escaped -- '#', '%', '\', '?' should be replaced by %23, %25, - * %27, %3f respectively. - * @param mimeType The MIMEType of the data. i.e. text/html, image/jpeg - * @param encoding The encoding of the data. i.e. utf-8, base64 + * Load the given data into the WebView using a 'data' scheme URL. Content + * loaded in this way does not have the ability to load content from the + * network. + * <p> + * If the value of the encoding parameter is 'base64', then the data must + * be encoded as base64. Otherwise, the data must use ASCII encoding for + * octets inside the range of safe URL characters and use the standard %xx + * hex encoding of URLs for octets outside that range. + * @param data A String of data in the given encoding. + * @param mimeType The MIMEType of the data, e.g. 'text/html'. + * @param encoding The encoding of the data. */ public void loadData(String data, String mimeType, String encoding) { checkThread(); @@ -1980,7 +1985,14 @@ public class WebView extends AbsoluteLayout } private void loadDataImpl(String data, String mimeType, String encoding) { - loadUrlImpl("data:" + mimeType + ";" + encoding + "," + data); + StringBuilder dataUrl = new StringBuilder("data:"); + dataUrl.append(mimeType); + if ("base64".equals(encoding)) { + dataUrl.append(";base64"); + } + dataUrl.append(","); + dataUrl.append(data); + loadUrlImpl(dataUrl.toString()); } /** @@ -1989,13 +2001,9 @@ public class WebView extends AbsoluteLayout * that is loaded through this interface. As such, it is used to resolve any * relative URLs. The historyUrl is used for the history entry. * <p> - * Note for post 1.0. Due to the change in the WebKit, the access to asset - * files through "file:///android_asset/" for the sub resources is more - * restricted. If you provide null or empty string as baseUrl, you won't be - * able to access asset files. If the baseUrl is anything other than - * http(s)/ftp(s)/about/javascript as scheme, you can access asset files for - * sub resources. - * + * Note that content specified in this way can access local device files + * (via 'file' scheme URLs) only if baseUrl specifies a scheme other than + * 'http', 'https', 'ftp', 'ftps', 'about' or 'javascript'. * @param baseUrl Url to resolve relative paths with, if null defaults to * "about:blank" * @param data A String of data in the given encoding. @@ -5531,6 +5539,13 @@ public class WebView extends AbsoluteLayout } mZoomManager.onSizeChanged(w, h, ow, oh); + + if (mLoadedPicture != null && mDelaySetPicture == null) { + // Size changes normally result in a new picture + // Re-set the loaded picture to simulate that + // However, do not update the base layer as that hasn't changed + setNewPicture(mLoadedPicture, false); + } } @Override @@ -5582,15 +5597,26 @@ public class WebView extends AbsoluteLayout } } - // Here are the snap align logic: - // 1. If it starts nearly horizontally or vertically, snap align; - // 2. If there is a dramitic direction change, let it go; - // 3. If there is a same direction back and forth, lock it. - - // adjustable parameters - private int mMinLockSnapReverseDistance; - private static final float MAX_SLOPE_FOR_DIAG = 1.5f; - private static final int MIN_BREAK_SNAP_CROSS_DISTANCE = 80; + /* + * Here is the snap align logic: + * 1. If it starts nearly horizontally or vertically, snap align; + * 2. If there is a dramitic direction change, let it go; + * + * Adjustable parameters. Angle is the radians on a unit circle, limited + * to quadrant 1. Values range from 0f (horizontal) to PI/2 (vertical) + */ + private static final float HSLOPE_TO_START_SNAP = .1f; + private static final float HSLOPE_TO_BREAK_SNAP = .2f; + private static final float VSLOPE_TO_START_SNAP = 1.25f; + private static final float VSLOPE_TO_BREAK_SNAP = .95f; + /* + * These values are used to influence the average angle when entering + * snap mode. If is is the first movement entering snap, we set the average + * to the appropriate ideal. If the user is entering into snap after the + * first movement, then we average the average angle with these values. + */ + private static final float ANGLE_VERT = 2f; + private static final float ANGLE_HORIZ = 0f; private boolean hitFocusedPlugin(int contentX, int contentY) { if (DebugFlags.WEB_VIEW) { @@ -5696,6 +5722,12 @@ public class WebView extends AbsoluteLayout return true; } + private float calculateDragAngle(int dx, int dy) { + dx = Math.abs(dx); + dy = Math.abs(dy); + return (float) Math.atan2(dy, dx); + } + /* * Common code for single touch and multi-touch. * (x, y) denotes current focus point, which is the touch point for single touch @@ -5941,16 +5973,17 @@ public class WebView extends AbsoluteLayout // if mZoomManager.supportsPanDuringZoom() is true. final ScaleGestureDetector detector = mZoomManager.getMultiTouchGestureDetector(); + mAverageAngle = calculateDragAngle(deltaX, deltaY); if (detector == null || !detector.isInProgress()) { // if it starts nearly horizontal or vertical, enforce it - int ax = Math.abs(deltaX); - int ay = Math.abs(deltaY); - if (ax > MAX_SLOPE_FOR_DIAG * ay) { + if (mAverageAngle < HSLOPE_TO_START_SNAP) { mSnapScrollMode = SNAP_X; mSnapPositive = deltaX > 0; - } else if (ay > MAX_SLOPE_FOR_DIAG * ax) { + mAverageAngle = ANGLE_HORIZ; + } else if (mAverageAngle > VSLOPE_TO_START_SNAP) { mSnapScrollMode = SNAP_Y; mSnapPositive = deltaY > 0; + mAverageAngle = ANGLE_VERT; } } @@ -5970,35 +6003,30 @@ public class WebView extends AbsoluteLayout if (deltaX == 0 && deltaY == 0) { keepScrollBarsVisible = done = true; } else { - if (mSnapScrollMode == SNAP_X || mSnapScrollMode == SNAP_Y) { - int ax = Math.abs(deltaX); - int ay = Math.abs(deltaY); - if (mSnapScrollMode == SNAP_X) { + mAverageAngle = (mAverageAngle + + calculateDragAngle(deltaX, deltaY)) / 2; + if (mSnapScrollMode != SNAP_NONE) { + if (mSnapScrollMode == SNAP_Y) { // radical change means getting out of snap mode - if (ay > MAX_SLOPE_FOR_DIAG * ax - && ay > MIN_BREAK_SNAP_CROSS_DISTANCE) { + if (mAverageAngle < VSLOPE_TO_BREAK_SNAP) { mSnapScrollMode = SNAP_NONE; } - // reverse direction means lock in the snap mode - if (ax > MAX_SLOPE_FOR_DIAG * ay && - (mSnapPositive - ? deltaX < -mMinLockSnapReverseDistance - : deltaX > mMinLockSnapReverseDistance)) { - mSnapScrollMode |= SNAP_LOCK; - } - } else { + } + if (mSnapScrollMode == SNAP_X) { // radical change means getting out of snap mode - if (ax > MAX_SLOPE_FOR_DIAG * ay - && ax > MIN_BREAK_SNAP_CROSS_DISTANCE) { + if (mAverageAngle > HSLOPE_TO_BREAK_SNAP) { mSnapScrollMode = SNAP_NONE; } - // reverse direction means lock in the snap mode - if (ay > MAX_SLOPE_FOR_DIAG * ax && - (mSnapPositive - ? deltaY < -mMinLockSnapReverseDistance - : deltaY > mMinLockSnapReverseDistance)) { - mSnapScrollMode |= SNAP_LOCK; - } + } + } else { + if (mAverageAngle < HSLOPE_TO_START_SNAP) { + mSnapScrollMode = SNAP_X; + mSnapPositive = deltaX > 0; + mAverageAngle = (mAverageAngle + ANGLE_HORIZ) / 2; + } else if (mAverageAngle > VSLOPE_TO_START_SNAP) { + mSnapScrollMode = SNAP_Y; + mSnapPositive = deltaY > 0; + mAverageAngle = (mAverageAngle + ANGLE_VERT) / 2; } } if (mSnapScrollMode != SNAP_NONE) { @@ -6008,13 +6036,9 @@ public class WebView extends AbsoluteLayout deltaX = 0; } } + mLastTouchX = x; + mLastTouchY = y; if ((deltaX | deltaY) != 0) { - if (deltaX != 0) { - mLastTouchX = x; - } - if (deltaY != 0) { - mLastTouchY = y; - } mHeldMotionless = MOTIONLESS_FALSE; } mLastTouchTime = eventTime; @@ -6324,8 +6348,8 @@ public class WebView extends AbsoluteLayout private void startTouch(float x, float y, long eventTime) { // Remember where the motion event started - mLastTouchX = Math.round(x); - mLastTouchY = Math.round(y); + mStartTouchX = mLastTouchX = Math.round(x); + mStartTouchY = mLastTouchY = Math.round(y); mLastTouchTime = eventTime; mVelocityTracker = VelocityTracker.obtain(); mSnapScrollMode = SNAP_NONE; @@ -6504,6 +6528,7 @@ public class WebView extends AbsoluteLayout private boolean mMapTrackballToArrowKeys = true; private DrawData mDelaySetPicture; + private DrawData mLoadedPicture; public void setMapTrackballToArrowKeys(boolean setMap) { checkThread(); @@ -6838,11 +6863,6 @@ public class WebView extends AbsoluteLayout vx = 0; } } - if (true /* EMG release: make our fling more like Maps' */) { - // maps cuts their velocity in half - vx = vx * 3 / 4; - vy = vy * 3 / 4; - } if ((maxX == 0 && vy == 0) || (maxY == 0 && vx == 0)) { WebViewCore.resumePriority(); if (!mSelectingText) { @@ -7282,7 +7302,6 @@ public class WebView extends AbsoluteLayout if (measuredHeight > heightSize) { measuredHeight = heightSize; mHeightCanMeasure = false; - } else if (measuredHeight < heightSize) { measuredHeight |= MEASURED_STATE_TOO_SMALL; } } @@ -8054,7 +8073,7 @@ public class WebView extends AbsoluteLayout case NEW_PICTURE_MSG_ID: { // called for new content final WebViewCore.DrawData draw = (WebViewCore.DrawData) msg.obj; - setNewPicture(draw); + setNewPicture(draw, true); break; } case WEBCORE_INITIALIZED_MSG_ID: @@ -8064,7 +8083,7 @@ public class WebView extends AbsoluteLayout AssetManager am = mContext.getAssets(); nativeCreate(msg.arg1, drawableDir, am); if (mDelaySetPicture != null) { - setNewPicture(mDelaySetPicture); + setNewPicture(mDelaySetPicture, true); mDelaySetPicture = null; } break; @@ -8377,11 +8396,11 @@ public class WebView extends AbsoluteLayout } } - void setNewPicture(final WebViewCore.DrawData draw) { + void setNewPicture(final WebViewCore.DrawData draw, boolean updateBaseLayer) { if (mNativeClass == 0) { if (mDelaySetPicture != null) { - throw new IllegalStateException( - "Tried to setNewPicture with a delay picture already set! (memory leak)"); + throw new IllegalStateException("Tried to setNewPicture with" + + " a delay picture already set! (memory leak)"); } // Not initialized yet, delay set mDelaySetPicture = draw; @@ -8389,9 +8408,11 @@ public class WebView extends AbsoluteLayout } WebViewCore.ViewState viewState = draw.mViewState; boolean isPictureAfterFirstLayout = viewState != null; - setBaseLayer(draw.mBaseLayer, draw.mInvalRegion, - getSettings().getShowVisualIndicator(), - isPictureAfterFirstLayout); + if (updateBaseLayer) { + setBaseLayer(draw.mBaseLayer, draw.mInvalRegion, + getSettings().getShowVisualIndicator(), + isPictureAfterFirstLayout); + } final Point viewSize = draw.mViewSize; if (isPictureAfterFirstLayout) { // Reset the last sent data here since dealing with new page. @@ -9013,8 +9034,9 @@ public class WebView extends AbsoluteLayout /** * Update our cache with updatedText. * @param updatedText The new text to put in our cache. + * @hide */ - /* package */ void updateCachedTextfield(String updatedText) { + protected void updateCachedTextfield(String updatedText) { // Also place our generation number so that when we look at the cache // we recognize that it is up to date. nativeUpdateCachedTextfield(updatedText, mTextGeneration); diff --git a/core/java/android/webkit/WebViewClient.java b/core/java/android/webkit/WebViewClient.java index 65026a5d02ac..d3be2bf1a8d6 100644 --- a/core/java/android/webkit/WebViewClient.java +++ b/core/java/android/webkit/WebViewClient.java @@ -30,7 +30,7 @@ public class WebViewClient { * proper handler for the url. If WebViewClient is provided, return true * means the host application handles the url, while return false means the * current WebView handles the url. - * + * * @param view The WebView that is initiating the callback. * @param url The url to be loaded. * @return True if the host application wants to leave the current WebView @@ -46,7 +46,7 @@ public class WebViewClient { * framesets will call onPageStarted one time for the main frame. This also * means that onPageStarted will not be called when the contents of an * embedded frame changes, i.e. clicking a link whose target is an iframe. - * + * * @param view The WebView that is initiating the callback. * @param url The url to be loaded. * @param favicon The favicon for this page if it already exists in the @@ -60,7 +60,7 @@ public class WebViewClient { * is called only for main frame. When onPageFinished() is called, the * rendering picture may not be updated yet. To get the notification for the * new Picture, use {@link WebView.PictureListener#onNewPicture}. - * + * * @param view The WebView that is initiating the callback. * @param url The url of the page. */ @@ -70,7 +70,7 @@ public class WebViewClient { /** * Notify the host application that the WebView will load the resource * specified by the given url. - * + * * @param view The WebView that is initiating the callback. * @param url The url of the resource the WebView will load. */ @@ -102,7 +102,7 @@ public class WebViewClient { * HTTP redirects. As the host application if it would like to continue * trying to load the resource. The default behavior is to send the cancel * message. - * + * * @param view The WebView that is initiating the callback. * @param cancelMsg The message to send if the host wants to cancel * @param continueMsg The message to send if the host wants to continue @@ -164,7 +164,7 @@ public class WebViewClient { * As the host application if the browser should resend data as the * requested page was a result of a POST. The default is to not resend the * data. - * + * * @param view The WebView that is initiating the callback. * @param dontResend The message to send if the browser should not resend * @param resend The message to send if the browser should resend data @@ -176,7 +176,7 @@ public class WebViewClient { /** * Notify the host application to update its visited links database. - * + * * @param view The WebView that is initiating the callback. * @param url The url being visited. * @param isReload True if this url is being reloaded. @@ -186,12 +186,12 @@ public class WebViewClient { } /** - * Notify the host application to handle a ssl certificate error request + * Notify the host application to handle a SSL certificate error request * (display the error to the user and ask whether to proceed or not). The * host application has to call either handler.cancel() or handler.proceed() * as the connection is suspended and waiting for the response. The default * behavior is to cancel the load. - * + * * @param view The WebView that is initiating the callback. * @param handler An SslErrorHandler object that will handle the user's * response. @@ -203,9 +203,29 @@ public class WebViewClient { } /** + * Notify the host application to handle a SSL client certificate + * request (display the request to the user and ask whether to + * proceed with a client certificate or not). The host application + * has to call either handler.cancel() or handler.proceed() as the + * connection is suspended and waiting for the response. The + * default behavior is to cancel, returning no client certificate. + * + * @param view The WebView that is initiating the callback. + * @param handler An ClientCertRequestHandler object that will + * handle the user's response. + * @param host_and_port The host and port of the requesting server. + * + * @hide + */ + public void onReceivedClientCertRequest(WebView view, + ClientCertRequestHandler handler, String host_and_port) { + handler.cancel(); + } + + /** * Notify the host application to handle an authentication request. The * default behavior is to cancel the request. - * + * * @param view The WebView that is initiating the callback. * @param handler The HttpAuthHandler that will handle the user's response. * @param host The host requiring authentication. @@ -223,7 +243,7 @@ public class WebViewClient { * true, WebView will not handle the key event. If return false, WebView * will always handle the key event, so none of the super in the view chain * will see the key event. The default behavior returns false. - * + * * @param view The WebView that is initiating the callback. * @param event The key event. * @return True if the host application wants to handle the key event @@ -239,7 +259,7 @@ public class WebViewClient { * or if shouldOverrideKeyEvent returns true. This is called asynchronously * from where the key is dispatched. It gives the host application an chance * to handle the unhandled key events. - * + * * @param view The WebView that is initiating the callback. * @param event The key event. */ @@ -249,7 +269,7 @@ public class WebViewClient { /** * Notify the host application that the scale applied to the WebView has * changed. - * + * * @param view he WebView that is initiating the callback. * @param oldScale The old scale factor * @param newScale The new scale factor diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java index 16e457103fa6..06a61bdceb21 100644 --- a/core/java/android/webkit/WebViewCore.java +++ b/core/java/android/webkit/WebViewCore.java @@ -1141,16 +1141,13 @@ public final class WebViewCore { if (baseUrl != null) { int i = baseUrl.indexOf(':'); if (i > 0) { - /* - * In 1.0, {@link - * WebView#loadDataWithBaseURL} can access - * local asset files as long as the data is - * valid. In the new WebKit, the restriction - * is tightened. To be compatible with 1.0, - * we automatically add the scheme of the - * baseUrl for local access as long as it is - * not http(s)/ftp(s)/about/javascript - */ + // In 1.0, WebView.loadDataWithBaseURL() could access local + // asset files using 'file' scheme URLs as long as the data is + // valid. Later versions of WebKit have tightened the + // restriction around when pages can access such local URLs. + // To maintain compatibility with 1.0, we register the scheme of + // the baseUrl to be considered local, as long as it is not + // http(s)/ftp(s)/about/javascript. String scheme = baseUrl.substring(0, i); if (!scheme.startsWith("http") && !scheme.startsWith("ftp") && @@ -1903,7 +1900,7 @@ public final class WebViewCore { width = mViewportWidth; } else { // For mobile web site. - width = viewWidth; + width = Math.round(mWebView.getViewWidth() / mWebView.getDefaultZoomScale()); } } return width; diff --git a/core/java/android/webkit/ZoomManager.java b/core/java/android/webkit/ZoomManager.java index 780339143620..883656bd6fae 100644 --- a/core/java/android/webkit/ZoomManager.java +++ b/core/java/android/webkit/ZoomManager.java @@ -634,8 +634,17 @@ class ZoomManager { } else { newTextWrapScale = mActualScale; } + final boolean firstTimeReflow = !exceedsMinScaleIncrement(mActualScale, mTextWrapScale); + if (firstTimeReflow || mInZoomOverview) { + // In case first time reflow or in zoom overview mode, let reflow and zoom + // happen at the same time. + mTextWrapScale = newTextWrapScale; + } if (settings.isNarrowColumnLayout() - && exceedsMinScaleIncrement(mTextWrapScale, newTextWrapScale)) { + && exceedsMinScaleIncrement(mTextWrapScale, newTextWrapScale) + && !firstTimeReflow + && !mInZoomOverview) { + // Reflow only. mTextWrapScale = newTextWrapScale; refreshZoomScale(true); } else if (!mInZoomOverview && willScaleTriggerZoom(getZoomOverviewScale())) { @@ -982,16 +991,16 @@ class ZoomManager { settings.getUseFixedViewport() && (mInitialZoomOverview || mInZoomOverview)) { // Keep mobile site's text wrap scale unchanged. For mobile sites, - // the text wrap scale is the same as zoom overview scale, which is 1.0f. - if (exceedsMinScaleIncrement(mTextWrapScale, 1.0f) || - exceedsMinScaleIncrement(newZoomOverviewScale, 1.0f)) { + // the text wrap scale is the same as zoom overview scale. + if (exceedsMinScaleIncrement(mTextWrapScale, mDefaultScale) || + exceedsMinScaleIncrement(newZoomOverviewScale, mDefaultScale)) { mTextWrapScale = getReadingLevelScale(); } else { mTextWrapScale = newZoomOverviewScale; } } - if (!mMinZoomScaleFixed) { + if (!mMinZoomScaleFixed || settings.getUseWideViewPort()) { mMinZoomScale = newZoomOverviewScale; mMaxZoomScale = Math.max(mMaxZoomScale, mMinZoomScale); } @@ -1004,9 +1013,9 @@ class ZoomManager { // Make sure mobile sites are correctly handled since mobile site will // change content width after rotating. boolean mobileSiteInOverview = mInZoomOverview && - !exceedsMinScaleIncrement(newZoomOverviewScale, 1.0f); + !exceedsMinScaleIncrement(newZoomOverviewScale, mDefaultScale); if (!mWebView.drawHistory() && - (scaleLessThanOverview || + ((scaleLessThanOverview && settings.getUseWideViewPort())|| ((mInitialZoomOverview || mobileSiteInOverview) && scaleHasDiff && zoomOverviewWidthChanged))) { mInitialZoomOverview = false; @@ -1062,7 +1071,8 @@ class ZoomManager { updateZoomRange(viewState, viewSize.x, drawData.mMinPrefWidth); setupZoomOverviewWidth(drawData, mWebView.getViewWidth()); final float overviewScale = getZoomOverviewScale(); - if (!mMinZoomScaleFixed) { + WebSettings settings = mWebView.getSettings(); + if (!mMinZoomScaleFixed || settings.getUseWideViewPort()) { mMinZoomScale = (mInitialScale > 0) ? Math.min(mInitialScale, overviewScale) : overviewScale; mMaxZoomScale = Math.max(mMaxZoomScale, mMinZoomScale); @@ -1070,8 +1080,6 @@ class ZoomManager { if (!mWebView.drawHistory()) { float scale; - WebSettings settings = mWebView.getSettings(); - if (mInitialScale > 0) { scale = mInitialScale; } else if (viewState.mViewScale > 0) { diff --git a/core/java/android/widget/GridLayout.java b/core/java/android/widget/GridLayout.java index b99cd7fabcfb..bda82a384254 100644 --- a/core/java/android/widget/GridLayout.java +++ b/core/java/android/widget/GridLayout.java @@ -48,11 +48,11 @@ import static java.lang.Math.min; * <p> * The grid is composed of a set of infinitely thin lines that separate the * viewing area into <em>cells</em>. Throughout the API, grid lines are referenced - * by grid <em>indices</em>. A grid with <code>N</code> columns - * has <code>N + 1</code> grid indices that run from <code>0</code> - * through <code>N</code> inclusive. Regardless of how GridLayout is - * configured, grid index <code>0</code> is fixed to the leading edge of the - * container and grid index <code>N</code> is fixed to its trailing edge + * by grid <em>indices</em>. A grid with {@code N} columns + * has {@code N + 1} grid indices that run from {@code 0} + * through {@code N} inclusive. Regardless of how GridLayout is + * configured, grid index {@code 0} is fixed to the leading edge of the + * container and grid index {@code N} is fixed to its trailing edge * (after padding is taken into account). * * <h4>Row and Column Groups</h4> @@ -231,8 +231,7 @@ public class GridLayout extends ViewGroup { /** * Returns the current orientation. * - * @return either {@link #HORIZONTAL} or {@link #VERTICAL}. The default - * is {@link #HORIZONTAL}. + * @return either {@link #HORIZONTAL} or {@link #VERTICAL} * * @see #setOrientation(int) * @@ -246,8 +245,10 @@ public class GridLayout extends ViewGroup { * The orientation property does not affect layout. Orientation is used * only to generate default row/column indices when they are not specified * by a component's layout parameters. + * <p> + * The default value of this property is {@link #HORIZONTAL}. * - * @param orientation the orientation, either {@link #HORIZONTAL} or {@link #VERTICAL}. + * @param orientation either {@link #HORIZONTAL} or {@link #VERTICAL} * * @see #getOrientation() * @@ -281,7 +282,7 @@ public class GridLayout extends ViewGroup { * only to generate default row/column indices when they are not specified * by a component's layout parameters. * - * @param rowCount the number of rows. + * @param rowCount the number of rows * * @see #getRowCount() * @see LayoutParams#rowGroup @@ -328,7 +329,7 @@ public class GridLayout extends ViewGroup { * Returns whether or not this GridLayout will allocate default margins when no * corresponding layout parameters are defined. * - * @return true if default margins should be allocated. + * @return {@code true} if default margins should be allocated * * @see #setUseDefaultMargins(boolean) * @@ -339,18 +340,20 @@ public class GridLayout extends ViewGroup { } /** - * When true, GridLayout allocates default margins around children + * When {@code true}, GridLayout allocates default margins around children * based on the child's visual characteristics. Each of the * margins so defined may be independently overridden by an assignment * to the appropriate layout parameter. * <p> - * When false, the default value of all margins is zero. + * When {@code false}, the default value of all margins is zero. * <p> - * When setting to true, consider setting the value of the + * When setting to {@code true}, consider setting the value of the * {@link #setMarginsIncludedInAlignment(boolean) marginsIncludedInAlignment} - * property to false. + * property to {@code false}. + * <p> + * The default value of this property is {@code false}. * - * @param useDefaultMargins use true to make GridLayout allocate default margins + * @param useDefaultMargins use {@code true} to make GridLayout allocate default margins * * @see #getUseDefaultMargins() * @see #setMarginsIncludedInAlignment(boolean) @@ -374,7 +377,7 @@ public class GridLayout extends ViewGroup { * * @see #setMarginsIncludedInAlignment(boolean) * - * @return true if alignment is between edges including margins. + * @return {@code true} if alignment is between edges including margins * * @attr ref android.R.styleable#GridLayout_marginsIncludedInAlignment */ @@ -383,12 +386,14 @@ public class GridLayout extends ViewGroup { } /** - * When true, the bounds of a view are extended outwards according to its + * When {@code true}, the bounds of a view are extended outwards according to its * margins before the edges of the resulting rectangle are aligned. - * When false, alignment occurs between the bounds of the view - i.e. + * When {@code false}, alignment occurs between the bounds of the view - i.e. * {@link #LEFT} alignment means align the left edges of the view. + * <p> + * The default value of this property is {@code true}. * - * @param marginsIncludedInAlignment true if alignment is between edges including margins. + * @param marginsIncludedInAlignment {@code true} if alignment between edges includes margins * * @see #getMarginsIncludedInAlignment() * @@ -402,8 +407,8 @@ public class GridLayout extends ViewGroup { /** * Returns whether or not row boundaries are ordered by their grid indices. * - * @return true if row boundaries must appear in the order of their indices, false otherwise. - * The default is false. + * @return {@code true} if row boundaries must appear in the order of their indices, + * {@code false} otherwise * * @see #setRowOrderPreserved(boolean) * @@ -414,23 +419,25 @@ public class GridLayout extends ViewGroup { } /** - * When this property is <code>false</code>, the default state, GridLayout + * When this property is {@code false}, the default state, GridLayout * is at liberty to choose an order that better suits the heights of its children. <p> - * When this property is <code>true</code>, GridLayout is forced to place the row boundaries + * When this property is {@code true}, GridLayout is forced to place the row boundaries * so that their associated grid indices are in ascending order in the view. * <p> * GridLayout implements this specification by creating ordering constraints between * the variables that represent the locations of the row boundaries. * - * When this property is <code>true</code>, constraints are added for each pair of consecutive - * indices: i.e. between row boundaries: <code>[0..1], [1..2], [3..4],...</code> etc. + * When this property is {@code true}, constraints are added for each pair of consecutive + * indices: i.e. between row boundaries: {@code [0..1], [1..2], [2..3],...} etc. * - * When the property is <code>false</code>, the ordering constraints are placed + * When the property is {@code false}, the ordering constraints are placed * only between boundaries that separate opposing edges of the layout's children. - * - * @param rowOrderPreserved use true to force GridLayout to respect the order - * of row boundaries. + * <p> + * The default value of this property is {@code false}. + + * @param rowOrderPreserved {@code true} to force GridLayout to respect the order + * of row boundaries * * @see #isRowOrderPreserved() * @@ -445,8 +452,8 @@ public class GridLayout extends ViewGroup { /** * Returns whether or not column boundaries are ordered by their grid indices. * - * @return true if column boundaries must appear in the order of their indices, false otherwise. - * The default is false. + * @return {@code true} if column boundaries must appear in the order of their indices, + * {@code false} otherwise * * @see #setColumnOrderPreserved(boolean) * @@ -457,22 +464,24 @@ public class GridLayout extends ViewGroup { } /** - * When this property is <code>false</code>, the default state, GridLayout + * When this property is {@code false}, the default state, GridLayout * is at liberty to choose an order that better suits the widths of its children. <p> - * When this property is <code>true</code>, GridLayout is forced to place the column boundaries + * When this property is {@code true}, GridLayout is forced to place the column boundaries * so that their associated grid indices are in ascending order in the view. * <p> * GridLayout implements this specification by creating ordering constraints between * the variables that represent the locations of the column boundaries. * - * When this property is <code>true</code>, constraints are added for each pair of consecutive - * indices: i.e. between column boundaries: <code>[0..1], [1..2], [3..4],...</code> etc. + * When this property is {@code true}, constraints are added for each pair of consecutive + * indices: i.e. between column boundaries: {@code [0..1], [1..2], [2..3],...} etc. * - * When the property is <code>false</code>, the ordering constraints are placed + * When the property is {@code false}, the ordering constraints are placed * only between boundaries that separate opposing edges of the layout's children. + * <p> + * The default value of this property is {@code false}. * - * @param columnOrderPreserved use true to force GridLayout to respect the order + * @param columnOrderPreserved use {@code true} to force GridLayout to respect the order * of column boundaries. * * @see #isColumnOrderPreserved() @@ -527,70 +536,76 @@ public class GridLayout extends ViewGroup { return margin == UNDEFINED ? getDefaultMarginValue(view, lp, leading, horizontal) : margin; } - private static boolean isUndefined(Interval span) { - return span.min == UNDEFINED || span.max == UNDEFINED; + private static int valueIfDefined(int value, int defaultValue) { + return (value != UNDEFINED) ? value : defaultValue; } + // install default indices for cells that don't define them private void validateLayoutParams() { - // install default indices for cells if *none* are defined - if (mHorizontalAxis.maxIndex1() == UNDEFINED || (mVerticalAxis.maxIndex1() == UNDEFINED)) { - boolean horizontal = mOrientation == HORIZONTAL; - int count = horizontal ? mHorizontalAxis.count : mVerticalAxis.count; - if (count == UNDEFINED) { - count = Integer.MAX_VALUE; - } - int x = 0; - int y = 0; - int maxSize = 0; - for (int i = 0, size = getChildCount(); i < size; i++) { - LayoutParams lp = getLayoutParams1(getChildAt(i)); + new Object() { + public int maxSize = 0; - Interval hSpan = lp.columnGroup.span; - int cellWidth = hSpan.size(); + private int valueIfDefined2(int value, int defaultValue) { + if (value != UNDEFINED) { + maxSize = 0; + return value; + } else { + return defaultValue; + } + } - Interval vSpan = lp.rowGroup.span; - int cellHeight = vSpan.size(); + { + final boolean horizontal = (mOrientation == HORIZONTAL); + final int axis = horizontal ? mHorizontalAxis.count : mVerticalAxis.count; + final int count = valueIfDefined(axis, Integer.MAX_VALUE); - if (horizontal) { - if (x + cellWidth > count) { - x = 0; - y += maxSize; - maxSize = 0; - } - } else { - if (y + cellHeight > count) { - y = 0; - x += maxSize; - maxSize = 0; + int row = 0; + int col = 0; + for (int i = 0, N = getChildCount(); i < N; i++) { + LayoutParams lp = getLayoutParams1(getChildAt(i)); + + Group colGroup = lp.columnGroup; + Interval cols = colGroup.span; + int colSpan = cols.size(); + + Group rowGroup = lp.rowGroup; + Interval rows = rowGroup.span; + int rowSpan = rows.size(); + + if (horizontal) { + row = valueIfDefined2(rows.min, row); + + int newCol = valueIfDefined(cols.min, (col + colSpan > count) ? 0 : col); + if (newCol < col) { + row += maxSize; + maxSize = 0; + } + col = newCol; + maxSize = max(maxSize, rowSpan); + } else { + col = valueIfDefined2(cols.min, col); + + int newRow = valueIfDefined(rows.min, (row + rowSpan > count) ? 0 : row); + if (newRow < row) { + col += maxSize; + maxSize = 0; + } + row = newRow; + maxSize = max(maxSize, colSpan); } - } - lp.setHorizontalGroupSpan(new Interval(x, x + cellWidth)); - lp.setVerticalGroupSpan(new Interval(y, y + cellHeight)); - if (horizontal) { - x = x + cellWidth; - } else { - y = y + cellHeight; - } - maxSize = max(maxSize, horizontal ? cellHeight : cellWidth); - } - } else { - /* - At least one row and one column index have been defined. - Assume missing row/cols are in error and set them to zero so that - they will display top/left and the developer can add the right indices. - Without this UNDEFINED would cause ArrayIndexOutOfBoundsException. - */ - for (int i = 0, size = getChildCount(); i < size; i++) { - LayoutParams lp = getLayoutParams1(getChildAt(i)); - if (isUndefined(lp.columnGroup.span)) { - lp.setHorizontalGroupSpan(LayoutParams.DEFAULT_SPAN); - } - if (isUndefined(lp.rowGroup.span)) { - lp.setVerticalGroupSpan(LayoutParams.DEFAULT_SPAN); + lp.setColumnGroupSpan(new Interval(col, col + colSpan)); + lp.setRowGroupSpan(new Interval(row, row + rowSpan)); + + if (horizontal) { + col = col + colSpan; + } else { + row = row + rowSpan; + } } } - } + }; + invalidateStructure(); } private void invalidateStructure() { @@ -767,15 +782,6 @@ public class GridLayout extends ViewGroup { return result; } - private int getAlignmentValue(Alignment alignment, View c, int dim, boolean horizontal, View c1) { - int result = alignment.getAlignmentValue(c, dim); - if (mMarginsIncludedInAlignment) { - int leadingMargin = getMargin(c1, true, horizontal); - return result + leadingMargin; - } - return result; - } - @Override public void requestLayout() { super.requestLayout(); @@ -835,18 +841,39 @@ public class GridLayout extends ViewGroup { int dx, dy; + Bounds colBounds = mHorizontalAxis.getGroupBounds().getValue(i); + Bounds rowBounds = mVerticalAxis.getGroupBounds().getValue(i); + + // Gravity offsets: the location of the alignment group relative to its cell group. + int c2ax = protect(hAlignment.getAlignmentValue(null, cellWidth - colBounds.size())); + int c2ay = protect(vAlignment.getAlignmentValue(null, cellHeight - rowBounds.size())); + if (mMarginsIncludedInAlignment) { - dx = protect(hAlignment.getAlignmentValue(view, cellWidth - pWidth)); - dy = protect(vAlignment.getAlignmentValue(view, cellHeight - pHeight)); - } else { - Bounds colBounds = mHorizontalAxis.getGroupBounds().getValue(i); - Bounds rowBounds = mVerticalAxis.getGroupBounds().getValue(i); + int leftMargin = getMargin(view, true, true); + int topMargin = getMargin(view, true, false); + int rightMargin = getMargin(view, false, true); + int bottomMargin = getMargin(view, false, false); - int mx = protect(hAlignment.getAlignmentValue(null, cellWidth - colBounds.size())); - int my = protect(vAlignment.getAlignmentValue(null, cellHeight - rowBounds.size())); + // Same calculation as getMeasurementIncludingMargin() + int measuredWidth = leftMargin + pWidth + rightMargin; + int measuredHeight = topMargin + pHeight + bottomMargin; - dx = mx + -colBounds.below - hAlignment.getAlignmentValue(view, pWidth); - dy = my + -rowBounds.below - vAlignment.getAlignmentValue(view, pHeight); + // Alignment offsets: the location of the view relative to its alignment group. + int a2vx = colBounds.before - hAlignment.getAlignmentValue(view, measuredWidth); + int a2vy = rowBounds.before - vAlignment.getAlignmentValue(view, measuredHeight); + + dx = c2ax + a2vx + leftMargin; + dy = c2ay + a2vy + topMargin; + + cellWidth -= leftMargin + rightMargin; + cellHeight -= topMargin + bottomMargin; + } else { + // Alignment offsets: the location of the view relative to its alignment group. + int a2vx = colBounds.before - hAlignment.getAlignmentValue(view, pWidth); + int a2vy = rowBounds.before - vAlignment.getAlignmentValue(view, pHeight); + + dx = c2ax + a2vx; + dy = c2ay + a2vy; } int width = hAlignment.getSizeInCell(view, pWidth, cellWidth); @@ -906,13 +933,11 @@ public class GridLayout extends ViewGroup { this.horizontal = horizontal; } - private int maxIndex(boolean internal) { + private int maxIndex() { // note the number Integer.MIN_VALUE + 1 comes up in undefined cells int count = -1; for (int i = 0, size = getChildCount(); i < size; i++) { - LayoutParams params = internal ? - getLayoutParams1(getChildAt(i)) : - getLayoutParams(getChildAt(i)); + LayoutParams params = getLayoutParams(getChildAt(i)); Group g = horizontal ? params.columnGroup : params.rowGroup; count = max(count, g.span.min); count = max(count, g.span.max); @@ -920,13 +945,9 @@ public class GridLayout extends ViewGroup { return count == -1 ? UNDEFINED : count; } - private int maxIndex1() { - return maxIndex(true); - } - public int getCount() { - if (!countWasExplicitySet && !countValid) { - count = max(0, maxIndex(false)); // if there are no cells, the count is zero + if (!countValid) { + count = max(0, maxIndex()); // if there are no cells, the count is zero countValid = true; } return count; @@ -974,8 +995,8 @@ public class GridLayout extends ViewGroup { int size = getMeasurementIncludingMargin(c, horizontal, PRF); // todo test this works correctly when the returned value is UNDEFINED - int below = getAlignmentValue(g.alignment, c, size, horizontal, c); - bounds.include(-below, size - below); + int before = g.alignment.getAlignmentValue(c, size); + bounds.include(before, size - before); } } @@ -1332,7 +1353,7 @@ public class GridLayout extends ViewGroup { if (!mMarginsIncludedInAlignment) { margin = (leading ? leadingMargins : trailingMargins)[index]; } else { - margin = getMargin(view, leading, horizontal); + margin = 0; } return leading ? (location + margin) : (location - margin); } @@ -1370,7 +1391,7 @@ public class GridLayout extends ViewGroup { private float[] getWeights() { if (weights == null) { - int N = getCount() + 1; + int N = getCount(); weights = new float[N]; } computeWeights(); @@ -1403,7 +1424,7 @@ public class GridLayout extends ViewGroup { float[] weights = getWeights(); float totalWeight = sum(weights); - if (totalWeight == 0f) { + if (totalWeight == 0f && weights.length > 0) { weights[weights.length - 1] = 1; totalWeight = 1; } @@ -1411,11 +1432,12 @@ public class GridLayout extends ViewGroup { int[] locations = getLocations(); int cumulativeDelta = 0; - for (int i = 0; i < locations.length; i++) { + // note |weights| = |locations| - 1 + for (int i = 0; i < weights.length; i++) { float weight = weights[i]; int delta = (int) (totalDelta * weight / totalWeight); cumulativeDelta += delta; - locations[i] = mins[i] + cumulativeDelta; + locations[i + 1] = mins[i + 1] + cumulativeDelta; totalDelta -= delta; totalWeight -= weight; @@ -1474,26 +1496,26 @@ public class GridLayout extends ViewGroup { * <li>{@link #height} = {@link #WRAP_CONTENT}</li> * <li>{@link #topMargin} = 0 when * {@link GridLayout#setUseDefaultMargins(boolean) useDefaultMargins} is - * <code>false</code>; otherwise {@link #UNDEFINED}, to + * {@code false}; otherwise {@link #UNDEFINED}, to * indicate that a default value should be computed on demand. </li> * <li>{@link #leftMargin} = 0 when * {@link GridLayout#setUseDefaultMargins(boolean) useDefaultMargins} is - * <code>false</code>; otherwise {@link #UNDEFINED}, to + * {@code false}; otherwise {@link #UNDEFINED}, to * indicate that a default value should be computed on demand. </li> * <li>{@link #bottomMargin} = 0 when * {@link GridLayout#setUseDefaultMargins(boolean) useDefaultMargins} is - * <code>false</code>; otherwise {@link #UNDEFINED}, to + * {@code false}; otherwise {@link #UNDEFINED}, to * indicate that a default value should be computed on demand. </li> * <li>{@link #rightMargin} = 0 when * {@link GridLayout#setUseDefaultMargins(boolean) useDefaultMargins} is - * <code>false</code>; otherwise {@link #UNDEFINED}, to + * {@code false}; otherwise {@link #UNDEFINED}, to * indicate that a default value should be computed on demand. </li> - * <li>{@link #rowGroup}<code>.span</code> = <code>[0, 1]</code> </li> - * <li>{@link #rowGroup}<code>.alignment</code> = {@link #BASELINE} </li> - * <li>{@link #columnGroup}<code>.span</code> = <code>[0, 1]</code> </li> - * <li>{@link #columnGroup}<code>.alignment</code> = {@link #LEFT} </li> - * <li>{@link #rowWeight} = <code>0f</code> </li> - * <li>{@link #columnWeight} = <code>0f</code> </li> + * <li>{@link #rowGroup}{@code .span} = {@code [0, 1]} </li> + * <li>{@link #rowGroup}{@code .alignment} = {@link #BASELINE} </li> + * <li>{@link #columnGroup}{@code .span} = {@code [0, 1]} </li> + * <li>{@link #columnGroup}{@code .alignment} = {@link #LEFT} </li> + * <li>{@link #rowWeight} = {@code 0f} </li> + * <li>{@link #columnWeight} = {@code 0f} </li> * </ul> * * @attr ref android.R.styleable#GridLayout_Layout_layout_row @@ -1513,22 +1535,22 @@ public class GridLayout extends ViewGroup { private static final int DEFAULT_MARGIN = UNDEFINED; private static final int DEFAULT_ROW = UNDEFINED; private static final int DEFAULT_COLUMN = UNDEFINED; - private static final Interval DEFAULT_SPAN = new Interval(0, 1); + private static final Interval DEFAULT_SPAN = new Interval(UNDEFINED, UNDEFINED + 1); private static final int DEFAULT_SPAN_SIZE = DEFAULT_SPAN.size(); - private static final Alignment DEFAULT_HORIZONTAL_ALIGNMENT = LEFT; - private static final Alignment DEFAULT_VERTCIAL_ALGIGNMENT = BASELINE; - private static final Group DEFAULT_HORIZONTAL_GROUP = - new Group(DEFAULT_SPAN, DEFAULT_HORIZONTAL_ALIGNMENT); - private static final Group DEFAULT_VERTICAL_GROUP = - new Group(DEFAULT_SPAN, DEFAULT_VERTCIAL_ALGIGNMENT); + private static final Alignment DEFAULT_COLUMN_ALIGNMENT = LEFT; + private static final Alignment DEFAULT_ROW_ALIGNMENT = BASELINE; + private static final Group DEFAULT_COLUMN_GROUP = + new Group(DEFAULT_SPAN, DEFAULT_COLUMN_ALIGNMENT); + private static final Group DEFAULT_ROW_GROUP = + new Group(DEFAULT_SPAN, DEFAULT_ROW_ALIGNMENT); private static final int DEFAULT_WEIGHT_0 = 0; private static final int DEFAULT_WEIGHT_1 = 1; // Misc private static final Rect CONTAINER_BOUNDS = new Rect(0, 0, 2, 2); - private static final Alignment[] HORIZONTAL_ALIGNMENTS = { LEFT, CENTER, RIGHT }; - private static final Alignment[] VERTICAL_ALIGNMENTS = { TOP, CENTER, BOTTOM }; + private static final Alignment[] COLUMN_ALIGNMENTS = { LEFT, CENTER, RIGHT }; + private static final Alignment[] ROW_ALIGNMENTS = { TOP, CENTER, BOTTOM }; // TypedArray indices @@ -1602,7 +1624,7 @@ public class GridLayout extends ViewGroup { * Constructs a new LayoutParams with default values as defined in {@link LayoutParams}. */ public LayoutParams() { - this(DEFAULT_HORIZONTAL_GROUP, DEFAULT_VERTICAL_GROUP); + this(DEFAULT_ROW_GROUP, DEFAULT_COLUMN_GROUP); } // Copying constructors @@ -1693,23 +1715,23 @@ public class GridLayout extends ViewGroup { // Gravity. For conversion from the static the integers defined in the Gravity class, // use Gravity.apply() to apply gravity to a view of zero size and see where it ends up. - private static Alignment getHorizontalAlignment(int gravity, int width) { + private static Alignment getColumnAlignment(int gravity, int width) { Rect r = new Rect(0, 0, 0, 0); Gravity.apply(gravity, 0, 0, CONTAINER_BOUNDS, r); - boolean fill = width == MATCH_PARENT; - Alignment defaultAlignment = fill ? FILL : DEFAULT_HORIZONTAL_ALIGNMENT; - return getAlignment(HORIZONTAL_ALIGNMENTS, FILL, r.left, r.right, + boolean fill = (width == MATCH_PARENT); + Alignment defaultAlignment = fill ? FILL : DEFAULT_COLUMN_ALIGNMENT; + return getAlignment(COLUMN_ALIGNMENTS, FILL, r.left, r.right, !definesHorizontal(gravity), defaultAlignment); } - private static Alignment getVerticalAlignment(int gravity, int height) { + private static Alignment getRowAlignment(int gravity, int height) { Rect r = new Rect(0, 0, 0, 0); Gravity.apply(gravity, 0, 0, CONTAINER_BOUNDS, r); - boolean fill = height == MATCH_PARENT; - Alignment defaultAlignment = fill ? FILL : DEFAULT_VERTCIAL_ALGIGNMENT; - return getAlignment(VERTICAL_ALIGNMENTS, FILL, r.top, r.bottom, + boolean fill = (height == MATCH_PARENT); + Alignment defaultAlignment = fill ? FILL : DEFAULT_ROW_ALIGNMENT; + return getAlignment(ROW_ALIGNMENTS, FILL, r.top, r.bottom, !definesVertical(gravity), defaultAlignment); } @@ -1725,13 +1747,13 @@ public class GridLayout extends ViewGroup { int column = a.getInteger(COLUMN, DEFAULT_COLUMN); int columnSpan = a.getInteger(COLUMN_SPAN, DEFAULT_SPAN_SIZE); Interval hSpan = new Interval(column, column + columnSpan); - this.columnGroup = new Group(hSpan, getHorizontalAlignment(gravity, width)); + this.columnGroup = new Group(hSpan, getColumnAlignment(gravity, width)); this.columnWeight = a.getFloat(COLUMN_WEIGHT, getDefaultWeight(width)); int row = a.getInteger(ROW, DEFAULT_ROW); int rowSpan = a.getInteger(ROW_SPAN, DEFAULT_SPAN_SIZE); Interval vSpan = new Interval(row, row + rowSpan); - this.rowGroup = new Group(vSpan, getVerticalAlignment(gravity, height)); + this.rowGroup = new Group(vSpan, getRowAlignment(gravity, height)); this.rowWeight = a.getFloat(ROW_WEIGHT, getDefaultWeight(height)); } finally { a.recycle(); @@ -1739,15 +1761,16 @@ public class GridLayout extends ViewGroup { } /** - * Describes how the child views are positioned. Default is <code>LEFT | BASELINE</code>. + * Describes how the child views are positioned. Default is {@code LEFT | BASELINE}. + * See {@link android.view.Gravity}. * - * @param gravity the new gravity. See {@link android.view.Gravity}. + * @param gravity the new gravity value * * @attr ref android.R.styleable#GridLayout_Layout_layout_gravity */ public void setGravity(int gravity) { - columnGroup = columnGroup.copyWriteAlignment(getHorizontalAlignment(gravity, width)); - rowGroup = rowGroup.copyWriteAlignment(getVerticalAlignment(gravity, height)); + columnGroup = columnGroup.copyWriteAlignment(getColumnAlignment(gravity, width)); + rowGroup = rowGroup.copyWriteAlignment(getRowAlignment(gravity, height)); } @Override @@ -1756,11 +1779,11 @@ public class GridLayout extends ViewGroup { this.height = attributes.getLayoutDimension(heightAttr, DEFAULT_HEIGHT); } - private void setVerticalGroupSpan(Interval span) { + private void setRowGroupSpan(Interval span) { rowGroup = rowGroup.copyWriteSpan(span); } - private void setHorizontalGroupSpan(Interval span) { + private void setColumnGroupSpan(Interval span) { columnGroup = columnGroup.copyWriteSpan(span); } } @@ -1881,7 +1904,7 @@ public class GridLayout extends ViewGroup { /* For each Group (with a given alignment) we need to store the amount of space required - above the alignment point and the amount of space required below it. One side of this + before the alignment point and the amount of space required after it. One side of this calculation is always 0 for LEADING and TRAILING alignments but we don't make use of this. For CENTER and BASELINE alignments both sides are needed and in the BASELINE case no simple optimisations are possible. @@ -1891,37 +1914,32 @@ public class GridLayout extends ViewGroup { of the values for each View. */ private static class Bounds { - public int below; - public int above; - - private Bounds(int below, int above) { - this.below = below; - this.above = above; - } + public int before; + public int after; private Bounds() { reset(); } private void reset() { - below = Integer.MAX_VALUE; - above = Integer.MIN_VALUE; + before = Integer.MIN_VALUE; + after = Integer.MIN_VALUE; } - private void include(int below, int above) { - this.below = min(this.below, below); - this.above = max(this.above, above); + private void include(int before, int after) { + this.before = max(this.before, before); + this.after = max(this.after, after); } private int size() { - return above - below; + return before + after; } @Override public String toString() { return "Bounds{" + - "below=" + below + - ", above=" + above + + "before=" + before + + ", after=" + after + '}'; } } @@ -1934,8 +1952,8 @@ public class GridLayout extends ViewGroup { * It is not necessary to have multiple instances of Intervals which have the same * {@link #min} and {@link #max} values. * <p> - * Intervals are often written as <code>[min, max]</code> and represent the set of values - * <em>x</em> such that <em>min <= x < max</em>. + * Intervals are often written as {@code [min, max]} and represent the set of values + * {@code x} such that {@code min <= x < max}. */ /* package */ static class Interval { /** @@ -1949,10 +1967,10 @@ public class GridLayout extends ViewGroup { public final int max; /** - * Construct a new Interval, <code>interval</code>, where: + * Construct a new Interval, {@code interval}, where: * <ul> - * <li> <code>interval.min = min</code> </li> - * <li> <code>interval.max = max</code> </li> + * <li> {@code interval.min = min} </li> + * <li> {@code interval.max = max} </li> * </ul> * * @param min the minimum value. @@ -1972,13 +1990,14 @@ public class GridLayout extends ViewGroup { } /** - * Returns true if the {@link #getClass class}, {@link #min} and {@link #max} properties - * of this Interval and the supplied parameter are pairwise equal; false otherwise. + * Returns {@code true} if the {@link #getClass class}, + * {@link #min} and {@link #max} properties of this Interval and the + * supplied parameter are pairwise equal; {@code false} otherwise. * - * @param that the object to compare this interval with. + * @param that the object to compare this interval with * * @return {@code true} if the specified object is equal to this - * {@code Interval}; {@code false} otherwise. + * {@code Interval}, {@code false} otherwise. */ @Override public boolean equals(Object that) { @@ -2019,7 +2038,7 @@ public class GridLayout extends ViewGroup { * cells. * <p> * Groups are immutable and so may be shared between views with the same - * <code>span</code> and <code>alignment</code>. + * {@code span} and {@code alignment}. */ public static class Group { /** @@ -2038,14 +2057,14 @@ public class GridLayout extends ViewGroup { public final Alignment alignment; /** - * Construct a new Group, <code>group</code>, where: + * Construct a new Group, {@code group}, where: * <ul> - * <li> <code>group.span = span</code> </li> - * <li> <code>group.alignment = alignment</code> </li> + * <li> {@code group.span = span} </li> + * <li> {@code group.alignment = alignment} </li> * </ul> * - * @param span the span. - * @param alignment the alignment. + * @param span the span + * @param alignment the alignment */ /* package */ Group(Interval span, Alignment alignment) { this.span = span; @@ -2053,32 +2072,32 @@ public class GridLayout extends ViewGroup { } /** - * Construct a new Group, <code>group</code>, where: + * Construct a new Group, {@code group}, where: * <ul> - * <li> <code>group.span = [min, max]</code> </li> - * <li> <code>group.alignment = alignment</code> </li> + * <li> {@code group.span = [start, start + size]} </li> + * <li> {@code group.alignment = alignment} </li> * </ul> * - * @param min the minimum. - * @param max the maximum. - * @param alignment the alignment. + * @param start the start + * @param size the size + * @param alignment the alignment */ - public Group(int min, int max, Alignment alignment) { - this(new Interval(min, max), alignment); + public Group(int start, int size, Alignment alignment) { + this(new Interval(start, start + size), alignment); } /** - * Construct a new Group, <code>group</code>, where: + * Construct a new Group, {@code group}, where: * <ul> - * <li> <code>group.span = [min, min + 1]</code> </li> - * <li> <code>group.alignment = alignment</code> </li> + * <li> {@code group.span = [start, start + 1]} </li> + * <li> {@code group.alignment = alignment} </li> * </ul> * - * @param min the minimum. - * @param alignment the alignment. + * @param start the start index + * @param alignment the alignment */ - public Group(int min, Alignment alignment) { - this(min, min + 1, alignment); + public Group(int start, Alignment alignment) { + this(start, 1, alignment); } private Group copyWriteSpan(Interval span) { @@ -2090,13 +2109,14 @@ public class GridLayout extends ViewGroup { } /** - * Returns true if the {@link #getClass class}, {@link #alignment} and <code>span</code> - * properties of this Group and the supplied parameter are pairwise equal; false otherwise. + * Returns {@code true} if the {@link #getClass class}, {@link #alignment} and {@code span} + * properties of this Group and the supplied parameter are pairwise equal, + * {@code false} otherwise. * - * @param that the object to compare this group with. + * @param that the object to compare this group with * * @return {@code true} if the specified object is equal to this - * {@code Group}; {@code false} otherwise. + * {@code Group}; {@code false} otherwise */ @Override public boolean equals(Object that) { @@ -2153,9 +2173,9 @@ public class GridLayout extends ViewGroup { * alignment location. * For horizontal alignments measurement is made from the left edge of the component. * - * @param view the view to which this alignment should be applied. - * @param viewSize the measured size of the view. - * @return the alignment value. + * @param view the view to which this alignment should be applied + * @param viewSize the measured size of the view + * @return the alignment value */ public int getAlignmentValue(View view, int viewSize); @@ -2164,10 +2184,10 @@ public class GridLayout extends ViewGroup { * In the case of vertical alignments this method should return a height; for * horizontal alignments this method should return the width. * - * @param view the view to which this alignment should be applied. - * @param viewSize the measured size of the view. - * @param cellSize the size of the cell into which this view will be placed. - * @return the aligned size. + * @param view the view to which this alignment should be applied + * @param viewSize the measured size of the view + * @param cellSize the size of the cell into which this view will be placed + * @return the aligned size */ public int getSizeInCell(View view, int viewSize, int cellSize); } @@ -2234,13 +2254,16 @@ public class GridLayout extends ViewGroup { * @see View#getBaseline() */ public static final Alignment BASELINE = new AbstractAlignment() { - public int getAlignmentValue(View view, int viewSize) { + public int getAlignmentValue(View view, int height) { if (view == null) { return UNDEFINED; } - // todo do we need to call measure first? int baseline = view.getBaseline(); - return baseline == -1 ? UNDEFINED : baseline; + if (baseline == -1) { + return UNDEFINED; + } else { + return baseline; + } } }; diff --git a/core/java/android/widget/Switch.java b/core/java/android/widget/Switch.java index cd4b7329f57e..5c6a26f3fb10 100644 --- a/core/java/android/widget/Switch.java +++ b/core/java/android/widget/Switch.java @@ -16,8 +16,6 @@ package android.widget; -import com.android.internal.R; - import android.content.Context; import android.content.res.ColorStateList; import android.content.res.Resources; @@ -37,6 +35,8 @@ import android.view.MotionEvent; import android.view.VelocityTracker; import android.view.ViewConfiguration; +import com.android.internal.R; + /** * A Switch is a two-state toggle switch widget that can select between two * options. The user may drag the "thumb" back and forth to choose the selected option, @@ -84,6 +84,7 @@ public class Switch extends CompoundButton { private Layout mOnLayout; private Layout mOffLayout; + @SuppressWarnings("hiding") private final Rect mTempRect = new Rect(); private static final int[] CHECKED_STATE_SET = { diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index eba9d37664bc..9a5977a0b517 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -8738,10 +8738,13 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener return false; } - boolean currentWordSelected = selectCurrentWord(); - if (!currentWordSelected) { - // No word found under cursor or text selection not permitted. - return false; + if (!hasSelection()) { + // There may already be a selection on device rotation + boolean currentWordSelected = selectCurrentWord(); + if (!currentWordSelected) { + // No word found under cursor or text selection not permitted. + return false; + } } ActionMode.Callback actionModeCallback = new SelectionActionModeCallback(); @@ -9057,6 +9060,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener private int mContainerPositionX, mContainerPositionY; // Visible or not (scrolled off screen), whether or not this handle should be visible private boolean mIsActive = false; + // Used to detect that setFrame was called + private boolean mNeedsUpdate = true; public HandleView() { super(TextView.this.mContext); @@ -9074,6 +9079,15 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener mIdealVerticalOffset = 0.7f * handleHeight; } + @Override + protected boolean setFrame(int left, int top, int right, int bottom) { + boolean changed = super.setFrame(left, top, right, bottom); + // onPreDraw is called for PhoneWindow before the layout of this view is + // performed. Make sure to update position, even if container didn't move. + if (changed) mNeedsUpdate = true; + return changed; + } + protected abstract void initDrawable(); // Touch-up filter: number of previous positions remembered @@ -9222,7 +9236,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener mPositionY += viewportToContentVerticalOffset(); } - protected boolean updateContainerPosition() { + private void checkForContainerPositionChange() { positionAtCursorOffset(getCurrentCursorOffset()); final int previousContainerPositionX = mContainerPositionX; @@ -9232,12 +9246,13 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener mContainerPositionX = mTempCoords[0] + mPositionX; mContainerPositionY = mTempCoords[1] + mPositionY; - return (previousContainerPositionX != mContainerPositionX || - previousContainerPositionY != mContainerPositionY); + mNeedsUpdate |= previousContainerPositionX != mContainerPositionX; + mNeedsUpdate |= previousContainerPositionY != mContainerPositionY; } public boolean onPreDraw() { - if (updateContainerPosition()) { + checkForContainerPositionChange(); + if (mNeedsUpdate) { if (mIsDragging) { if (mTempCoords[0] != mLastParentX || mTempCoords[1] != mLastParentY) { mTouchToWindowOffsetX += mTempCoords[0] - mLastParentX; @@ -9261,6 +9276,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener dismiss(); } } + mNeedsUpdate = false; } return true; } diff --git a/core/java/com/android/internal/app/ActionBarImpl.java b/core/java/com/android/internal/app/ActionBarImpl.java index dda3be6f1105..8d5df6f96714 100644 --- a/core/java/com/android/internal/app/ActionBarImpl.java +++ b/core/java/com/android/internal/app/ActionBarImpl.java @@ -156,9 +156,7 @@ public class ActionBarImpl extends ActionBar { mContextDisplayMode = mActionView.isSplitActionBar() ? CONTEXT_DISPLAY_SPLIT : CONTEXT_DISPLAY_NORMAL; - TypedArray a = mContext.obtainStyledAttributes(null, R.styleable.ActionBar); - mContentHeight = a.getLayoutDimension(R.styleable.ActionBar_height, 0); - a.recycle(); + mContentHeight = mActionView.getContentHeight(); } public void onConfigurationChanged(Configuration newConfig) { @@ -179,9 +177,7 @@ public class ActionBarImpl extends ActionBar { mActionView.setCollapsable(!mHasEmbeddedTabs && getNavigationMode() == NAVIGATION_MODE_TABS); - TypedArray a = mContext.obtainStyledAttributes(null, R.styleable.ActionBar); - mContentHeight = a.getLayoutDimension(R.styleable.ActionBar_height, 0); - a.recycle(); + mContentHeight = mActionView.getContentHeight(); if (mTabScrollView != null) { mTabScrollView.getLayoutParams().height = mContentHeight; @@ -368,7 +364,7 @@ public class ActionBarImpl extends ActionBar { mode.invalidate(); mContextView.initForMode(mode); animateToMode(true); - if (mSplitView != null) { + if (mSplitView != null && mContextDisplayMode == CONTEXT_DISPLAY_SPLIT) { // TODO animate this mSplitView.setVisibility(View.VISIBLE); } @@ -526,7 +522,7 @@ public class ActionBarImpl extends ActionBar { mContainerView.setTranslationY(-mContainerView.getHeight()); b.with(ObjectAnimator.ofFloat(mContainerView, "translationY", 0)); } - if (mSplitView != null) { + if (mSplitView != null && mContextDisplayMode == CONTEXT_DISPLAY_SPLIT) { mSplitView.setAlpha(0); b.with(ObjectAnimator.ofFloat(mSplitView, "alpha", 1)); } @@ -560,7 +556,7 @@ public class ActionBarImpl extends ActionBar { b.with(ObjectAnimator.ofFloat(mContainerView, "translationY", -mContainerView.getHeight())); } - if (mSplitView != null) { + if (mSplitView != null && mSplitView.getVisibility() == View.VISIBLE) { mSplitView.setAlpha(1); b.with(ObjectAnimator.ofFloat(mSplitView, "alpha", 0)); } diff --git a/core/java/com/android/internal/view/IInputMethodManager.aidl b/core/java/com/android/internal/view/IInputMethodManager.aidl index 8039fdac7057..812f92badcfe 100644 --- a/core/java/com/android/internal/view/IInputMethodManager.aidl +++ b/core/java/com/android/internal/view/IInputMethodManager.aidl @@ -68,4 +68,5 @@ interface IInputMethodManager { boolean setCurrentInputMethodSubtype(in InputMethodSubtype subtype); boolean switchToLastInputMethod(in IBinder token); boolean setInputMethodEnabled(String id, boolean enabled); + boolean setAdditionalInputMethodSubtypes(in IBinder token, in InputMethodSubtype[] subtypes); } diff --git a/core/java/com/android/internal/view/menu/ActionMenuPresenter.java b/core/java/com/android/internal/view/menu/ActionMenuPresenter.java index 91dd7e36f7ba..98c2747a6573 100644 --- a/core/java/com/android/internal/view/menu/ActionMenuPresenter.java +++ b/core/java/com/android/internal/view/menu/ActionMenuPresenter.java @@ -39,10 +39,13 @@ public class ActionMenuPresenter extends BaseMenuPresenter { private View mOverflowButton; private boolean mReserveOverflow; + private boolean mReserveOverflowSet; private int mWidthLimit; private int mActionItemWidthLimit; private int mMaxItems; + private boolean mMaxItemsSet; private boolean mStrictWidthLimit; + private boolean mWidthLimitSet; // Group IDs that have been added as actions - used temporarily, allocated here for reuse. private final SparseBooleanArray mActionButtonGroups = new SparseBooleanArray(); @@ -64,14 +67,21 @@ public class ActionMenuPresenter extends BaseMenuPresenter { super.initForMenu(context, menu); final Resources res = context.getResources(); - final int screen = res.getConfiguration().screenLayout; - // TODO Use the no-buttons specifier instead here - mReserveOverflow = (screen & Configuration.SCREENLAYOUT_SIZE_MASK) == - Configuration.SCREENLAYOUT_SIZE_XLARGE; - mWidthLimit = res.getDisplayMetrics().widthPixels / 2; + + if (!mReserveOverflowSet) { + // TODO Use the no-buttons specifier instead here + mReserveOverflow = res.getConfiguration() + .isLayoutSizeAtLeast(Configuration.SCREENLAYOUT_SIZE_LARGE); + } + + if (!mWidthLimitSet) { + mWidthLimit = res.getDisplayMetrics().widthPixels / 2; + } // Measure for initial configuration - mMaxItems = res.getInteger(com.android.internal.R.integer.max_action_buttons); + if (!mMaxItemsSet) { + mMaxItems = res.getInteger(com.android.internal.R.integer.max_action_buttons); + } int width = mWidthLimit; if (mReserveOverflow) { @@ -92,15 +102,19 @@ public class ActionMenuPresenter extends BaseMenuPresenter { } public void setWidthLimit(int width, boolean strict) { - if (mReserveOverflow) { - width -= mOverflowButton.getMeasuredWidth(); - } - mActionItemWidthLimit = width; + mWidthLimit = width; mStrictWidthLimit = strict; + mWidthLimitSet = true; + } + + public void setReserveOverflow(boolean reserveOverflow) { + mReserveOverflow = reserveOverflow; + mReserveOverflowSet = true; } public void setItemLimit(int itemCount) { mMaxItems = itemCount; + mMaxItemsSet = true; } @Override diff --git a/core/java/com/android/internal/view/menu/MenuItemImpl.java b/core/java/com/android/internal/view/menu/MenuItemImpl.java index f2430e4cb2ea..1a6cc5432963 100644 --- a/core/java/com/android/internal/view/menu/MenuItemImpl.java +++ b/core/java/com/android/internal/view/menu/MenuItemImpl.java @@ -19,6 +19,7 @@ package com.android.internal.view.menu; import com.android.internal.view.menu.MenuView.ItemView; import android.content.ActivityNotFoundException; +import android.content.Context; import android.content.Intent; import android.graphics.drawable.Drawable; import android.util.Log; @@ -28,6 +29,7 @@ import android.view.MenuItem; import android.view.SubMenu; import android.view.View; import android.view.ViewDebug; +import android.widget.LinearLayout; /** * @hide @@ -554,9 +556,9 @@ public final class MenuItemImpl implements MenuItem { } public MenuItem setActionView(int resId) { - LayoutInflater inflater = LayoutInflater.from(mMenu.getContext()); - // TODO - Fix for proper parent. Lazily inflate in the presenter. - setActionView(inflater.inflate(resId, null)); + final Context context = mMenu.getContext(); + final LayoutInflater inflater = LayoutInflater.from(context); + setActionView(inflater.inflate(resId, new LinearLayout(context))); return this; } diff --git a/core/java/com/android/internal/widget/ActionBarContainer.java b/core/java/com/android/internal/widget/ActionBarContainer.java index 1726390ca638..d710cfae56f3 100644 --- a/core/java/com/android/internal/widget/ActionBarContainer.java +++ b/core/java/com/android/internal/widget/ActionBarContainer.java @@ -16,6 +16,7 @@ package com.android.internal.widget; +import android.app.ActionBar; import android.content.Context; import android.content.res.TypedArray; import android.util.AttributeSet; @@ -32,6 +33,7 @@ import android.widget.FrameLayout; public class ActionBarContainer extends FrameLayout { private boolean mIsTransitioning; private View mTabContainer; + private ActionBarView mActionBarView; public ActionBarContainer(Context context) { this(context, null); @@ -46,6 +48,12 @@ public class ActionBarContainer extends FrameLayout { a.recycle(); } + @Override + public void onFinishInflate() { + super.onFinishInflate(); + mActionBarView = (ActionBarView) findViewById(com.android.internal.R.id.action_bar); + } + /** * Set the action bar into a "transitioning" state. While transitioning * the bar will block focus and touch from all of its descendants. This @@ -101,9 +109,8 @@ public class ActionBarContainer extends FrameLayout { final int count = getChildCount(); for (int i = 0; i < count; i++) { final View child = getChildAt(i); - if (child == mTabContainer) { - continue; - } + + if (child == mTabContainer) continue; final LayoutParams lp = (LayoutParams) child.getLayoutParams(); nonTabHeight = Math.max(nonTabHeight, @@ -125,8 +132,22 @@ public class ActionBarContainer extends FrameLayout { super.onLayout(changed, l, t, r, b); if (mTabContainer != null && mTabContainer.getVisibility() != GONE) { final int containerHeight = getMeasuredHeight(); - mTabContainer.layout(l, containerHeight - mTabContainer.getMeasuredHeight(), - r, containerHeight); + final int tabHeight = mTabContainer.getMeasuredHeight(); + + if ((mActionBarView.getDisplayOptions() & ActionBar.DISPLAY_SHOW_HOME) == 0) { + // Not showing home, put tabs on top. + final int count = getChildCount(); + for (int i = 0; i < count; i++){ + final View child = getChildAt(i); + + if (child == mTabContainer) continue; + + child.offsetTopAndBottom(tabHeight); + } + mTabContainer.layout(l, 0, r, tabHeight); + } else { + mTabContainer.layout(l, containerHeight - tabHeight, r, containerHeight); + } } } } diff --git a/core/java/com/android/internal/widget/ActionBarContextView.java b/core/java/com/android/internal/widget/ActionBarContextView.java index e4c4989fbe22..fc439944f518 100644 --- a/core/java/com/android/internal/widget/ActionBarContextView.java +++ b/core/java/com/android/internal/widget/ActionBarContextView.java @@ -168,14 +168,14 @@ public class ActionBarContextView extends AbsActionBarView implements AnimatorLi final MenuBuilder menu = (MenuBuilder) mode.getMenu(); mActionMenuPresenter = new ActionMenuPresenter(); - menu.addMenuPresenter(mActionMenuPresenter); - mMenuView = (ActionMenuView) mActionMenuPresenter.getMenuView(this); + mActionMenuPresenter.setReserveOverflow(true); final LayoutParams layoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT); - mMenuView.setLayoutParams(layoutParams); if (mSplitView == null) { - addView(mMenuView); + menu.addMenuPresenter(mActionMenuPresenter); + mMenuView = (ActionMenuView) mActionMenuPresenter.getMenuView(this); + addView(mMenuView, layoutParams); } else { // Allow full screen width in split mode. mActionMenuPresenter.setWidthLimit( @@ -184,7 +184,10 @@ public class ActionBarContextView extends AbsActionBarView implements AnimatorLi mActionMenuPresenter.setItemLimit(Integer.MAX_VALUE); // Span the whole width layoutParams.width = LayoutParams.MATCH_PARENT; - mSplitView.addView(mMenuView); + layoutParams.height = mContentHeight; + menu.addMenuPresenter(mActionMenuPresenter); + mMenuView = (ActionMenuView) mActionMenuPresenter.getMenuView(this); + mSplitView.addView(mMenuView, layoutParams); } mAnimateInOnLayout = true; diff --git a/core/java/com/android/internal/widget/ActionBarView.java b/core/java/com/android/internal/widget/ActionBarView.java index eb97ea8b2176..e3286dda28a3 100644 --- a/core/java/com/android/internal/widget/ActionBarView.java +++ b/core/java/com/android/internal/widget/ActionBarView.java @@ -273,6 +273,10 @@ public class ActionBarView extends AbsActionBarView { requestLayout(); } + public int getContentHeight() { + return mContentHeight; + } + public void setSplitActionBar(boolean splitActionBar) { if (mSplitActionBar != splitActionBar) { if (mMenuView != null) { @@ -327,15 +331,15 @@ public class ActionBarView extends AbsActionBarView { mActionMenuPresenter.setCallback(cb); mExpandedMenuPresenter = new ExpandedActionViewMenuPresenter(); } - builder.addMenuPresenter(mActionMenuPresenter); - builder.addMenuPresenter(mExpandedMenuPresenter); - final ActionMenuView menuView = (ActionMenuView) mActionMenuPresenter.getMenuView(this); + ActionMenuView menuView; final LayoutParams layoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT); - menuView.setLayoutParams(layoutParams); if (!mSplitActionBar) { - addView(menuView); + builder.addMenuPresenter(mActionMenuPresenter); + builder.addMenuPresenter(mExpandedMenuPresenter); + menuView = (ActionMenuView) mActionMenuPresenter.getMenuView(this); + addView(menuView, layoutParams); } else { // Allow full screen width in split mode. mActionMenuPresenter.setWidthLimit( @@ -344,9 +348,15 @@ public class ActionBarView extends AbsActionBarView { mActionMenuPresenter.setItemLimit(Integer.MAX_VALUE); // Span the whole width layoutParams.width = LayoutParams.MATCH_PARENT; + builder.addMenuPresenter(mActionMenuPresenter); + builder.addMenuPresenter(mExpandedMenuPresenter); + menuView = (ActionMenuView) mActionMenuPresenter.getMenuView(this); if (mSplitView != null) { - mSplitView.addView(menuView); - } // We'll add this later if we missed it this time. + mSplitView.addView(menuView, layoutParams); + } else { + // We'll add this later if we missed it this time. + menuView.setLayoutParams(layoutParams); + } } mMenuView = menuView; } diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java index 4337e905b08e..d034eab8af94 100644 --- a/core/java/com/android/internal/widget/LockPatternUtils.java +++ b/core/java/com/android/internal/widget/LockPatternUtils.java @@ -36,6 +36,7 @@ import android.text.TextUtils; import android.util.Log; import android.view.View; import android.widget.Button; +import android.widget.TextView; import java.io.File; import java.io.FileNotFoundException; @@ -885,6 +886,18 @@ public class LockPatternUtils { } /** + * Sets the visibility of emergency call prompt based on emergency capable + * @param emergencyText the emergency call text to be updated + */ + public void updateEmergencyCallText(TextView emergencyText) { + if (isEmergencyCallCapable()) { + emergencyText.setVisibility(View.VISIBLE); + } else { + emergencyText.setVisibility(View.GONE); + } + } + + /** * Resumes a call in progress. Typically launched from the EmergencyCall button * on various lockscreens. * diff --git a/core/java/com/android/internal/widget/multiwaveview/Ease.java b/core/java/com/android/internal/widget/multiwaveview/Ease.java new file mode 100644 index 000000000000..7f90c441fe03 --- /dev/null +++ b/core/java/com/android/internal/widget/multiwaveview/Ease.java @@ -0,0 +1,132 @@ +/* + * 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.multiwaveview; + +import android.animation.TimeInterpolator; + +class Ease { + private static final float DOMAIN = 1.0f; + private static final float DURATION = 1.0f; + private static final float START = 0.0f; + + static class Linear { + public static final TimeInterpolator easeNone = new TimeInterpolator() { + public float getInterpolation(float input) { + return input; + } + }; + } + + static class Cubic { + public static final TimeInterpolator easeIn = new TimeInterpolator() { + public float getInterpolation(float input) { + return DOMAIN*(input/=DURATION)*input*input + START; + } + }; + public static final TimeInterpolator easeOut = new TimeInterpolator() { + public float getInterpolation(float input) { + return DOMAIN*((input=input/DURATION-1)*input*input + 1) + START; + } + }; + public static final TimeInterpolator easeInOut = new TimeInterpolator() { + public float getInterpolation(float input) { + return ((input/=DURATION/2) < 1.0f) ? + (DOMAIN/2*input*input*input + START) + : (DOMAIN/2*((input-=2)*input*input + 2) + START); + } + }; + } + + static class Quad { + public static final TimeInterpolator easeIn = new TimeInterpolator() { + public float getInterpolation (float input) { + return DOMAIN*(input/=DURATION)*input + START; + } + }; + public static final TimeInterpolator easeOut = new TimeInterpolator() { + public float getInterpolation(float input) { + return -DOMAIN *(input/=DURATION)*(input-2) + START; + } + }; + public static final TimeInterpolator easeInOut = new TimeInterpolator() { + public float getInterpolation(float input) { + return ((input/=DURATION/2) < 1) ? + (DOMAIN/2*input*input + START) + : (-DOMAIN/2 * ((--input)*(input-2) - 1) + START); + } + }; + } + + static class Quart { + public static final TimeInterpolator easeIn = new TimeInterpolator() { + public float getInterpolation(float input) { + return DOMAIN*(input/=DURATION)*input*input*input + START; + } + }; + public static final TimeInterpolator easeOut = new TimeInterpolator() { + public float getInterpolation(float input) { + return -DOMAIN * ((input=input/DURATION-1)*input*input*input - 1) + START; + } + }; + public static final TimeInterpolator easeInOut = new TimeInterpolator() { + public float getInterpolation(float input) { + return ((input/=DURATION/2) < 1) ? + (DOMAIN/2*input*input*input*input + START) + : (-DOMAIN/2 * ((input-=2)*input*input*input - 2) + START); + } + }; + } + + static class Quint { + public static final TimeInterpolator easeIn = new TimeInterpolator() { + public float getInterpolation(float input) { + return DOMAIN*(input/=DURATION)*input*input*input*input + START; + } + }; + public static final TimeInterpolator easeOut = new TimeInterpolator() { + public float getInterpolation(float input) { + return DOMAIN*((input=input/DURATION-1)*input*input*input*input + 1) + START; + } + }; + public static final TimeInterpolator easeInOut = new TimeInterpolator() { + public float getInterpolation(float input) { + return ((input/=DURATION/2) < 1) ? + (DOMAIN/2*input*input*input*input*input + START) + : (DOMAIN/2*((input-=2)*input*input*input*input + 2) + START); + } + }; + } + + static class Sine { + public static final TimeInterpolator easeIn = new TimeInterpolator() { + public float getInterpolation(float input) { + return -DOMAIN * (float) Math.cos(input/DURATION * (Math.PI/2)) + DOMAIN + START; + } + }; + public static final TimeInterpolator easeOut = new TimeInterpolator() { + public float getInterpolation(float input) { + return DOMAIN * (float) Math.sin(input/DURATION * (Math.PI/2)) + START; + } + }; + public static final TimeInterpolator easeInOut = new TimeInterpolator() { + public float getInterpolation(float input) { + return -DOMAIN/2 * ((float)Math.cos(Math.PI*input/DURATION) - 1.0f) + START; + } + }; + } + +} diff --git a/core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java b/core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java new file mode 100644 index 000000000000..026ad2763d99 --- /dev/null +++ b/core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java @@ -0,0 +1,645 @@ +/* + * 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.multiwaveview; + +import java.util.ArrayList; + +import android.animation.Animator; +import android.animation.Animator.AnimatorListener; +import android.animation.ObjectAnimator; +import android.animation.TimeInterpolator; +import android.animation.ValueAnimator; +import android.animation.ValueAnimator.AnimatorUpdateListener; +import android.content.Context; +import android.content.res.Resources; +import android.content.res.TypedArray; +import android.graphics.Canvas; +import android.graphics.RectF; +import android.graphics.drawable.Drawable; +import android.os.Vibrator; +import android.util.AttributeSet; +import android.util.Log; +import android.util.TypedValue; +import android.view.MotionEvent; +import android.view.View; + +import com.android.internal.R; + +/** + * A special widget containing a center and outer ring. Moving the center ring to the outer ring + * causes an event that can be caught by implementing OnTriggerListener. + */ +public class MultiWaveView extends View implements AnimatorUpdateListener { + private static final String TAG = "MultiWaveView"; + private static final boolean DEBUG = false; + + // Wave state machine + private static final int STATE_IDLE = 0; + private static final int STATE_FIRST_TOUCH = 1; + private static final int STATE_TRACKING = 2; + private static final int STATE_SNAP = 3; + private static final int STATE_FINISH = 4; + + // Animation properties. + private static final float SNAP_MARGIN_DEFAULT = 20.0f; // distance to ring before we snap to it + + public interface OnTriggerListener { + int NO_HANDLE = 0; + int CENTER_HANDLE = 1; + public void onGrabbed(View v, int handle); + public void onReleased(View v, int handle); + public void onTrigger(View v, int target); + public void onGrabbedStateChange(View v, int handle); + } + + // Tune-able parameters + private static final int CHEVRON_INCREMENTAL_DELAY = 50; + private static final int CHEVRON_ANIMATION_DURATION = 1000; + private static final int RETURN_TO_HOME_DURATION = 150; + private static final int HIDE_ANIMATION_DELAY = 500; + private static final int HIDE_ANIMATION_DURACTION = 2000; + private static final int SHOW_ANIMATION_DURATION = 0; + private static final int SHOW_ANIMATION_DELAY = 0; + private TimeInterpolator mChevronAnimationInterpolator = Ease.Quint.easeOut; + + private ArrayList<TargetDrawable> mTargetDrawables = new ArrayList<TargetDrawable>(); + private ArrayList<TargetDrawable> mChevronDrawables = new ArrayList<TargetDrawable>(); + private ArrayList<Tweener> mChevronAnimations = new ArrayList<Tweener>(); + private ArrayList<Tweener> mTargetAnimations = new ArrayList<Tweener>(); + private Tweener mHandleAnimation; + private OnTriggerListener mOnTriggerListener; + private TargetDrawable mHandleDrawable; + private TargetDrawable mOuterRing; + private Vibrator mVibrator; + + private int mFeedbackCount = 3; + private int mVibrationDuration = 0; + private int mGrabbedState; + private int mActiveTarget = -1; + private float mTapRadius; + private float mWaveCenterX; + private float mWaveCenterY; + private float mVerticalOffset; + private float mHorizontalOffset; + private float mOuterRadius = 0.0f; + private float mHitRadius = 0.0f; + private float mSnapMargin = 0.0f; + private boolean mDragging; + + private AnimatorListener mResetListener = new Animator.AnimatorListener() { + public void onAnimationStart(Animator animation) { } + public void onAnimationRepeat(Animator animation) { } + public void onAnimationEnd(Animator animation) { + switchToState(STATE_IDLE, mWaveCenterX, mWaveCenterY); + } + public void onAnimationCancel(Animator animation) { } + }; + + public MultiWaveView(Context context) { + this(context, null); + } + + public MultiWaveView(Context context, AttributeSet attrs) { + super(context, attrs); + Resources res = context.getResources(); + + TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.MultiWaveView); + mOuterRadius = a.getDimension(R.styleable.MultiWaveView_outerRadius, mOuterRadius); + mHorizontalOffset = a.getDimension(R.styleable.MultiWaveView_horizontalOffset, + mHorizontalOffset); + mVerticalOffset = a.getDimension(R.styleable.MultiWaveView_verticalOffset, + mVerticalOffset); + mHitRadius = a.getDimension(R.styleable.MultiWaveView_hitRadius, mHitRadius); + mSnapMargin = a.getDimension(R.styleable.MultiWaveView_snapMargin, mSnapMargin); + mVibrationDuration = a.getInt(R.styleable.MultiWaveView_vibrationDuration, + mVibrationDuration); + mFeedbackCount = a.getInt(R.styleable.MultiWaveView_feedbackCount, + mFeedbackCount); + mHandleDrawable = new TargetDrawable(res, + a.getDrawable(R.styleable.MultiWaveView_handleDrawable)); + mTapRadius = mHandleDrawable.getWidth()/2; + mOuterRing = new TargetDrawable(res, a.getDrawable(R.styleable.MultiWaveView_waveDrawable)); + + // Read animation drawables + Drawable leftChevron = a.getDrawable(R.styleable.MultiWaveView_leftChevronDrawable); + if (leftChevron != null) { + for (int i = 0; i < mFeedbackCount; i++) { + mChevronDrawables.add(new TargetDrawable(res, leftChevron)); + } + } + Drawable rightChevron = a.getDrawable(R.styleable.MultiWaveView_rightChevronDrawable); + if (rightChevron != null) { + for (int i = 0; i < mFeedbackCount; i++) { + mChevronDrawables.add(new TargetDrawable(res, rightChevron)); + } + } + + // Read array of target drawables + TypedValue outValue = new TypedValue(); + if (a.getValue(R.styleable.MultiWaveView_targetDrawables, outValue)) { + setTargetResources(outValue.resourceId); + } + if (mTargetDrawables == null || mTargetDrawables.size() == 0) { + throw new IllegalStateException("Must specify at least one target drawable"); + } + + setVibrateEnabled(mVibrationDuration > 0); + } + + private void dump() { + Log.v(TAG, "Outer Radius = " + mOuterRadius); + Log.v(TAG, "HitRadius = " + mHitRadius); + Log.v(TAG, "SnapMargin = " + mSnapMargin); + Log.v(TAG, "FeedbackCount = " + mFeedbackCount); + Log.v(TAG, "VibrationDuration = " + mVibrationDuration); + Log.v(TAG, "TapRadius = " + mTapRadius); + Log.v(TAG, "WaveCenterX = " + mWaveCenterX); + Log.v(TAG, "WaveCenterY = " + mWaveCenterY); + Log.v(TAG, "HorizontalOffset = " + mHorizontalOffset); + Log.v(TAG, "VerticalOffset = " + mVerticalOffset); + } + + @Override + protected int getSuggestedMinimumWidth() { + // View should be large enough to contain the background + target drawable on either edge + return mOuterRing.getWidth() + + (mTargetDrawables.size() > 0 ? (mTargetDrawables.get(0).getWidth()) : 0); + } + + @Override + protected int getSuggestedMinimumHeight() { + // View should be large enough to contain the unlock ring + target drawable on either edge + return mOuterRing.getHeight() + + (mTargetDrawables.size() > 0 ? (mTargetDrawables.get(0).getHeight()) : 0); + } + + private void switchToState(int state, float x, float y) { + switch (state) { + case STATE_IDLE: + stopChevronAnimation(); + deactivateTargets(); + mHandleDrawable.setState(TargetDrawable.STATE_INACTIVE); + break; + + case STATE_FIRST_TOUCH: + stopHandleAnimation(); + deactivateTargets(); + showTargets(); + mHandleDrawable.setState(TargetDrawable.STATE_ACTIVE); + setGrabbedState(OnTriggerListener.CENTER_HANDLE); + break; + + case STATE_TRACKING: + break; + + case STATE_SNAP: + break; + + case STATE_FINISH: + doFinish(); + break; + } + } + + /** + * Animation used to attract user's attention to the target button. + * Assumes mChevronDrawables is an a list with an even number of chevrons filled with left + * followed by right chevrons. + */ + private void startChevronAnimation() { + final int icons = mChevronDrawables.size(); + for (Tweener tween : mChevronAnimations) { + tween.animator.cancel(); + } + for (int i = 0; i < icons; i++) { + TargetDrawable icon = mChevronDrawables.get(i); + icon.setY(mWaveCenterY); + icon.setAlpha(1.0f); + mChevronAnimations.clear(); + int delay = (int) (Math.abs(0.5f + i - icons / 2) * CHEVRON_INCREMENTAL_DELAY); + if (i < icons/2) { + // Left chevrons + icon.setX(mWaveCenterX - mHandleDrawable.getWidth() / 2); + mChevronAnimations.add(Tweener.to(icon, CHEVRON_ANIMATION_DURATION, + "ease", mChevronAnimationInterpolator, + "delay", delay, + "x", mWaveCenterX - mOuterRadius, + "alpha", 0.0f, + "onUpdate", this)); + } else { + // Right chevrons + icon.setX(mWaveCenterX + mHandleDrawable.getWidth() / 2); + mChevronAnimations.add(Tweener.to(icon, CHEVRON_ANIMATION_DURATION, + "ease", mChevronAnimationInterpolator, + "delay", delay, + "x", mWaveCenterX + mOuterRadius, + "alpha", 0.0f, + "onUpdate", this)); + } + } + } + + private void stopChevronAnimation() { + for (Tweener anim : mChevronAnimations) { + anim.animator.end(); + } + mChevronAnimations.clear(); + } + + private void stopHandleAnimation() { + if (mHandleAnimation != null) { + mHandleAnimation.animator.end(); + mHandleAnimation = null; + } + } + + private void deactivateTargets() { + for (TargetDrawable target : mTargetDrawables) { + target.setState(TargetDrawable.STATE_INACTIVE); + } + mActiveTarget = -1; + } + + void invalidateGlobalRegion(TargetDrawable drawable) { + int width = drawable.getWidth(); + int height = drawable.getHeight(); + RectF childBounds = new RectF(0, 0, width, height); + childBounds.offset(drawable.getX() - width/2, drawable.getY() - height/2); + View view = this; + while (view.getParent() != null && view.getParent() instanceof View) { + view = (View) view.getParent(); + view.getMatrix().mapRect(childBounds); + view.invalidate((int) Math.floor(childBounds.left), + (int) Math.floor(childBounds.top), + (int) Math.ceil(childBounds.right), + (int) Math.ceil(childBounds.bottom)); + } + } + + /** + * Dispatches a trigger event to listener. Ignored if a listener is not set. + * @param whichHandle the handle that triggered the event. + */ + private void dispatchTriggerEvent(int whichHandle) { + vibrate(); + if (mOnTriggerListener != null) { + mOnTriggerListener.onTrigger(this, whichHandle); + } + } + + private void doFinish() { + // Inform listener of any active targets. Typically only one will be active. + final int activeTarget = mActiveTarget; + boolean targetHit = activeTarget != -1; + if (targetHit) { + Log.v(TAG, "Finish with target hit = " + targetHit); + dispatchTriggerEvent(mActiveTarget); + } + + setGrabbedState(OnTriggerListener.NO_HANDLE); + + // Animate finger outline back to home position + mHandleDrawable.setAlpha(targetHit ? 0.0f : 1.0f); + mHandleAnimation = Tweener.to(mHandleDrawable, RETURN_TO_HOME_DURATION, + "ease", Ease.Quart.easeOut, + "delay", targetHit ? HIDE_ANIMATION_DELAY : 0, + "alpha", 1.0f, + "x", mWaveCenterX, + "y", mWaveCenterY, + "onUpdate", this, + "onComplete", mResetListener); + + // Hide unselected targets + hideTargets(true); + + // Highlight the selected one + if (targetHit) { + mTargetDrawables.get(activeTarget).setState(TargetDrawable.STATE_ACTIVE); + } + + stopChevronAnimation(); + } + + private void hideTargets(boolean animate) { + if (mTargetAnimations.size() > 0) { + stopTargetAnimation(); + } + for (TargetDrawable target : mTargetDrawables) { + target.setState(TargetDrawable.STATE_INACTIVE); + mTargetAnimations.add(Tweener.to(target, + animate ? HIDE_ANIMATION_DURACTION : 0, + "alpha", 0.0f, + "delay", HIDE_ANIMATION_DELAY, + "onUpdate", this)); + } + mTargetAnimations.add(Tweener.to(mOuterRing, + animate ? HIDE_ANIMATION_DURACTION : 0, + "alpha", 0.0f, + "delay", HIDE_ANIMATION_DELAY, + "onUpdate", this)); + } + + private void showTargets() { + if (mTargetAnimations.size() > 0) { + stopTargetAnimation(); + } + for (TargetDrawable target : mTargetDrawables) { + target.setState(TargetDrawable.STATE_INACTIVE); + mTargetAnimations.add(Tweener.to(target, SHOW_ANIMATION_DURATION, + "alpha", 1.0f, + "delay", SHOW_ANIMATION_DELAY, + "onUpdate", this)); + } + mTargetAnimations.add(Tweener.to(mOuterRing, SHOW_ANIMATION_DURATION, + "alpha", 1.0f, + "delay", SHOW_ANIMATION_DELAY, + "onUpdate", this)); + } + + private void stopTargetAnimation() { + for (Tweener anim : mTargetAnimations) { + anim.animator.end(); + } + mTargetAnimations.clear(); + } + + private void vibrate() { + if (mVibrator != null) { + mVibrator.vibrate(mVibrationDuration); + } + } + + /** + * Loads an array of drawables from the given resourceId. + * + * @param resourceId + */ + public void setTargetResources(int resourceId) { + Resources res = getContext().getResources(); + TypedArray array = res.obtainTypedArray(resourceId); + int count = array.length(); + mTargetDrawables = new ArrayList<TargetDrawable>(count); + for (int i = 0; i < count; i++) { + Drawable drawable = array.getDrawable(i); + mTargetDrawables.add(new TargetDrawable(res, drawable)); + } + } + + /** + * Enable or disable vibrate on touch. + * + * @param enabled + */ + public void setVibrateEnabled(boolean enabled) { + if (enabled && mVibrator == null) { + mVibrator = (Vibrator) getContext().getSystemService(Context.VIBRATOR_SERVICE); + } else { + mVibrator = null; + } + } + + /** + * Starts chevron animation. Example use case: show chevron animation whenever the phone rings + * or the user touches the screen. + * + */ + public void ping() { + stopChevronAnimation(); + startChevronAnimation(); + } + + /** + * Resets the widget to default state and cancels all animation. If animate is 'true', will + * animate objects into place. Otherwise, objects will snap back to place. + * + * @param animate + */ + public void reset(boolean animate) { + stopChevronAnimation(); + stopHandleAnimation(); + stopTargetAnimation(); + hideChevrons(); + hideTargets(animate); + mHandleDrawable.setX(mWaveCenterX); + mHandleDrawable.setY(mWaveCenterY); + mHandleDrawable.setState(TargetDrawable.STATE_INACTIVE); + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + final int action = event.getAction(); + + boolean handled = false; + float x = event.getX(); + float y = event.getY(); + switch (action) { + case MotionEvent.ACTION_DOWN: + handleDown(x, y); + handled = true; + break; + + case MotionEvent.ACTION_MOVE: + handleMove(x, y); + handled = true; + break; + + case MotionEvent.ACTION_UP: + handleUp(x, y); + handleMove(x, y); + handled = true; + break; + + case MotionEvent.ACTION_CANCEL: + handleMove(x, y); + handled = true; + break; + } + invalidate(); + return handled ? true : super.onTouchEvent(event); + } + + private void handleDown(float x, float y) { + final float dx = x - mWaveCenterX; + final float dy = y - mWaveCenterY; + if (dist2(dx,dy) <= square(mTapRadius)) { + if (DEBUG) Log.v(TAG, "** Handle HIT"); + switchToState(STATE_FIRST_TOUCH, x, y); + mDragging = true; + } else { + mDragging = false; + stopTargetAnimation(); + ping(); + } + } + + private void handleUp(float x, float y) { + if (DEBUG && mDragging) Log.v(TAG, "** Handle RELEASE"); + switchToState(STATE_FINISH, x, y); + } + + private void handleMove(float x, float y) { + if (!mDragging) { + return; + } + + float tx = x - mWaveCenterX; + float ty = y - mWaveCenterY; + float touchRadius = (float) Math.sqrt(dist2(tx, ty)); + final float scale = touchRadius > mOuterRadius ? mOuterRadius / touchRadius : 1.0f; + float limitX = mWaveCenterX + tx * scale; + float limitY = mWaveCenterY + ty * scale; + + int activeTarget = -1; + boolean singleTarget = mTargetDrawables.size() == 1; + if (singleTarget) { + // Snap to outer ring if there's only one target + float snapRadius = mOuterRadius - mSnapMargin; + if (touchRadius > snapRadius) { + activeTarget = 0; + x = limitX; + y = limitY; + } + } else { + // If there's more than one target, snap to the closest one less than hitRadius away. + float best = Float.MAX_VALUE; + final float hitRadius2 = mHitRadius * mHitRadius; + for (int i = 0; i < mTargetDrawables.size(); i++) { + // Snap to the first target in range + TargetDrawable target = mTargetDrawables.get(i); + float dx = limitX - target.getX(); + float dy = limitY - target.getY(); + float dist2 = dx*dx + dy*dy; + if (target.isValid() && dist2 < hitRadius2 && dist2 < best) { + activeTarget = i; + best = dist2; + } + } + } + if (activeTarget != -1) { + switchToState(STATE_SNAP, x,y); + mHandleDrawable.setX(singleTarget ? limitX : mTargetDrawables.get(activeTarget).getX()); + mHandleDrawable.setY(singleTarget ? limitY : mTargetDrawables.get(activeTarget).getY()); + TargetDrawable currentTarget = mTargetDrawables.get(activeTarget); + if (currentTarget.hasState(TargetDrawable.STATE_FOCUSED)) { + currentTarget.setState(TargetDrawable.STATE_FOCUSED); + mHandleDrawable.setAlpha(0.0f); + } + } else { + switchToState(STATE_TRACKING, x, y); + mHandleDrawable.setX(x); + mHandleDrawable.setY(y); + mHandleDrawable.setAlpha(1.0f); + } + // Draw handle outside parent's bounds + invalidateGlobalRegion(mHandleDrawable); + + if (mActiveTarget != activeTarget && activeTarget != -1) { + vibrate(); + } + mActiveTarget = activeTarget; + } + + /** + * Sets the current grabbed state, and dispatches a grabbed state change + * event to our listener. + */ + private void setGrabbedState(int newState) { + if (newState != mGrabbedState) { + if (newState != OnTriggerListener.NO_HANDLE) { + vibrate(); + } + mGrabbedState = newState; + if (mOnTriggerListener != null) { + mOnTriggerListener.onGrabbedStateChange(this, mGrabbedState); + } + } + } + + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + super.onLayout(changed, left, top, right, bottom); + final int width = right - left; + final int height = bottom - top; + + mWaveCenterX = mHorizontalOffset + Math.max(width, mOuterRing.getWidth() ) / 2; + mWaveCenterY = mVerticalOffset + Math.max(height, mOuterRing.getHeight()) / 2; + mHandleDrawable.setX(mWaveCenterX); + mHandleDrawable.setY(mWaveCenterY); + mOuterRing.setX(mWaveCenterX); + mOuterRing.setY(Math.max(mWaveCenterY, mWaveCenterY)); + mOuterRing.setAlpha(0.0f); + if (mOuterRadius == 0.0f) { + mOuterRadius = 0.5f*(float) Math.sqrt(dist2(mWaveCenterX, mWaveCenterY)); + } + if (mHitRadius == 0.0f) { + // Use the radius of inscribed circle of the first target. + mHitRadius = mTargetDrawables.get(0).getWidth() / 2.0f; + } + if (mSnapMargin == 0.0f) { + mSnapMargin = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, + SNAP_MARGIN_DEFAULT, getContext().getResources().getDisplayMetrics()); + } + for (int i = 0; i < mTargetDrawables.size(); i++) { + final TargetDrawable targetIcon = mTargetDrawables.get(i); + double angle = -2.0f * Math.PI * i / mTargetDrawables.size(); + float xPosition = mWaveCenterX + mOuterRadius * (float) Math.cos(angle); + float yPosition = mWaveCenterY + mOuterRadius * (float) Math.sin(angle); + targetIcon.setX(xPosition); + targetIcon.setY(yPosition); + targetIcon.setAlpha(0.0f); + } + hideChevrons(); + hideTargets(false); + if (DEBUG) dump(); + } + + private void hideChevrons() { + for (TargetDrawable chevron : mChevronDrawables) { + chevron.setAlpha(0.0f); + } + } + + @Override + protected void onDraw(Canvas canvas) { + mOuterRing.draw(canvas); + for (TargetDrawable target : mTargetDrawables) { + target.draw(canvas); + } + for (TargetDrawable target : mChevronDrawables) { + target.draw(canvas); + } + mHandleDrawable.draw(canvas); + } + + public void setOnTriggerListener(OnTriggerListener listener) { + mOnTriggerListener = listener; + } + + public void onAnimationUpdate(ValueAnimator animation) { + invalidateGlobalRegion(mHandleDrawable); + invalidate(); + } + + private float square(float d) { + return d * d; + } + + private float dist2(float dx, float dy) { + return dx*dx + dy*dy; + } + +}
\ No newline at end of file diff --git a/core/java/com/android/internal/widget/multiwaveview/TargetDrawable.java b/core/java/com/android/internal/widget/multiwaveview/TargetDrawable.java new file mode 100644 index 000000000000..d3baa2bb73a3 --- /dev/null +++ b/core/java/com/android/internal/widget/multiwaveview/TargetDrawable.java @@ -0,0 +1,215 @@ +/* + * 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.multiwaveview; + +import android.content.res.Resources; +import android.graphics.Canvas; +import android.graphics.ColorFilter; +import android.graphics.drawable.Drawable; +import android.graphics.drawable.StateListDrawable; +import android.util.Log; + +public class TargetDrawable { + private static final String TAG = "TargetDrawable"; + public static final int[] STATE_ACTIVE = + { android.R.attr.state_enabled, android.R.attr.state_active }; + public static final int[] STATE_INACTIVE = + { android.R.attr.state_enabled, -android.R.attr.state_active }; + public static final int[] STATE_FOCUSED = + { android.R.attr.state_enabled, android.R.attr.state_focused }; + + private float mTranslationX = 0.0f; + private float mTranslationY = 0.0f; + private float mScaleX = 1.0f; + private float mScaleY = 1.0f; + private float mAlpha = 1.0f; + private Drawable mDrawable; + + /* package */ static class DrawableWithAlpha extends Drawable { + private float mAlpha = 1.0f; + private Drawable mRealDrawable; + public DrawableWithAlpha(Drawable realDrawable) { + mRealDrawable = realDrawable; + } + public void setAlpha(float alpha) { + mAlpha = alpha; + } + public float getAlpha() { + return mAlpha; + } + public void draw(Canvas canvas) { + mRealDrawable.setAlpha((int) Math.round(mAlpha * 255f)); + mRealDrawable.draw(canvas); + } + @Override + public void setAlpha(int alpha) { + mRealDrawable.setAlpha(alpha); + } + @Override + public void setColorFilter(ColorFilter cf) { + mRealDrawable.setColorFilter(cf); + } + @Override + public int getOpacity() { + return mRealDrawable.getOpacity(); + } + } + + public TargetDrawable(Resources res, int resId) { + this(res, resId == 0 ? null : res.getDrawable(resId)); + } + + public TargetDrawable(Resources res, Drawable drawable) { + // Mutate the drawable so we can animate shared drawable properties. + mDrawable = drawable != null ? drawable.mutate() : null; + resizeDrawables(); + setState(STATE_INACTIVE); + } + + public void setState(int [] state) { + if (mDrawable instanceof StateListDrawable) { + StateListDrawable d = (StateListDrawable) mDrawable; + d.setState(state); + } + } + + public boolean hasState(int [] state) { + if (mDrawable instanceof StateListDrawable) { + StateListDrawable d = (StateListDrawable) mDrawable; + // TODO: this doesn't seem to work + return d.getStateDrawableIndex(state) != -1; + } + return false; + } + + /** + * Returns true if the drawable is a StateListDrawable and is in the focused state. + * + * @return + */ + public boolean isActive() { + if (mDrawable instanceof StateListDrawable) { + StateListDrawable d = (StateListDrawable) mDrawable; + int[] states = d.getState(); + for (int i = 0; i < states.length; i++) { + if (states[i] == android.R.attr.state_focused) { + return true; + } + } + } + return false; + } + + /** + * Returns true if this target is enabled. Typically an enabled target contains a valid + * drawable in a valid state. Currently all targets with valid drawables are valid. + * + * @return + */ + public boolean isValid() { + return mDrawable != null; + } + + /** + * Makes drawables in a StateListDrawable all the same dimensions. + * If not a StateListDrawable, then justs sets the bounds to the intrinsic size of the + * drawable. + */ + private void resizeDrawables() { + if (mDrawable instanceof StateListDrawable) { + StateListDrawable d = (StateListDrawable) mDrawable; + int maxWidth = 0; + int maxHeight = 0; + for (int i = 0; i < d.getStateCount(); i++) { + Drawable childDrawable = d.getStateDrawable(i); + maxWidth = Math.max(maxWidth, childDrawable.getIntrinsicWidth()); + maxHeight = Math.max(maxHeight, childDrawable.getIntrinsicHeight()); + } + Log.v(TAG, "union of childDrawable rects " + d + " to: " + maxWidth + "x" + maxHeight); + d.setBounds(0, 0, maxWidth, maxHeight); + for (int i = 0; i < d.getStateCount(); i++) { + Drawable childDrawable = d.getStateDrawable(i); + Log.v(TAG, "sizing drawable " + childDrawable + " to: " + maxWidth + "x" + maxHeight); + childDrawable.setBounds(0, 0, maxWidth, maxHeight); + } + } else if (mDrawable != null) { + mDrawable.setBounds(0, 0, + mDrawable.getIntrinsicWidth(), mDrawable.getIntrinsicHeight()); + } + } + + public void setX(float x) { + mTranslationX = x; + } + + public void setY(float y) { + mTranslationY = y; + } + + public void setScaleX(float x) { + mScaleX = x; + } + + public void setScaleY(float y) { + mScaleY = y; + } + + public void setAlpha(float alpha) { + mAlpha = alpha; + } + + public float getX() { + return mTranslationX; + } + + public float getY() { + return mTranslationY; + } + + public float getScaleX() { + return mScaleX; + } + + public float getScaleY() { + return mScaleY; + } + + public float getAlpha() { + return mAlpha; + } + + public int getWidth() { + return mDrawable != null ? mDrawable.getIntrinsicWidth() : 0; + } + + public int getHeight() { + return mDrawable != null ? mDrawable.getIntrinsicHeight() : 0; + } + + public void draw(Canvas canvas) { + if (mDrawable == null) { + return; + } + canvas.save(Canvas.MATRIX_SAVE_FLAG); + canvas.translate(mTranslationX, mTranslationY); + canvas.scale(mScaleX, mScaleY); + canvas.translate(-0.5f * getWidth(), -0.5f * getHeight()); + mDrawable.setAlpha((int) Math.round(mAlpha * 255f)); + mDrawable.draw(canvas); + canvas.restore(); + } +} diff --git a/core/java/com/android/internal/widget/multiwaveview/Tweener.java b/core/java/com/android/internal/widget/multiwaveview/Tweener.java new file mode 100644 index 000000000000..c2746d97a323 --- /dev/null +++ b/core/java/com/android/internal/widget/multiwaveview/Tweener.java @@ -0,0 +1,132 @@ +/* + * 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.multiwaveview; + +import java.util.ArrayList; +import java.util.HashMap; + +import android.animation.Animator.AnimatorListener; +import android.animation.ObjectAnimator; +import android.animation.PropertyValuesHolder; +import android.animation.TimeInterpolator; +import android.animation.ValueAnimator.AnimatorUpdateListener; + +class Tweener { + private static final String TAG = "Tweener"; + + private Object object; + ObjectAnimator animator; + private static HashMap<Object, Tweener> sTweens = new HashMap<Object, Tweener>(); + + public Tweener(Object obj, ObjectAnimator anim) { + object = obj; + animator = anim; + } + + public static Tweener to(Object object, long duration, Object... vars) { + long delay = 0; + AnimatorUpdateListener updateListener = null; + AnimatorListener listener = null; + TimeInterpolator interpolator = null; + + // Iterate through arguments and discover properties to animate + ArrayList<PropertyValuesHolder> props = new ArrayList<PropertyValuesHolder>(vars.length/2); + for (int i = 0; i < vars.length; i+=2) { + if (!(vars[i] instanceof String)) { + throw new IllegalArgumentException("Key must be a string: " + vars[i]); + } + String key = (String) vars[i]; + Object value = vars[i+1]; + if ("simultaneousTween".equals(key)) { + // TODO + } else if ("ease".equals(key)) { + interpolator = (TimeInterpolator) value; // TODO: multiple interpolators? + } else if ("onUpdate".equals(key) || "onUpdateListener".equals(key)) { + updateListener = (AnimatorUpdateListener) value; + } else if ("onComplete".equals(key) || "onCompleteListener".equals(key)) { + listener = (AnimatorListener) value; + } else if ("delay".equals(key)) { + delay = ((Number) value).longValue(); + } else if ("syncWith".equals(key)) { + // TODO + } else if (value instanceof Number[]) { + // TODO: support Tween.from() + } else if (value instanceof Number) { + float floatValue = ((Number)value).floatValue(); + props.add(PropertyValuesHolder.ofFloat(key, floatValue)); + } else { + throw new IllegalArgumentException( + "Bad argument for key \"" + key + "with value" + value); + } + } + + // Re-use existing tween, if present + Tweener tween = sTweens.get(object); + if (tween == null) { + ObjectAnimator anim = ObjectAnimator.ofPropertyValuesHolder(object, + props.toArray(new PropertyValuesHolder[props.size()])); + tween = new Tweener(object, anim); + sTweens.put(object, tween); + } else { + tween.animator.cancel(); + replace(props, object); + } + + if (interpolator != null) { + tween.animator.setInterpolator(interpolator); + } + + // Update animation with properties discovered in loop above + tween.animator.setStartDelay(delay); + tween.animator.setDuration(duration); + if (updateListener != null) { + tween.animator.removeAllUpdateListeners(); // There should be only one + tween.animator.addUpdateListener(updateListener); + } + if (listener != null) { + tween.animator.removeAllListeners(); // There should be only one. + tween.animator.addListener(listener); + } + tween.animator.start(); + + return tween; + } + + Tweener from(Object object, long duration, Object... vars) { + // TODO: for v of vars + // toVars[v] = object[v] + // object[v] = vars[v] + return Tweener.to(object, duration, vars); + } + + static void replace(ArrayList<PropertyValuesHolder> props, Object... args) { + for (final Object killobject : args) { + Tweener tween = sTweens.get(killobject); + if (tween != null) { + if (killobject == tween.object) { + tween.animator.cancel(); + if (props != null) { + tween.animator.setValues( + props.toArray(new PropertyValuesHolder[props.size()])); + } else { + sTweens.remove(tween); + } + } + } + } + } +} diff --git a/core/jni/Android.mk b/core/jni/Android.mk index cfff0ca49f74..7b0882f55cd9 100644 --- a/core/jni/Android.mk +++ b/core/jni/Android.mk @@ -104,6 +104,7 @@ LOCAL_SRC_FILES:= \ android/graphics/NinePatchImpl.cpp \ android/graphics/NinePatchPeeker.cpp \ android/graphics/Paint.cpp \ + android/graphics/ParcelSurfaceTexture.cpp \ android/graphics/Path.cpp \ android/graphics/PathMeasure.cpp \ android/graphics/PathEffect.cpp \ diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp index 455209584f22..21b0a42c087e 100644 --- a/core/jni/AndroidRuntime.cpp +++ b/core/jni/AndroidRuntime.cpp @@ -105,6 +105,7 @@ extern int register_android_graphics_ColorFilter(JNIEnv* env); extern int register_android_graphics_DrawFilter(JNIEnv* env); extern int register_android_graphics_Matrix(JNIEnv* env); extern int register_android_graphics_Paint(JNIEnv* env); +extern int register_android_graphics_ParcelSurfaceTexture(JNIEnv* env); extern int register_android_graphics_Path(JNIEnv* env); extern int register_android_graphics_PathMeasure(JNIEnv* env); extern int register_android_graphics_Picture(JNIEnv*); @@ -1142,6 +1143,7 @@ static const RegJNIRec gRegJNI[] = { REG_JNI(register_android_graphics_Movie), REG_JNI(register_android_graphics_NinePatch), REG_JNI(register_android_graphics_Paint), + REG_JNI(register_android_graphics_ParcelSurfaceTexture), REG_JNI(register_android_graphics_Path), REG_JNI(register_android_graphics_PathMeasure), REG_JNI(register_android_graphics_PathEffect), diff --git a/core/jni/android/graphics/ParcelSurfaceTexture.cpp b/core/jni/android/graphics/ParcelSurfaceTexture.cpp new file mode 100644 index 000000000000..517d7e28f71b --- /dev/null +++ b/core/jni/android/graphics/ParcelSurfaceTexture.cpp @@ -0,0 +1,152 @@ +/* + * 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. + */ + +#define LOG_TAG "ParcelSurfaceTexture" + +#include <gui/SurfaceTextureClient.h> + +#include <android_runtime/AndroidRuntime.h> + +#include <utils/Log.h> + +#include <binder/Parcel.h> + +#include "android_util_Binder.h" +#include "jni.h" +#include "JNIHelp.h" +#include "SurfaceTexture.h" + +// ---------------------------------------------------------------------------- + +namespace android { + +const char* const kParcelSurfaceTextureClassPathName = + "android/graphics/ParcelSurfaceTexture"; + +struct fields_t { + jfieldID iSurfaceTexture; +}; +static fields_t fields; + +#define ANDROID_GRAPHICS_ISURFACETEXTURE_JNI_ID "mISurfaceTexture" + +// ---------------------------------------------------------------------------- + +static void ParcelSurfaceTexture_setISurfaceTexture( + JNIEnv* env, jobject thiz, const sp<ISurfaceTexture>& iSurfaceTexture) +{ + ISurfaceTexture* const p = + (ISurfaceTexture*)env->GetIntField(thiz, fields.iSurfaceTexture); + if (iSurfaceTexture.get()) { + iSurfaceTexture->incStrong(thiz); + } + if (p) { + p->decStrong(thiz); + } + env->SetIntField(thiz, fields.iSurfaceTexture, (int)iSurfaceTexture.get()); +} + +static sp<ISurfaceTexture> ParcelSurfaceTexture_getISurfaceTexture( + JNIEnv* env, jobject thiz) +{ + sp<ISurfaceTexture> iSurfaceTexture( + (ISurfaceTexture*)env->GetIntField(thiz, fields.iSurfaceTexture)); + return iSurfaceTexture; +} + +sp<ANativeWindow> android_ParcelSurfaceTexture_getNativeWindow( + JNIEnv* env, jobject thiz) +{ + sp<ISurfaceTexture> iSurfaceTexture( + ParcelSurfaceTexture_getISurfaceTexture(env, thiz)); + sp<SurfaceTextureClient> surfaceTextureClient(iSurfaceTexture != NULL ? + new SurfaceTextureClient(iSurfaceTexture) : NULL); + return surfaceTextureClient; +} + +bool android_ParcelSurfaceTexture_isInstanceOf(JNIEnv* env, jobject thiz) +{ + jclass parcelSurfaceTextureClass = env->FindClass( + kParcelSurfaceTextureClassPathName); + return env->IsInstanceOf(thiz, parcelSurfaceTextureClass); +} + +// ---------------------------------------------------------------------------- + +static void ParcelSurfaceTexture_classInit(JNIEnv* env, jclass clazz) +{ + fields.iSurfaceTexture = + env->GetFieldID(clazz, ANDROID_GRAPHICS_ISURFACETEXTURE_JNI_ID, "I"); + if (fields.iSurfaceTexture == NULL) { + LOGE("can't find android/graphics/ParcelSurfaceTexture.%s", + ANDROID_GRAPHICS_ISURFACETEXTURE_JNI_ID); + } +} + +static void ParcelSurfaceTexture_init(JNIEnv* env, jobject thiz, jobject jSurfaceTexture) +{ + sp<ISurfaceTexture> iSurfaceTexture( + SurfaceTexture_getSurfaceTexture(env, jSurfaceTexture)); + ParcelSurfaceTexture_setISurfaceTexture(env, thiz, iSurfaceTexture); +} + +static void ParcelSurfaceTexture_finalize(JNIEnv* env, jobject thiz) +{ + ParcelSurfaceTexture_setISurfaceTexture(env, thiz, 0); +} + +static void ParcelSurfaceTexture_writeToParcel( + JNIEnv* env, jobject thiz, jobject jParcel, jint flags) +{ + Parcel* parcel = parcelForJavaObject(env, jParcel); + sp<ISurfaceTexture> iSurfaceTexture( + ParcelSurfaceTexture_getISurfaceTexture(env, thiz)); + sp<IBinder> b(iSurfaceTexture->asBinder()); + parcel->writeStrongBinder(b); +} + +static void ParcelSurfaceTexture_readFromParcel( + JNIEnv* env, jobject thiz, jobject jParcel) +{ + Parcel* parcel = parcelForJavaObject(env, jParcel); + sp<ISurfaceTexture> iSurfaceTexture( + interface_cast<ISurfaceTexture>(parcel->readStrongBinder())); + ParcelSurfaceTexture_setISurfaceTexture(env, thiz, iSurfaceTexture); +} + +// ---------------------------------------------------------------------------- + +static JNINativeMethod gParcelSurfaceTextureMethods[] = { + {"nativeClassInit", "()V", (void*)ParcelSurfaceTexture_classInit }, + {"nativeInit", "(Landroid/graphics/SurfaceTexture;)V", + (void *)ParcelSurfaceTexture_init }, + { "nativeFinalize", "()V", (void *)ParcelSurfaceTexture_finalize }, + { "nativeWriteToParcel", "(Landroid/os/Parcel;I)V", + (void *)ParcelSurfaceTexture_writeToParcel }, + { "nativeReadFromParcel", "(Landroid/os/Parcel;)V", + (void *)ParcelSurfaceTexture_readFromParcel }, +}; + + +int register_android_graphics_ParcelSurfaceTexture(JNIEnv* env) +{ + int err = 0; + err = AndroidRuntime::registerNativeMethods(env, kParcelSurfaceTextureClassPathName, + gParcelSurfaceTextureMethods, NELEM(gParcelSurfaceTextureMethods)); + return err; +} + +} // namespace android diff --git a/core/jni/android/graphics/SurfaceTexture.cpp b/core/jni/android/graphics/SurfaceTexture.cpp index 2f701904e1e5..3f922f620621 100644 --- a/core/jni/android/graphics/SurfaceTexture.cpp +++ b/core/jni/android/graphics/SurfaceTexture.cpp @@ -35,6 +35,7 @@ namespace android { static const char* const OutOfResourcesException = "android/graphics/SurfaceTexture$OutOfResourcesException"; +const char* const kSurfaceTextureClassPathName = "android/graphics/SurfaceTexture"; struct fields_t { jfieldID surfaceTexture; @@ -74,6 +75,12 @@ sp<ANativeWindow> android_SurfaceTexture_getNativeWindow( return surfaceTextureClient; } +bool android_SurfaceTexture_isInstanceOf(JNIEnv* env, jobject thiz) +{ + jclass surfaceTextureClass = env->FindClass(kSurfaceTextureClassPathName); + return env->IsInstanceOf(thiz, surfaceTextureClass); +} + // ---------------------------------------------------------------------------- class JNISurfaceTextureContext : public SurfaceTexture::FrameAvailableListener @@ -123,7 +130,6 @@ static void SurfaceTexture_classInit(JNIEnv* env, jclass clazz) if (fields.postEvent == NULL) { LOGE("can't find android/graphics/SurfaceTexture.postEventFromNative"); } - } static void SurfaceTexture_init(JNIEnv* env, jobject thiz, jint texName, @@ -156,6 +162,13 @@ static void SurfaceTexture_finalize(JNIEnv* env, jobject thiz) SurfaceTexture_setSurfaceTexture(env, thiz, 0); } +static void SurfaceTexture_setDefaultBufferSize( + JNIEnv* env, jobject thiz, jint width, jint height) +{ + sp<SurfaceTexture> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz)); + surfaceTexture->setDefaultBufferSize(width, height); +} + static void SurfaceTexture_updateTexImage(JNIEnv* env, jobject thiz) { sp<SurfaceTexture> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz)); @@ -179,12 +192,11 @@ static jlong SurfaceTexture_getTimestamp(JNIEnv* env, jobject thiz) // ---------------------------------------------------------------------------- -const char* const kSurfaceTextureClassPathName = "android/graphics/SurfaceTexture"; - static JNINativeMethod gSurfaceTextureMethods[] = { {"nativeClassInit", "()V", (void*)SurfaceTexture_classInit }, {"nativeInit", "(ILjava/lang/Object;)V", (void*)SurfaceTexture_init }, {"nativeFinalize", "()V", (void*)SurfaceTexture_finalize }, + {"nativeSetDefaultBufferSize", "(II)V", (void*)SurfaceTexture_setDefaultBufferSize }, {"nativeUpdateTexImage", "()V", (void*)SurfaceTexture_updateTexImage }, {"nativeGetTransformMatrix", "([F)V", (void*)SurfaceTexture_getTransformMatrix }, {"nativeGetTimestamp", "()J", (void*)SurfaceTexture_getTimestamp } diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestRelativeLayoutLtrActivity.java b/core/jni/android/graphics/SurfaceTexture.h index d6b8d02356ee..79d8dd3cbc50 100644 --- a/tests/BiDiTests/src/com/android/bidi/BiDiTestRelativeLayoutLtrActivity.java +++ b/core/jni/android/graphics/SurfaceTexture.h @@ -14,18 +14,18 @@ * limitations under the License. */ -package com.android.bidi; +#ifndef _ANDROID_GRAPHICS_SURFACETEXTURE_H +#define _ANDROID_GRAPHICS_SURFACETEXTURE_H -import android.app.Activity; -import android.os.Bundle; +#include <gui/SurfaceTexture.h> +#include <utils/StrongPointer.h> +#include "jni.h" -public class BiDiTestRelativeLayoutLtrActivity extends Activity { +namespace android { - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); +/* Gets the underlying SurfaceTexture from a SurfaceTexture Java object. */ +sp<SurfaceTexture> SurfaceTexture_getSurfaceTexture(JNIEnv* env, jobject thiz); - setContentView(R.layout.relative_layout_ltr); - } -} +} // namespace android +#endif // _ANDROID_GRAPHICS_SURFACETEXTURE_H diff --git a/core/jni/android_nfc_NdefMessage.cpp b/core/jni/android_nfc_NdefMessage.cpp index d9b64aa3f7bd..41099cb503af 100644 --- a/core/jni/android_nfc_NdefMessage.cpp +++ b/core/jni/android_nfc_NdefMessage.cpp @@ -102,6 +102,19 @@ static jint android_nfc_NdefMessage_parseNdefMessage(JNIEnv *e, jobject o, } TRACE("phFriNfc_NdefRecord_Parse() returned 0x%04x", status); + // We don't exactly know what *is* a valid length, but a simple + // sanity check is to make sure that the length of the header + // plus all fields does not exceed raw_msg_size. The min length + // of the header is 3 bytes: TNF, Type Length, Payload Length + // (ID length field is optional!) + uint64_t indicatedMsgLength = 3 + record.TypeLength + record.IdLength + + (uint64_t)record.PayloadLength; + if (indicatedMsgLength > + (uint64_t)raw_msg_size) { + LOGE("phFri_NdefRecord_Parse: invalid length field"); + goto end; + } + type = e->NewByteArray(record.TypeLength); if (type == NULL) { LOGD("NFC_Set Record Type Error\n"); diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp index ec8b6e07f325..70c2f7b41251 100644 --- a/core/jni/android_view_Surface.cpp +++ b/core/jni/android_view_Surface.cpp @@ -55,6 +55,9 @@ enum { static const char* const OutOfResourcesException = "android/view/Surface$OutOfResourcesException"; +const char* const kSurfaceSessionClassPathName = "android/view/SurfaceSession"; +const char* const kSurfaceClassPathName = "android/view/Surface"; + struct sso_t { jfieldID client; }; @@ -181,6 +184,11 @@ sp<ANativeWindow> android_Surface_getNativeWindow( return getSurface(env, clazz); } +bool android_Surface_isInstanceOf(JNIEnv* env, jobject obj) { + jclass surfaceClass = env->FindClass(kSurfaceClassPathName); + return env->IsInstanceOf(obj, surfaceClass); +} + static void setSurface(JNIEnv* env, jobject clazz, const sp<Surface>& surface) { Surface* const p = (Surface*)env->GetIntField(clazz, so.surface); @@ -759,8 +767,6 @@ static void Surface_writeToParcel( // ---------------------------------------------------------------------------- // ---------------------------------------------------------------------------- -const char* const kSurfaceSessionClassPathName = "android/view/SurfaceSession"; -const char* const kSurfaceClassPathName = "android/view/Surface"; static void nativeClassInit(JNIEnv* env, jclass clazz); static JNINativeMethod gSurfaceSessionMethods[] = { diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 3efb83c04b40..b2606c16d40b 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -159,6 +159,15 @@ android:label="@string/permlab_receiveMms" android:description="@string/permdesc_receiveMms" /> + <!-- Allows an application to receive emergency cell broadcast messages, + to record or display them to the user. Reserved for system apps. + @hide Pending API council approval --> + <permission android:name="android.permission.RECEIVE_EMERGENCY_BROADCAST" + android:permissionGroup="android.permission-group.MESSAGES" + android:protectionLevel="signatureOrSystem" + android:label="@string/permlab_receiveEmergencyBroadcast" + android:description="@string/permdesc_receiveEmergencyBroadcast" /> + <!-- Allows an application to read SMS messages. --> <permission android:name="android.permission.READ_SMS" android:permissionGroup="android.permission-group.MESSAGES" @@ -208,6 +217,22 @@ android:label="@string/permlab_writeContacts" android:description="@string/permdesc_writeContacts" /> + + <!-- Allows an application to read the user's personal profile data. --> + <permission android:name="android.permission.READ_PROFILE" + android:permissionGroup="android.permission-group.PERSONAL_INFO" + android:protectionLevel="dangerous" + android:label="@string/permlab_readProfile" + android:description="@string/permdesc_readProfile" /> + + <!-- Allows an application to write (but not read) the user's + personal profile data. --> + <permission android:name="android.permission.WRITE_PROFILE" + android:permissionGroup="android.permission-group.PERSONAL_INFO" + android:protectionLevel="dangerous" + android:label="@string/permlab_writeProfile" + android:description="@string/permdesc_writeProfile" /> + <!-- Allows an application to read the user's calendar data. --> <permission android:name="android.permission.READ_CALENDAR" android:permissionGroup="android.permission-group.PERSONAL_INFO" diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_answer_active.png b/core/res/res/drawable-hdpi/ic_lockscreen_answer_active.png Binary files differnew file mode 100644 index 000000000000..80899128f1bf --- /dev/null +++ b/core/res/res/drawable-hdpi/ic_lockscreen_answer_active.png diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_answer_focused.png b/core/res/res/drawable-hdpi/ic_lockscreen_answer_focused.png Binary files differnew file mode 100644 index 000000000000..e4ba8fdab78b --- /dev/null +++ b/core/res/res/drawable-hdpi/ic_lockscreen_answer_focused.png diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_answer_normal.png b/core/res/res/drawable-hdpi/ic_lockscreen_answer_normal.png Binary files differnew file mode 100644 index 000000000000..c9197c81b98d --- /dev/null +++ b/core/res/res/drawable-hdpi/ic_lockscreen_answer_normal.png diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_chevron_left.png b/core/res/res/drawable-hdpi/ic_lockscreen_chevron_left.png Binary files differnew file mode 100644 index 000000000000..d008afa1ef26 --- /dev/null +++ b/core/res/res/drawable-hdpi/ic_lockscreen_chevron_left.png diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_chevron_right.png b/core/res/res/drawable-hdpi/ic_lockscreen_chevron_right.png Binary files differnew file mode 100644 index 000000000000..e5089003c052 --- /dev/null +++ b/core/res/res/drawable-hdpi/ic_lockscreen_chevron_right.png diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_decline_activated.png b/core/res/res/drawable-hdpi/ic_lockscreen_decline_activated.png Binary files differnew file mode 100644 index 000000000000..98667697085f --- /dev/null +++ b/core/res/res/drawable-hdpi/ic_lockscreen_decline_activated.png diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_decline_focused.png b/core/res/res/drawable-hdpi/ic_lockscreen_decline_focused.png Binary files differnew file mode 100644 index 000000000000..f5dfacc48ea4 --- /dev/null +++ b/core/res/res/drawable-hdpi/ic_lockscreen_decline_focused.png diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_decline_normal.png b/core/res/res/drawable-hdpi/ic_lockscreen_decline_normal.png Binary files differnew file mode 100644 index 000000000000..b4d399d66d89 --- /dev/null +++ b/core/res/res/drawable-hdpi/ic_lockscreen_decline_normal.png diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_handle_normal.png b/core/res/res/drawable-hdpi/ic_lockscreen_handle_normal.png Binary files differnew file mode 100644 index 000000000000..e21a87caa40c --- /dev/null +++ b/core/res/res/drawable-hdpi/ic_lockscreen_handle_normal.png diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_handle_pressed.png b/core/res/res/drawable-hdpi/ic_lockscreen_handle_pressed.png Binary files differnew file mode 100644 index 000000000000..3283f99a555e --- /dev/null +++ b/core/res/res/drawable-hdpi/ic_lockscreen_handle_pressed.png diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_lock_normal.png b/core/res/res/drawable-hdpi/ic_lockscreen_lock_normal.png Binary files differnew file mode 100644 index 000000000000..732133c13a24 --- /dev/null +++ b/core/res/res/drawable-hdpi/ic_lockscreen_lock_normal.png diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_lock_pressed.png b/core/res/res/drawable-hdpi/ic_lockscreen_lock_pressed.png Binary files differnew file mode 100644 index 000000000000..0bbf62fd1231 --- /dev/null +++ b/core/res/res/drawable-hdpi/ic_lockscreen_lock_pressed.png diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_outerring.png b/core/res/res/drawable-hdpi/ic_lockscreen_outerring.png Binary files differnew file mode 100644 index 000000000000..5294bc5c805e --- /dev/null +++ b/core/res/res/drawable-hdpi/ic_lockscreen_outerring.png diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_silent_activated.png b/core/res/res/drawable-hdpi/ic_lockscreen_silent_activated.png Binary files differnew file mode 100644 index 000000000000..fce4980c74b8 --- /dev/null +++ b/core/res/res/drawable-hdpi/ic_lockscreen_silent_activated.png diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_silent_focused.png b/core/res/res/drawable-hdpi/ic_lockscreen_silent_focused.png Binary files differnew file mode 100644 index 000000000000..ecafbeaee1b5 --- /dev/null +++ b/core/res/res/drawable-hdpi/ic_lockscreen_silent_focused.png diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_silent_normal.png b/core/res/res/drawable-hdpi/ic_lockscreen_silent_normal.png Binary files differnew file mode 100644 index 000000000000..1f527b75ec42 --- /dev/null +++ b/core/res/res/drawable-hdpi/ic_lockscreen_silent_normal.png diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_soundon_activated.png b/core/res/res/drawable-hdpi/ic_lockscreen_soundon_activated.png Binary files differnew file mode 100644 index 000000000000..73f01c9e859c --- /dev/null +++ b/core/res/res/drawable-hdpi/ic_lockscreen_soundon_activated.png diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_soundon_focused.png b/core/res/res/drawable-hdpi/ic_lockscreen_soundon_focused.png Binary files differnew file mode 100644 index 000000000000..d4e558dcfe06 --- /dev/null +++ b/core/res/res/drawable-hdpi/ic_lockscreen_soundon_focused.png diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_soundon_normal.png b/core/res/res/drawable-hdpi/ic_lockscreen_soundon_normal.png Binary files differnew file mode 100644 index 000000000000..5d999a62d891 --- /dev/null +++ b/core/res/res/drawable-hdpi/ic_lockscreen_soundon_normal.png diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_text_activated.png b/core/res/res/drawable-hdpi/ic_lockscreen_text_activated.png Binary files differnew file mode 100644 index 000000000000..d01bdb273f7e --- /dev/null +++ b/core/res/res/drawable-hdpi/ic_lockscreen_text_activated.png diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_text_focusde.png b/core/res/res/drawable-hdpi/ic_lockscreen_text_focusde.png Binary files differnew file mode 100644 index 000000000000..72b8f0a742e4 --- /dev/null +++ b/core/res/res/drawable-hdpi/ic_lockscreen_text_focusde.png diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_text_normal.png b/core/res/res/drawable-hdpi/ic_lockscreen_text_normal.png Binary files differnew file mode 100644 index 000000000000..bf73a26b6f63 --- /dev/null +++ b/core/res/res/drawable-hdpi/ic_lockscreen_text_normal.png diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_unlock_activated.png b/core/res/res/drawable-hdpi/ic_lockscreen_unlock_activated.png Binary files differnew file mode 100644 index 000000000000..d333946642aa --- /dev/null +++ b/core/res/res/drawable-hdpi/ic_lockscreen_unlock_activated.png diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_unlock_focused.png b/core/res/res/drawable-hdpi/ic_lockscreen_unlock_focused.png Binary files differnew file mode 100644 index 000000000000..e0532228cad4 --- /dev/null +++ b/core/res/res/drawable-hdpi/ic_lockscreen_unlock_focused.png diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_unlock_normal.png b/core/res/res/drawable-hdpi/ic_lockscreen_unlock_normal.png Binary files differnew file mode 100644 index 000000000000..7db46c1a8c86 --- /dev/null +++ b/core/res/res/drawable-hdpi/ic_lockscreen_unlock_normal.png diff --git a/core/res/res/drawable-large-nodpi/default_wallpaper.jpg b/core/res/res/drawable-large-nodpi/default_wallpaper.jpg Binary files differnew file mode 100644 index 000000000000..7d7cdbbd5134 --- /dev/null +++ b/core/res/res/drawable-large-nodpi/default_wallpaper.jpg diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_answer_active.png b/core/res/res/drawable-mdpi/ic_lockscreen_answer_active.png Binary files differnew file mode 100644 index 000000000000..0ad03c0f211e --- /dev/null +++ b/core/res/res/drawable-mdpi/ic_lockscreen_answer_active.png diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_answer_focused.png b/core/res/res/drawable-mdpi/ic_lockscreen_answer_focused.png Binary files differnew file mode 100644 index 000000000000..f46e8bd0b993 --- /dev/null +++ b/core/res/res/drawable-mdpi/ic_lockscreen_answer_focused.png diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_answer_normal.png b/core/res/res/drawable-mdpi/ic_lockscreen_answer_normal.png Binary files differnew file mode 100644 index 000000000000..ddeeb18fc0e5 --- /dev/null +++ b/core/res/res/drawable-mdpi/ic_lockscreen_answer_normal.png diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_chevron_left.png b/core/res/res/drawable-mdpi/ic_lockscreen_chevron_left.png Binary files differnew file mode 100644 index 000000000000..e5ef113b0909 --- /dev/null +++ b/core/res/res/drawable-mdpi/ic_lockscreen_chevron_left.png diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_chevron_right.png b/core/res/res/drawable-mdpi/ic_lockscreen_chevron_right.png Binary files differnew file mode 100644 index 000000000000..ab723b711e94 --- /dev/null +++ b/core/res/res/drawable-mdpi/ic_lockscreen_chevron_right.png diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_decline_activated.png b/core/res/res/drawable-mdpi/ic_lockscreen_decline_activated.png Binary files differnew file mode 100644 index 000000000000..d1aae183448f --- /dev/null +++ b/core/res/res/drawable-mdpi/ic_lockscreen_decline_activated.png diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_decline_focused.png b/core/res/res/drawable-mdpi/ic_lockscreen_decline_focused.png Binary files differnew file mode 100644 index 000000000000..b52c844d2473 --- /dev/null +++ b/core/res/res/drawable-mdpi/ic_lockscreen_decline_focused.png diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_decline_normal.png b/core/res/res/drawable-mdpi/ic_lockscreen_decline_normal.png Binary files differnew file mode 100644 index 000000000000..722027ec086e --- /dev/null +++ b/core/res/res/drawable-mdpi/ic_lockscreen_decline_normal.png diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_handle_normal.png b/core/res/res/drawable-mdpi/ic_lockscreen_handle_normal.png Binary files differnew file mode 100644 index 000000000000..c10344f83bba --- /dev/null +++ b/core/res/res/drawable-mdpi/ic_lockscreen_handle_normal.png diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_handle_pressed.png b/core/res/res/drawable-mdpi/ic_lockscreen_handle_pressed.png Binary files differnew file mode 100644 index 000000000000..08c6cfe71bc6 --- /dev/null +++ b/core/res/res/drawable-mdpi/ic_lockscreen_handle_pressed.png diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_lock_normal.png b/core/res/res/drawable-mdpi/ic_lockscreen_lock_normal.png Binary files differnew file mode 100644 index 000000000000..30eb97473dc1 --- /dev/null +++ b/core/res/res/drawable-mdpi/ic_lockscreen_lock_normal.png diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_lock_pressed.png b/core/res/res/drawable-mdpi/ic_lockscreen_lock_pressed.png Binary files differnew file mode 100644 index 000000000000..aab2f6b065b6 --- /dev/null +++ b/core/res/res/drawable-mdpi/ic_lockscreen_lock_pressed.png diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_outerring.png b/core/res/res/drawable-mdpi/ic_lockscreen_outerring.png Binary files differnew file mode 100644 index 000000000000..4151f73a61e7 --- /dev/null +++ b/core/res/res/drawable-mdpi/ic_lockscreen_outerring.png diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_silent_activated.png b/core/res/res/drawable-mdpi/ic_lockscreen_silent_activated.png Binary files differnew file mode 100644 index 000000000000..3b2f3fc8579b --- /dev/null +++ b/core/res/res/drawable-mdpi/ic_lockscreen_silent_activated.png diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_silent_focused.png b/core/res/res/drawable-mdpi/ic_lockscreen_silent_focused.png Binary files differnew file mode 100644 index 000000000000..6a5af9d652eb --- /dev/null +++ b/core/res/res/drawable-mdpi/ic_lockscreen_silent_focused.png diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_silent_normal.png b/core/res/res/drawable-mdpi/ic_lockscreen_silent_normal.png Binary files differnew file mode 100644 index 000000000000..c288ce4284cd --- /dev/null +++ b/core/res/res/drawable-mdpi/ic_lockscreen_silent_normal.png diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_soundon_activated.png b/core/res/res/drawable-mdpi/ic_lockscreen_soundon_activated.png Binary files differnew file mode 100644 index 000000000000..03f524dea92a --- /dev/null +++ b/core/res/res/drawable-mdpi/ic_lockscreen_soundon_activated.png diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_soundon_focused.png b/core/res/res/drawable-mdpi/ic_lockscreen_soundon_focused.png Binary files differnew file mode 100644 index 000000000000..db59b5f3eee7 --- /dev/null +++ b/core/res/res/drawable-mdpi/ic_lockscreen_soundon_focused.png diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_soundon_normal.png b/core/res/res/drawable-mdpi/ic_lockscreen_soundon_normal.png Binary files differnew file mode 100644 index 000000000000..eb6ceedb8185 --- /dev/null +++ b/core/res/res/drawable-mdpi/ic_lockscreen_soundon_normal.png diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_text_activated.png b/core/res/res/drawable-mdpi/ic_lockscreen_text_activated.png Binary files differnew file mode 100644 index 000000000000..dbfc5babbc03 --- /dev/null +++ b/core/res/res/drawable-mdpi/ic_lockscreen_text_activated.png diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_text_focusde.png b/core/res/res/drawable-mdpi/ic_lockscreen_text_focusde.png Binary files differnew file mode 100644 index 000000000000..1de758664a22 --- /dev/null +++ b/core/res/res/drawable-mdpi/ic_lockscreen_text_focusde.png diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_text_normal.png b/core/res/res/drawable-mdpi/ic_lockscreen_text_normal.png Binary files differnew file mode 100644 index 000000000000..e007322b9a43 --- /dev/null +++ b/core/res/res/drawable-mdpi/ic_lockscreen_text_normal.png diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_unlock_activated.png b/core/res/res/drawable-mdpi/ic_lockscreen_unlock_activated.png Binary files differnew file mode 100644 index 000000000000..df479932ca8b --- /dev/null +++ b/core/res/res/drawable-mdpi/ic_lockscreen_unlock_activated.png diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_unlock_focused.png b/core/res/res/drawable-mdpi/ic_lockscreen_unlock_focused.png Binary files differnew file mode 100644 index 000000000000..6f51447744a2 --- /dev/null +++ b/core/res/res/drawable-mdpi/ic_lockscreen_unlock_focused.png diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_unlock_normal.png b/core/res/res/drawable-mdpi/ic_lockscreen_unlock_normal.png Binary files differnew file mode 100644 index 000000000000..dd255f57c7ee --- /dev/null +++ b/core/res/res/drawable-mdpi/ic_lockscreen_unlock_normal.png diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_answer_active.png b/core/res/res/drawable-xhdpi/ic_lockscreen_answer_active.png Binary files differnew file mode 100644 index 000000000000..8edf62dd2e89 --- /dev/null +++ b/core/res/res/drawable-xhdpi/ic_lockscreen_answer_active.png diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_answer_focused.png b/core/res/res/drawable-xhdpi/ic_lockscreen_answer_focused.png Binary files differnew file mode 100644 index 000000000000..2a47e9b6939c --- /dev/null +++ b/core/res/res/drawable-xhdpi/ic_lockscreen_answer_focused.png diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_answer_normal.png b/core/res/res/drawable-xhdpi/ic_lockscreen_answer_normal.png Binary files differnew file mode 100644 index 000000000000..f049dc9966b2 --- /dev/null +++ b/core/res/res/drawable-xhdpi/ic_lockscreen_answer_normal.png diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_chevron_left.png b/core/res/res/drawable-xhdpi/ic_lockscreen_chevron_left.png Binary files differnew file mode 100644 index 000000000000..75173cb701fd --- /dev/null +++ b/core/res/res/drawable-xhdpi/ic_lockscreen_chevron_left.png diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_chevron_right.png b/core/res/res/drawable-xhdpi/ic_lockscreen_chevron_right.png Binary files differnew file mode 100644 index 000000000000..9f6da72fbc13 --- /dev/null +++ b/core/res/res/drawable-xhdpi/ic_lockscreen_chevron_right.png diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_decline_activated.png b/core/res/res/drawable-xhdpi/ic_lockscreen_decline_activated.png Binary files differnew file mode 100644 index 000000000000..4244ca08865d --- /dev/null +++ b/core/res/res/drawable-xhdpi/ic_lockscreen_decline_activated.png diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_decline_focused.png b/core/res/res/drawable-xhdpi/ic_lockscreen_decline_focused.png Binary files differnew file mode 100644 index 000000000000..a98a379ba8bc --- /dev/null +++ b/core/res/res/drawable-xhdpi/ic_lockscreen_decline_focused.png diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_decline_normal.png b/core/res/res/drawable-xhdpi/ic_lockscreen_decline_normal.png Binary files differnew file mode 100644 index 000000000000..fa2a0f466ec3 --- /dev/null +++ b/core/res/res/drawable-xhdpi/ic_lockscreen_decline_normal.png diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_lock_normal.png b/core/res/res/drawable-xhdpi/ic_lockscreen_lock_normal.png Binary files differnew file mode 100644 index 000000000000..c44a33012aa6 --- /dev/null +++ b/core/res/res/drawable-xhdpi/ic_lockscreen_lock_normal.png diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_lock_pressed.png b/core/res/res/drawable-xhdpi/ic_lockscreen_lock_pressed.png Binary files differnew file mode 100644 index 000000000000..2264dc3fc9d7 --- /dev/null +++ b/core/res/res/drawable-xhdpi/ic_lockscreen_lock_pressed.png diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_outerring.png b/core/res/res/drawable-xhdpi/ic_lockscreen_outerring.png Binary files differnew file mode 100644 index 000000000000..0b4b26053850 --- /dev/null +++ b/core/res/res/drawable-xhdpi/ic_lockscreen_outerring.png diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_silent_activated.png b/core/res/res/drawable-xhdpi/ic_lockscreen_silent_activated.png Binary files differnew file mode 100644 index 000000000000..fd812116d7f5 --- /dev/null +++ b/core/res/res/drawable-xhdpi/ic_lockscreen_silent_activated.png diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_silent_focused.png b/core/res/res/drawable-xhdpi/ic_lockscreen_silent_focused.png Binary files differnew file mode 100644 index 000000000000..5a93472045b0 --- /dev/null +++ b/core/res/res/drawable-xhdpi/ic_lockscreen_silent_focused.png diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_silent_normal.png b/core/res/res/drawable-xhdpi/ic_lockscreen_silent_normal.png Binary files differnew file mode 100644 index 000000000000..73f6a2e7eda8 --- /dev/null +++ b/core/res/res/drawable-xhdpi/ic_lockscreen_silent_normal.png diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_soundon_activated.png b/core/res/res/drawable-xhdpi/ic_lockscreen_soundon_activated.png Binary files differnew file mode 100644 index 000000000000..9edc70bc09af --- /dev/null +++ b/core/res/res/drawable-xhdpi/ic_lockscreen_soundon_activated.png diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_soundon_focused.png b/core/res/res/drawable-xhdpi/ic_lockscreen_soundon_focused.png Binary files differnew file mode 100644 index 000000000000..0485af0baa05 --- /dev/null +++ b/core/res/res/drawable-xhdpi/ic_lockscreen_soundon_focused.png diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_soundon_normal.png b/core/res/res/drawable-xhdpi/ic_lockscreen_soundon_normal.png Binary files differnew file mode 100644 index 000000000000..6af5375b919b --- /dev/null +++ b/core/res/res/drawable-xhdpi/ic_lockscreen_soundon_normal.png diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_text_activated.png b/core/res/res/drawable-xhdpi/ic_lockscreen_text_activated.png Binary files differnew file mode 100644 index 000000000000..29c4572b5927 --- /dev/null +++ b/core/res/res/drawable-xhdpi/ic_lockscreen_text_activated.png diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_text_focusde.png b/core/res/res/drawable-xhdpi/ic_lockscreen_text_focusde.png Binary files differnew file mode 100644 index 000000000000..42c8ad2aed63 --- /dev/null +++ b/core/res/res/drawable-xhdpi/ic_lockscreen_text_focusde.png diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_text_normal.png b/core/res/res/drawable-xhdpi/ic_lockscreen_text_normal.png Binary files differnew file mode 100644 index 000000000000..ff65f209d439 --- /dev/null +++ b/core/res/res/drawable-xhdpi/ic_lockscreen_text_normal.png diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_unlock_activated.png b/core/res/res/drawable-xhdpi/ic_lockscreen_unlock_activated.png Binary files differnew file mode 100644 index 000000000000..fa0be9656ec3 --- /dev/null +++ b/core/res/res/drawable-xhdpi/ic_lockscreen_unlock_activated.png diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_unlock_focused.png b/core/res/res/drawable-xhdpi/ic_lockscreen_unlock_focused.png Binary files differnew file mode 100644 index 000000000000..d067ab8d29fd --- /dev/null +++ b/core/res/res/drawable-xhdpi/ic_lockscreen_unlock_focused.png diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_unlock_normal.png b/core/res/res/drawable-xhdpi/ic_lockscreen_unlock_normal.png Binary files differnew file mode 100644 index 000000000000..1a53c630c5b0 --- /dev/null +++ b/core/res/res/drawable-xhdpi/ic_lockscreen_unlock_normal.png diff --git a/core/res/res/drawable/ic_lockscreen_answer.xml b/core/res/res/drawable/ic_lockscreen_answer.xml new file mode 100644 index 000000000000..b42fc2a15a95 --- /dev/null +++ b/core/res/res/drawable/ic_lockscreen_answer.xml @@ -0,0 +1,30 @@ +<?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. +--> +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + + <item + android:state_enabled="true" + android:state_active="false" + android:state_focused="false" + android:drawable="@drawable/ic_lockscreen_answer_normal" /> + + <item + android:state_enabled="true" + android:state_active="true" + android:state_focused="false" + android:drawable="@drawable/ic_lockscreen_answer_active" /> + +</selector> diff --git a/core/res/res/drawable/ic_lockscreen_decline.xml b/core/res/res/drawable/ic_lockscreen_decline.xml new file mode 100644 index 000000000000..65128a1afb4c --- /dev/null +++ b/core/res/res/drawable/ic_lockscreen_decline.xml @@ -0,0 +1,30 @@ +<?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. +--> +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + + <item + android:state_enabled="true" + android:state_active="false" + android:state_focused="false" + android:drawable="@drawable/ic_lockscreen_decline_normal" /> + + <item + android:state_enabled="true" + android:state_active="true" + android:state_focused="false" + android:drawable="@drawable/ic_lockscreen_decline_activated" /> + +</selector> diff --git a/core/res/res/drawable/ic_lockscreen_handle.xml b/core/res/res/drawable/ic_lockscreen_handle.xml new file mode 100644 index 000000000000..e7b4a6e95f83 --- /dev/null +++ b/core/res/res/drawable/ic_lockscreen_handle.xml @@ -0,0 +1,30 @@ +<?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. +--> +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + + <item + android:state_enabled="true" + android:state_active="false" + android:state_focused="false" + android:drawable="@drawable/ic_lockscreen_handle_normal" /> + + <item + android:state_enabled="true" + android:state_active="true" + android:state_focused="false" + android:drawable="@drawable/ic_lockscreen_handle_pressed" /> + +</selector> diff --git a/core/res/res/drawable/ic_lockscreen_send_sms.xml b/core/res/res/drawable/ic_lockscreen_send_sms.xml new file mode 100644 index 000000000000..2503a5caff39 --- /dev/null +++ b/core/res/res/drawable/ic_lockscreen_send_sms.xml @@ -0,0 +1,30 @@ +<?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. +--> +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + + <item + android:state_enabled="true" + android:state_active="false" + android:state_focused="false" + android:drawable="@drawable/ic_lockscreen_text_normal" /> + + <item + android:state_enabled="true" + android:state_active="true" + android:state_focused="false" + android:drawable="@drawable/ic_lockscreen_text_activated" /> + +</selector> diff --git a/core/res/res/drawable/ic_lockscreen_silent.xml b/core/res/res/drawable/ic_lockscreen_silent.xml new file mode 100644 index 000000000000..2521eb7faf82 --- /dev/null +++ b/core/res/res/drawable/ic_lockscreen_silent.xml @@ -0,0 +1,30 @@ +<?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. +--> +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + + <item + android:state_enabled="true" + android:state_active="false" + android:state_focused="false" + android:drawable="@drawable/ic_lockscreen_silent_normal" /> + + <item + android:state_enabled="true" + android:state_active="true" + android:state_focused="false" + android:drawable="@drawable/ic_lockscreen_silent_activated" /> + +</selector> diff --git a/core/res/res/drawable/ic_lockscreen_soundon.xml b/core/res/res/drawable/ic_lockscreen_soundon.xml new file mode 100644 index 000000000000..2b306a5cdc75 --- /dev/null +++ b/core/res/res/drawable/ic_lockscreen_soundon.xml @@ -0,0 +1,30 @@ +<?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. +--> +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + + <item + android:state_enabled="true" + android:state_active="false" + android:state_focused="false" + android:drawable="@drawable/ic_lockscreen_soundon_normal" /> + + <item + android:state_enabled="true" + android:state_active="true" + android:state_focused="false" + android:drawable="@drawable/ic_lockscreen_soundon_activated" /> + +</selector> diff --git a/core/res/res/drawable/ic_lockscreen_unlock.xml b/core/res/res/drawable/ic_lockscreen_unlock.xml new file mode 100644 index 000000000000..0a49c18e8c52 --- /dev/null +++ b/core/res/res/drawable/ic_lockscreen_unlock.xml @@ -0,0 +1,30 @@ +<?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. +--> +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + + <item + android:state_enabled="true" + android:state_active="false" + android:state_focused="false" + android:drawable="@drawable/ic_lockscreen_unlock_normal" /> + + <item + android:state_enabled="true" + android:state_active="true" + android:state_focused="false" + android:drawable="@drawable/ic_lockscreen_unlock_activated" /> + +</selector> diff --git a/core/res/res/layout-sw600dp/keyguard_screen_tab_unlock.xml b/core/res/res/layout-sw600dp/keyguard_screen_tab_unlock.xml index c9c1692aa9aa..543747fc06d3 100644 --- a/core/res/res/layout-sw600dp/keyguard_screen_tab_unlock.xml +++ b/core/res/res/layout-sw600dp/keyguard_screen_tab_unlock.xml @@ -59,7 +59,7 @@ /> <com.android.internal.widget.WaveView - android:id="@+id/wave_view" + android:id="@+id/unlock_widget" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" diff --git a/core/res/res/layout-sw600dp/keyguard_screen_tab_unlock_land.xml b/core/res/res/layout-sw600dp/keyguard_screen_tab_unlock_land.xml index fbb9983b2665..c83f910cde5d 100644 --- a/core/res/res/layout-sw600dp/keyguard_screen_tab_unlock_land.xml +++ b/core/res/res/layout-sw600dp/keyguard_screen_tab_unlock_land.xml @@ -44,31 +44,22 @@ </RelativeLayout> <!-- right side --> - <LinearLayout - android:layout_height="match_parent" - android:layout_weight="1" - android:layout_width="0dip" - android:orientation="horizontal" - android:gravity="center_horizontal" - > - <TextView - android:id="@+id/screenLocked" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_below="@id/status2" - android:textAppearance="?android:attr/textAppearanceMedium" - android:gravity="center" - android:layout_marginTop="12dip" - android:drawablePadding="4dip" - /> + <RelativeLayout + android:layout_height="match_parent" + android:layout_weight="1" + android:layout_width="0dip" + android:gravity="center_horizontal|center_vertical"> <com.android.internal.widget.WaveView - android:id="@+id/wave_view" + android:id="@+id/unlock_widget" android:layout_width="wrap_content" - android:layout_height="match_parent" - android:layout_marginRight="0dip" - android:layout_weight="1.0" - /> + android:layout_height="wrap_content" + android:textAppearance="?android:attr/textAppearanceMedium" + android:gravity="center" + android:layout_marginTop="12dip" + android:layout_alignParentLeft="true" + android:layout_alignParentTop="true" + android:drawablePadding="4dip"/> <!-- "emergency calls only" shown when sim is missing or PUKd --> <TextView @@ -76,24 +67,35 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentTop="true" - android:layout_marginTop="20dip" + android:layout_alignParentRight="true" + android:layout_marginTop="12dip" android:text="@string/emergency_calls_only" - android:textAppearance="?android:attr/textAppearanceSmall" - android:textColor="@color/white" - /> + android:textAppearance="?android:attr/textAppearanceMedium" + android:textColor="@color/white"/> + - <!-- emergency call button shown when sim is PUKd and tab_selector is - hidden --> + <com.android.internal.widget.WaveView + android:id="@+id/wave_view" + android:layout_width="wrap_content" + android:layout_height="match_parent" + android:layout_gravity="center_vertical|center_horizontal" + android:layout_marginRight="0dip" + android:layout_weight="1.0"/> + + + <!-- emergency call button shown when sim is PUKd and tab_selector is hidden --> <Button android:id="@+id/emergencyCallButton" android:layout_width="wrap_content" android:layout_height="wrap_content" + android:layout_marginRight="80dip" + android:layout_marginBottom="80dip" + android:layout_alignParentRight="true" + android:layout_alignParentBottom="true" android:drawableLeft="@drawable/ic_emergency" style="@style/Widget.Button.Transparent" - android:drawablePadding="8dip" - android:layout_marginRight="80dip" - android:visibility="gone" - /> + android:drawablePadding="8dip"/> + + </RelativeLayout>> - </LinearLayout> </LinearLayout> diff --git a/core/res/res/layout/action_menu_item_layout.xml b/core/res/res/layout/action_menu_item_layout.xml index 5e828fae655d..4206dcb6137d 100644 --- a/core/res/res/layout/action_menu_item_layout.xml +++ b/core/res/res/layout/action_menu_item_layout.xml @@ -19,19 +19,20 @@ android:layout_height="wrap_content" android:layout_gravity="center" android:addStatesFromChildren="true" - android:background="?attr/selectableItemBackground" android:gravity="center" + android:focusable="true" android:paddingLeft="12dip" android:paddingRight="12dip" - android:minWidth="64dip" - android:minHeight="?attr/actionBarSize" - android:focusable="true"> + style="?android:attr/actionButtonStyle"> <ImageButton android:id="@+id/imageButton" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:visibility="gone" - android:padding="@dimen/action_bar_icon_vertical_padding" + android:paddingTop="@dimen/action_bar_icon_vertical_padding" + android:paddingBottom="@dimen/action_bar_icon_vertical_padding" + android:paddingLeft="4dip" + android:paddingRight="4dip" android:scaleType="fitCenter" android:adjustViewBounds="true" android:background="@null" @@ -45,6 +46,9 @@ style="?attr/buttonStyleSmall" android:textColor="?attr/actionMenuTextColor" android:background="@null" - android:padding="4dip" + android:paddingTop="4dip" + android:paddingBottom="4dip" + android:paddingLeft="4dip" + android:paddingRight="4dip" android:focusable="false" /> </com.android.internal.view.menu.ActionMenuItemView> diff --git a/core/res/res/layout/global_actions_item.xml b/core/res/res/layout/global_actions_item.xml index 68fe96053faa..67b164479cbe 100644 --- a/core/res/res/layout/global_actions_item.xml +++ b/core/res/res/layout/global_actions_item.xml @@ -40,7 +40,7 @@ android:layout_alignParentBottom="true" android:layout_alignParentRight="true" - android:textAppearance="?android:attr/textAppearanceSmallInverse" + android:textAppearance="?android:attr/textAppearanceSmall" /> @@ -54,7 +54,7 @@ android:layout_above="@id/status" android:layout_alignWithParentIfMissing="true" android:gravity="center_vertical" - android:textAppearance="?android:attr/textAppearanceLargeInverse" + android:textAppearance="?android:attr/textAppearanceLarge" /> diff --git a/core/res/res/layout/keyguard_screen_tab_unlock.xml b/core/res/res/layout/keyguard_screen_tab_unlock.xml index 5fe38d5405e3..24891dce7882 100644 --- a/core/res/res/layout/keyguard_screen_tab_unlock.xml +++ b/core/res/res/layout/keyguard_screen_tab_unlock.xml @@ -22,11 +22,11 @@ depending on the state of the device. It is the same for landscape and portrait.--> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:tabunlock="http://schemas.android.com/apk/res/com.android.tabunlock" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center_horizontal" - android:id="@+id/root"> + android:id="@+id/root" + android:clipChildren="false"> <TextView android:id="@+id/carrier" @@ -162,13 +162,25 @@ android:drawablePadding="4dip" /> - <com.android.internal.widget.SlidingTab - android:id="@+id/tab_selector" + <com.android.internal.widget.multiwaveview.MultiWaveView + android:id="@+id/unlock_widget" android:orientation="horizontal" android:layout_width="match_parent" - android:layout_height="wrap_content" + android:layout_height="300dip" android:layout_alignParentBottom="true" - android:layout_marginBottom="80dip" + + android:targetDrawables="@array/lockscreen_targets_when_silent" + android:handleDrawable="@drawable/ic_lockscreen_handle" + android:waveDrawable="@drawable/ic_lockscreen_outerring" + android:outerRadius="@*android:dimen/multiwaveview_target_placement_radius" + android:snapMargin="@*android:dimen/multiwaveview_snap_margin" + android:hitRadius="@*android:dimen/multiwaveview_hit_radius" + android:vibrationDuration="20" + android:leftChevronDrawable="@drawable/ic_lockscreen_chevron_left" + android:rightChevronDrawable="@drawable/ic_lockscreen_chevron_right" + android:feedbackCount="3" + android:horizontalOffset="0dip" + android:verticalOffset="60dip" /> <!-- emergency call button shown when sim is PUKd and tab_selector is diff --git a/core/res/res/layout/keyguard_screen_tab_unlock_land.xml b/core/res/res/layout/keyguard_screen_tab_unlock_land.xml index 3c2ad9af3154..02994a9bf841 100644 --- a/core/res/res/layout/keyguard_screen_tab_unlock_land.xml +++ b/core/res/res/layout/keyguard_screen_tab_unlock_land.xml @@ -21,11 +21,11 @@ state of the device, as well as instructions on how to get past it depending on the state of the device.--> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:tabunlock="http://schemas.android.com/apk/res/com.android.tabunlock" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal" - android:id="@+id/root"> + android:id="@+id/root" + android:clipChildren="false"> <!-- left side --> <RelativeLayout @@ -164,12 +164,23 @@ </RelativeLayout> <!-- right side --> - <com.android.internal.widget.SlidingTab - android:id="@+id/tab_selector" - android:orientation="vertical" - android:layout_width="wrap_content" + <com.android.internal.widget.multiwaveview.MultiWaveView + android:id="@+id/unlock_widget" + android:layout_width="300dip" android:layout_height="match_parent" - android:layout_marginRight="80dip" + + android:targetDrawables="@array/lockscreen_targets_when_silent" + android:handleDrawable="@drawable/ic_lockscreen_handle" + android:waveDrawable="@drawable/ic_lockscreen_outerring" + android:outerRadius="@*android:dimen/multiwaveview_target_placement_radius" + android:snapMargin="@*android:dimen/multiwaveview_snap_margin" + android:hitRadius="@*android:dimen/multiwaveview_hit_radius" + android:vibrationDuration="20" + android:leftChevronDrawable="@drawable/ic_lockscreen_chevron_left" + android:rightChevronDrawable="@drawable/ic_lockscreen_chevron_right" + android:feedbackCount="3" + android:horizontalOffset="60dip" + android:verticalOffset="0dip" /> <!-- emergency call button shown when sim is PUKd and tab_selector is diff --git a/core/res/res/layout/preference.xml b/core/res/res/layout/preference.xml index 1f92252b2d8d..448f89abc31d 100644 --- a/core/res/res/layout/preference.xml +++ b/core/res/res/layout/preference.xml @@ -22,7 +22,8 @@ android:layout_height="wrap_content" android:minHeight="?android:attr/listPreferredItemHeight" android:gravity="center_vertical" - android:paddingRight="?android:attr/scrollbarSize"> + android:paddingRight="?android:attr/scrollbarSize" + android:background="?android:attr/selectableItemBackground" > <ImageView android:id="@+android:id/icon" diff --git a/core/res/res/layout/preference_widget_switch.xml b/core/res/res/layout/preference_widget_switch.xml new file mode 100644 index 000000000000..ed4ed57c54c0 --- /dev/null +++ b/core/res/res/layout/preference_widget_switch.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2011 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<!-- Layout used by SwitchPreference for the switch widget style. This is inflated + inside android.R.layout.preference. --> +<Switch xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+android:id/switchWidget" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center" + android:padding="16dip" + android:focusable="false" + android:clickable="false" /> diff --git a/core/res/res/values-land/arrays.xml b/core/res/res/values-land/arrays.xml new file mode 100644 index 000000000000..85130ba16798 --- /dev/null +++ b/core/res/res/values-land/arrays.xml @@ -0,0 +1,37 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* //device/apps/common/assets/res/any/colors.xml +** +** Copyright 2006, 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. +*/ +--> +<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + + <!-- Resources for MultiWaveView in LockScreen --> + <array name="ic_lockscreen_targets_when_silent"> + <item>@null</item>" + <item>@drawable/ic_lockscreen_unlock</item> + <item>@null</item> + <item>@drawable/ic_lockscreen_soundon</item> + </array> + + <array name="ic_lockscreen_targets_when_soundon"> + <item>@null</item>" + <item>@drawable/ic_lockscreen_unlock</item> + <item>@null</item> + <item>@drawable/ic_lockscreen_silent</item> + </array> + +</resources> diff --git a/core/res/res/values/arrays.xml b/core/res/res/values/arrays.xml index 810c3b26423e..0f04a6724db1 100644 --- a/core/res/res/values/arrays.xml +++ b/core/res/res/values/arrays.xml @@ -333,4 +333,19 @@ <item>中文 (繁體)</item> </string-array> + <!-- Resources for MultiWaveView in LockScreen --> + <array name="lockscreen_targets_when_silent"> + <item>@drawable/ic_lockscreen_unlock</item> + <item>@null</item> + <item>@drawable/ic_lockscreen_soundon</item> + <item>@null</item> + </array> + + <array name="lockscreen_targets_when_soundon"> + <item>@drawable/ic_lockscreen_unlock</item> + <item>@null</item> + <item>@drawable/ic_lockscreen_silent</item> + <item>@null</item>" + </array> + </resources> diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index 4a7c6909ba56..acfdfc90cf6c 100755 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -374,11 +374,11 @@ pointer will go until that pointers go up thereby enabling touches with multiple pointers to be split across multiple windows. --> <attr name="windowEnableSplitTouch" format="boolean" /> - + <!-- Control whether a container should automatically close itself if the user touches outside of it. This only applies to activities and dialogs. - + <p>Note: this attribute will only be respected for applications that are targeting {@link android.os.Build.VERSION_CODES#HONEYCOMB} or later. --> @@ -548,7 +548,7 @@ <!-- NumberPicker input text style. --> <attr name="numberPickerInputTextStyle" format="reference" /> - <!-- The CalndarView style. --> + <!-- The CalendarView style. --> <attr name="calendarViewStyle" format="reference" /> <!-- The TimePicker style. --> @@ -658,6 +658,8 @@ <attr name="preferenceLayoutChild" format="reference" /> <!-- Preference panel style --> <attr name="preferencePanelStyle" format="reference" /> + <!-- Default style for switch preferences. --> + <attr name="switchPreferenceStyle" format="reference" /> <!-- ============================ --> <!-- Text selection handle styles --> @@ -1914,7 +1916,7 @@ <!-- Place the scroll bar on the right. --> <enum name="right" value="2" /> </attr> - + <!-- Specifies the type of layer backing this view. The default value is none. Refer to {@link android.view.View#setLayerType(int, android.graphics.Paint)} for more information.--> @@ -4814,7 +4816,7 @@ <!-- The view id of the AppWidget subview which should be auto-advanced. by the widget's host. --> <attr name="autoAdvanceViewId" format="reference" /> - <!-- Optional parameter which indicates if and how this widget can be + <!-- Optional parameter which indicates if and how this widget can be resized. --> <attr name="resizeMode" format="integer"> <flag name="none" value="0x0" /> @@ -5007,6 +5009,48 @@ </declare-styleable> <!-- =============================== --> + <!-- MultiWaveView class attributes --> + <!-- =============================== --> + <eat-comment /> + <declare-styleable name="MultiWaveView"> + <!-- Reference to an array resource that be shown as targets around a circle. --> + <attr name="targetDrawables" format="reference"/> + + <!-- Sets a drawable as the drag center. --> + <attr name="handleDrawable" format="reference" /> + + <!-- Drawable to use for chevron animation on the left. --> + <attr name="leftChevronDrawable" format="reference" /> + + <!-- Drawable to use for chevron animation on the right. --> + <attr name="rightChevronDrawable" format="reference" /> + + <!-- Drawable to use for wave ripple animation. --> + <attr name="waveDrawable" format="reference" /> + + <!-- Outer radius of target circle. Icons will be drawn on this circle. --> + <attr name="outerRadius" format="dimension" /> + + <!-- Size of target radius. Points within this distance of target center is a "hit". --> + <attr name="hitRadius" format="dimension" /> + + <!-- Tactile feedback duration for actions. Set to '0' for no vibration. --> + <attr name="vibrationDuration" format="integer"/> + + <!-- How close we need to be before snapping to a target. --> + <attr name="snapMargin" format="dimension" /> + + <!-- Number of waves/chevrons to show in animation. --> + <attr name="feedbackCount" format="integer" /> + + <!-- Used to shift center of pattern vertically. --> + <attr name="verticalOffset" format="dimension" /> + + <!-- Used to shift center of pattern horizontally. --> + <attr name="horizontalOffset" format="dimension" /> + </declare-styleable> + + <!-- =============================== --> <!-- LockPatternView class attributes --> <!-- =============================== --> <eat-comment /> @@ -5143,7 +5187,7 @@ </declare-styleable> <declare-styleable name="Storage"> - <!-- path to mount point for the storage --> + <!-- path to mount point for the storage --> <attr name="mountPoint" format="string" /> <!-- user visible description of the storage --> <attr name="storageDescription" format="string" /> @@ -5160,4 +5204,24 @@ <attr name="allowMassStorage" format="boolean" /> </declare-styleable> + <declare-styleable name="SwitchPreference"> + <!-- The summary for the Preference in a PreferenceActivity screen when the + SwitchPreference is checked. If separate on/off summaries are not + needed, the summary attribute can be used instead. --> + <attr name="summaryOn" /> + <!-- The summary for the Preference in a PreferenceActivity screen when the + SwitchPreference is unchecked. If separate on/off summaries are not + needed, the summary attribute can be used instead. --> + <attr name="summaryOff" /> + <!-- The text used on the switch itself when in the "on" state. + This should be a very SHORT string, as it appears in a small space. --> + <attr name="switchTextOn" format="string" /> + <!-- The text used on the switch itself when in the "off" state. + This should be a very SHORT string, as it appears in a small space. --> + <attr name="switchTextOff" format="string" /> + <!-- The state (true for on, or false for off) that causes dependents to be disabled. By default, + dependents will be disabled when this is unchecked, so the value of this preference is false. --> + <attr name="disableDependentsState" /> + </declare-styleable> + </resources> diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index bc98e8446f09..c95b0ae76bb3 100755 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -627,4 +627,7 @@ Example 2: devices sold in India should include tables 4 through 13 to enable use of the new Release 9 tables for Indic languages. --> <integer-array name="config_sms_enabled_locking_shift_tables"></integer-array> + + <!-- Set to true if the RSSI should always display CDMA signal strength even on EVDO --> + <bool name="config_alwaysUseCdmaRssi">false</bool> </resources> diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml index 724c528d4da7..df22f15f0034 100644 --- a/core/res/res/values/dimens.xml +++ b/core/res/res/values/dimens.xml @@ -57,6 +57,15 @@ <!-- Default correction for the space key in the password keyboard --> <dimen name="password_keyboard_spacebar_vertical_correction">4dip</dimen> + <!-- Default target placement radius for MultiWaveView --> + <dimen name="multiwaveview_target_placement_radius">135dip</dimen> + + <!-- Default distance beyond which MultiWaveView snaps to the target radius --> + <dimen name="multiwaveview_snap_margin">20dip</dimen> + + <!-- Default distance from each snap target that MultiWaveView considers a "hit" --> + <dimen name="multiwaveview_hit_radius">60dip</dimen> + <!-- Preference activity side margins --> <dimen name="preference_screen_side_margin">0dp</dimen> <!-- Preference activity side margins negative--> diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml index 55312e32815e..4108c1b9a5ea 100644 --- a/core/res/res/values/public.xml +++ b/core/res/res/values/public.xml @@ -1282,6 +1282,7 @@ Resources added in version 11 of the platform (Honeycomb / 3.0). =============================================================== --> <eat-comment /> + <public type="attr" name="allContactsName" id="0x010102cc" /> <public type="attr" name="windowActionBar" id="0x010102cd" /> <public type="attr" name="actionBarStyle" id="0x010102ce" /> @@ -1442,6 +1443,7 @@ <public type="interpolator" name="accelerate_quad" id="0x010c0000" /> <!-- Acceleration curve matching a quadtratic ease in function. --> <public type="interpolator" name="decelerate_quad" id="0x010c0001" /> + <!-- Acceleration curve matching a cubic ease out function. --> <public type="interpolator" name="accelerate_cubic" id="0x010c0002" /> <!-- Acceleration curve matching a cubic ease in function. --> @@ -1650,18 +1652,57 @@ <public type="attr" name="resizeMode" id="0x01010363" /> <!-- =============================================================== - Resources added in version 13 of the platform (Honeycomb MR 2) + Resources added in version 13 of the platform (Honeycomb MR 2 / 3.2) =============================================================== --> <eat-comment /> <public type="attr" name="requiresSmallestWidthDp" id="0x01010364" /> - <public type="attr" name="compatibleWidthLimitDp" /> - <public type="attr" name="largestWidthLimitDp" /> - - <public type="style" name="Theme.Holo.Light.NoActionBar" /> - <public type="style" name="Theme.Holo.Light.NoActionBar.Fullscreen" /> + <public type="attr" name="compatibleWidthLimitDp" id="0x01010365" /> + <public type="attr" name="largestWidthLimitDp" id="0x01010366" /> + + <public type="style" name="Theme.Holo.Light.NoActionBar" id="0x010300f0" /> + <public type="style" name="Theme.Holo.Light.NoActionBar.Fullscreen" id="0x010300f1" /> + + <public type="style" name="Widget.ActionBar.TabView" id="0x010300f2" /> + <public type="style" name="Widget.ActionBar.TabText" id="0x010300f3" /> + <public type="style" name="Widget.ActionBar.TabBar" id="0x010300f4" /> + <public type="style" name="Widget.Holo.ActionBar.TabView" id="0x010300f5" /> + <public type="style" name="Widget.Holo.ActionBar.TabText" id="0x010300f6" /> + <public type="style" name="Widget.Holo.ActionBar.TabBar" id="0x010300f7" /> + <public type="style" name="Widget.Holo.Light.ActionBar.TabView" id="0x010300f8" /> + <public type="style" name="Widget.Holo.Light.ActionBar.TabText" id="0x010300f9" /> + <public type="style" name="Widget.Holo.Light.ActionBar.TabBar" id="0x010300fa" /> + <public type="style" name="TextAppearance.Holo" id="0x010300fb" /> + <public type="style" name="TextAppearance.Holo.Inverse" id="0x010300fc" /> + <public type="style" name="TextAppearance.Holo.Large" id="0x010300fd" /> + <public type="style" name="TextAppearance.Holo.Large.Inverse" id="0x010300fe" /> + <public type="style" name="TextAppearance.Holo.Medium" id="0x010300ff" /> + <public type="style" name="TextAppearance.Holo.Medium.Inverse" id="0x01030100" /> + <public type="style" name="TextAppearance.Holo.Small" id="0x01030101" /> + <public type="style" name="TextAppearance.Holo.Small.Inverse" id="0x01030102" /> + <public type="style" name="TextAppearance.Holo.SearchResult.Title" id="0x01030103" /> + <public type="style" name="TextAppearance.Holo.SearchResult.Subtitle" id="0x01030104" /> + <public type="style" name="TextAppearance.Holo.Widget" id="0x01030105" /> + <public type="style" name="TextAppearance.Holo.Widget.Button" id="0x01030106" /> + <public type="style" name="TextAppearance.Holo.Widget.IconMenu.Item" id="0x01030107" /> + <public type="style" name="TextAppearance.Holo.Widget.TabWidget" id="0x01030108" /> + <public type="style" name="TextAppearance.Holo.Widget.TextView" id="0x01030109" /> + <public type="style" name="TextAppearance.Holo.Widget.TextView.PopupMenu" id="0x0103010a" /> + <public type="style" name="TextAppearance.Holo.Widget.DropDownHint" id="0x0103010b" /> + <public type="style" name="TextAppearance.Holo.Widget.DropDownItem" id="0x0103010c" /> + <public type="style" name="TextAppearance.Holo.Widget.TextView.SpinnerItem" id="0x0103010d" /> + <public type="style" name="TextAppearance.Holo.Widget.EditText" id="0x0103010e" /> + <public type="style" name="TextAppearance.Holo.Widget.PopupMenu" id="0x0103010f" /> + <public type="style" name="TextAppearance.Holo.Widget.PopupMenu.Large" id="0x01030110" /> + <public type="style" name="TextAppearance.Holo.Widget.PopupMenu.Small" id="0x01030111" /> + <public type="style" name="TextAppearance.Holo.Widget.ActionBar.Title" id="0x01030112" /> + <public type="style" name="TextAppearance.Holo.Widget.ActionBar.Subtitle" id="0x01030113" /> + <public type="style" name="TextAppearance.Holo.Widget.ActionMode.Title" id="0x01030114" /> + <public type="style" name="TextAppearance.Holo.Widget.ActionMode.Subtitle" id="0x01030115" /> + <public type="style" name="TextAppearance.Holo.WindowTitle" id="0x01030116" /> + <public type="style" name="TextAppearance.Holo.DialogWindowTitle" id="0x01030117" /> <!-- =============================================================== - Resources added in version 13 of the platform (Ice Cream Sandwich) + Resources added in version 14 of the platform (Ice Cream Sandwich) =============================================================== --> <eat-comment /> <public type="attr" name="state_hovered" /> @@ -1669,6 +1710,10 @@ <public type="attr" name="state_drag_hovered" /> <public type="attr" name="stopWithTask" /> + <public type="attr" name="switchTextOn" /> + <public type="attr" name="switchTextOff" /> + <public type="attr" name="switchPreferenceStyle" /> + <public type="style" name="TextAppearance.SuggestionHighlight" /> <public type="style" name="Theme.Holo.SplitActionBarWhenNarrow" /> <public type="style" name="Theme.Holo.Light.SplitActionBarWhenNarrow" /> @@ -1707,4 +1752,17 @@ <public type="attr" name="accessibilityFlags" /> <public type="attr" name="canRetrieveWindowContent" /> + <public type="attr" name="targetDrawables" /> + <public type="attr" name="handleDrawable" /> + <public type="attr" name="leftChevronDrawable" /> + <public type="attr" name="rightChevronDrawable" /> + <public type="attr" name="waveDrawable" /> + <public type="attr" name="outerRadius" /> + <public type="attr" name="hitRadius" /> + <public type="attr" name="vibrationDuration" /> + <public type="attr" name="snapMargin" /> + <public type="attr" name="feedbackCount" /> + <public type="attr" name="verticalOffset" /> + <public type="attr" name="horizontalOffset" /> + </resources> diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index bb03104fb616..3736157e3432 100755 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -459,6 +459,13 @@ your messages or delete them without showing them to you.</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_receiveEmergencyBroadcast">receive emergency broadcasts</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_receiveEmergencyBroadcast">Allows application to receive + and process emergency broadcast messages. This permission is only available + to system 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_sendSms">send SMS messages</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_sendSms">Allows application to send SMS @@ -895,6 +902,20 @@ applications can use this to erase or modify your contact data.</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_readProfile">read profile data</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_readProfile" product="default">Allows an application to read all + of your personal profile information. Malicious applications can use this to identify + you and send your personal information to other people.</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_writeProfile">write profile data</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_writeProfile" product="default">Allows an application to modify + your personal profile information. Malicious applications can use this to erase or + modify your profile data.</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_readCalendar">read calendar events</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_readCalendar" product="tablet">Allows an application to read all @@ -1458,6 +1479,10 @@ <!-- Description of policy access to require encrypted storage [CHAR LIMIT=110]--> <string name="policydesc_encryptedStorage">Require that stored application data be encrypted </string> + <!-- Title of policy access to disable all device cameras [CHAR LIMIT=30]--> + <string name="policylab_disableCamera">Disable cameras</string> + <!-- Description of policy access to disable all device cameras [CHAR LIMIT=110]--> + <string name="policydesc_disableCamera">Prevent use of all device cameras</string> <!-- The order of these is important, don't reorder without changing Contacts.java --> <skip /> <!-- Phone number types from android.provider.Contacts. This could be used when adding a new phone number for a contact, for example. --> @@ -1877,7 +1902,7 @@ <!-- Do not translate. WebView User Agent string --> <string name="web_user_agent" translatable="false">Mozilla/5.0 (Linux; U; <xliff:g id="x">Android %s</xliff:g>) - AppleWebKit/534.27 (KHTML, like Gecko) Version/4.0 <xliff:g id="mobile">%s</xliff:g>Safari/534.27</string> + AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 <xliff:g id="mobile">%s</xliff:g>Safari/534.30</string> <!-- Do not translate. WebView User Agent targeted content --> <string name="web_user_agent_target_content" translatable="false">"Mobile "</string> diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml index 06355283a89e..19b05c9489ef 100644 --- a/core/res/res/values/styles.xml +++ b/core/res/res/values/styles.xml @@ -903,6 +903,12 @@ <item name="android:widgetLayout">@android:layout/preference_widget_checkbox</item> </style> + <style name="Preference.SwitchPreference"> + <item name="android:widgetLayout">@android:layout/preference_widget_switch</item> + <item name="android:switchTextOn">@android:string/capital_on</item> + <item name="android:switchTextOff">@android:string/capital_off</item> + </style> + <style name="Preference.PreferenceScreen"> </style> @@ -947,6 +953,12 @@ <item name="android:widgetLayout">@android:layout/preference_widget_checkbox</item> </style> + <style name="Preference.Holo.SwitchPreference"> + <item name="android:widgetLayout">@android:layout/preference_widget_switch</item> + <item name="android:switchTextOn">@android:string/capital_on</item> + <item name="android:switchTextOff">@android:string/capital_off</item> + </style> + <style name="Preference.Holo.PreferenceScreen"> </style> @@ -1109,6 +1121,7 @@ <item name="android:paddingLeft">16dip</item> <item name="android:paddingRight">16dip</item> <item name="android:minWidth">64dip</item> + <item name="android:minHeight">?android:attr/actionBarSize</item> </style> <style name="Widget.ActionButton.Overflow"> @@ -1120,17 +1133,17 @@ <item name="android:src">?android:attr/actionModeCloseDrawable</item> </style> - <style name="Widget.ActionBarView_TabView"> + <style name="Widget.ActionBar.TabView" parent="Widget"> <item name="android:gravity">center_horizontal</item> <item name="android:background">@drawable/minitab_lt</item> <item name="android:paddingLeft">4dip</item> <item name="android:paddingRight">4dip</item> </style> - <style name="Widget.ActionBarView_TabBar"> + <style name="Widget.ActionBar.TabBar" parent="Widget"> </style> - <style name="Widget.ActionBarView_TabText"> + <style name="Widget.ActionBar.TabText" parent="Widget"> <item name="android:textAppearance">@style/TextAppearance.Widget.TextView.PopupMenu</item> <item name="android:textColor">?android:attr/textColorPrimaryInverse</item> <item name="android:textSize">18sp</item> @@ -1770,7 +1783,6 @@ <item name="android:gravity">center</item> <item name="android:paddingLeft">16dip</item> <item name="android:paddingRight">16dip</item> - <item name="android:minHeight">56dip</item> <item name="android:scaleType">center</item> </style> @@ -1785,22 +1797,22 @@ <style name="Widget.Holo.ActionButton.TextButton" parent="Widget.Holo.ButtonBar.Button"> </style> - <style name="Widget.Holo.ActionBarView_TabView" parent="Widget.ActionBarView_TabView"> + <style name="Widget.Holo.ActionBar.TabView" parent="Widget.ActionBar.TabView"> <item name="android:background">@drawable/tab_indicator_holo</item> <item name="android:paddingLeft">16dip</item> <item name="android:paddingRight">16dip</item> </style> - <style name="Widget.Holo.Tab" parent="Widget.Holo.ActionBarView_TabView"> + <style name="Widget.Holo.Tab" parent="Widget.Holo.ActionBar.TabView"> </style> - <style name="Widget.Holo.ActionBarView_TabBar" parent="Widget.ActionBarView_TabBar"> + <style name="Widget.Holo.ActionBar.TabBar" parent="Widget.ActionBar.TabBar"> <item name="android:divider">?android:attr/dividerVertical</item> <item name="android:showDividers">middle</item> <item name="android:dividerPadding">8dip</item> </style> - <style name="Widget.Holo.ActionBarView_TabText" parent="Widget.ActionBarView_TabText"> + <style name="Widget.Holo.ActionBar.TabText" parent="Widget.ActionBar.TabText"> <item name="android:textAppearance">@style/TextAppearance.Holo.Medium</item> <item name="android:textColor">?android:attr/textColorPrimary</item> <item name="android:textSize">18sp</item> @@ -2119,16 +2131,16 @@ <item name="android:contentDescription">@string/action_menu_overflow_description</item> </style> - <style name="Widget.Holo.Light.ActionBarView_TabView" parent="Widget.Holo.ActionBarView_TabView"> + <style name="Widget.Holo.Light.ActionBar.TabView" parent="Widget.Holo.ActionBar.TabView"> </style> - <style name="Widget.Holo.Light.Tab" parent="Widget.Holo.Light.ActionBarView_TabView"> + <style name="Widget.Holo.Light.Tab" parent="Widget.Holo.Light.ActionBar.TabView"> </style> - <style name="Widget.Holo.Light.ActionBarView_TabBar" parent="Widget.Holo.ActionBarView_TabBar"> + <style name="Widget.Holo.Light.ActionBar.TabBar" parent="Widget.Holo.ActionBar.TabBar"> </style> - <style name="Widget.Holo.Light.ActionBarView_TabText" parent="Widget.Holo.ActionBarView_TabText"> + <style name="Widget.Holo.Light.ActionBar.TabText" parent="Widget.Holo.ActionBar.TabText"> </style> <style name="Widget.Holo.Light.ActionMode" parent="Widget.Holo.ActionMode"> diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml index 4f39da429bd2..5f77dc5bcef5 100644 --- a/core/res/res/values/themes.xml +++ b/core/res/res/values/themes.xml @@ -247,6 +247,7 @@ <item name="preferenceStyle">@android:style/Preference</item> <item name="preferenceInformationStyle">@android:style/Preference.Information</item> <item name="checkBoxPreferenceStyle">@android:style/Preference.CheckBoxPreference</item> + <item name="switchPreferenceStyle">@android:style/Preference.SwitchPreference</item> <item name="yesNoPreferenceStyle">@android:style/Preference.DialogPreference.YesNoPreference</item> <item name="dialogPreferenceStyle">@android:style/Preference.DialogPreference</item> <item name="editTextPreferenceStyle">@android:style/Preference.DialogPreference.EditTextPreference</item> @@ -271,9 +272,9 @@ <item name="actionModeShareDrawable">@android:drawable/ic_menu_share_holo_dark</item> <item name="actionModeFindDrawable">@android:drawable/ic_menu_find_holo_dark</item> <item name="actionModeWebSearchDrawable">@android:drawable/ic_menu_search</item> - <item name="actionBarTabStyle">@style/Widget.ActionBarView_TabView</item> - <item name="actionBarTabBarStyle">@style/Widget.ActionBarView_TabBar</item> - <item name="actionBarTabTextStyle">@style/Widget.ActionBarView_TabText</item> + <item name="actionBarTabStyle">@style/Widget.ActionBar.TabView</item> + <item name="actionBarTabBarStyle">@style/Widget.ActionBar.TabBar</item> + <item name="actionBarTabTextStyle">@style/Widget.ActionBar.TabText</item> <item name="actionModeStyle">@style/Widget.ActionMode</item> <item name="actionModeCloseButtonStyle">@style/Widget.ActionButton.CloseMode</item> <item name="actionBarStyle">@android:style/Widget.ActionBar</item> @@ -687,7 +688,7 @@ <item name="android:imeExtractEnterAnimation">@android:anim/input_method_extract_enter</item> <item name="android:imeExtractExitAnimation">@android:anim/input_method_extract_exit</item> </style> - + <!-- Theme for the search input bar. --> <style name="Theme.SearchBar" parent="Theme.Holo.Light.Panel"> <item name="windowContentOverlay">@null</item> @@ -1003,6 +1004,7 @@ <item name="preferenceStyle">@android:style/Preference.Holo</item> <item name="preferenceInformationStyle">@android:style/Preference.Holo.Information</item> <item name="checkBoxPreferenceStyle">@android:style/Preference.Holo.CheckBoxPreference</item> + <item name="switchPreferenceStyle">@android:style/Preference.Holo.SwitchPreference</item> <item name="yesNoPreferenceStyle">@android:style/Preference.Holo.DialogPreference.YesNoPreference</item> <item name="dialogPreferenceStyle">@android:style/Preference.Holo.DialogPreference</item> <item name="editTextPreferenceStyle">@android:style/Preference.Holo.DialogPreference.EditTextPreference</item> @@ -1019,9 +1021,9 @@ <item name="actionOverflowButtonStyle">@android:style/Widget.Holo.ActionButton.Overflow</item> <item name="actionModeBackground">@android:drawable/cab_background_holo_dark</item> <item name="actionModeCloseDrawable">@android:drawable/cab_ic_close_holo</item> - <item name="actionBarTabStyle">@style/Widget.Holo.ActionBarView_TabView</item> - <item name="actionBarTabBarStyle">@style/Widget.Holo.ActionBarView_TabBar</item> - <item name="actionBarTabTextStyle">@style/Widget.Holo.ActionBarView_TabText</item> + <item name="actionBarTabStyle">@style/Widget.Holo.ActionBar.TabView</item> + <item name="actionBarTabBarStyle">@style/Widget.Holo.ActionBar.TabBar</item> + <item name="actionBarTabTextStyle">@style/Widget.Holo.ActionBar.TabText</item> <item name="actionModeStyle">@style/Widget.Holo.ActionMode</item> <item name="actionModeCloseButtonStyle">@style/Widget.Holo.ActionButton.CloseMode</item> <item name="actionBarStyle">@android:style/Widget.Holo.ActionBar</item> @@ -1291,6 +1293,7 @@ <item name="preferenceStyle">@android:style/Preference.Holo</item> <item name="preferenceInformationStyle">@android:style/Preference.Holo.Information</item> <item name="checkBoxPreferenceStyle">@android:style/Preference.Holo.CheckBoxPreference</item> + <item name="switchPreferenceStyle">@android:style/Preference.Holo.SwitchPreference</item> <item name="yesNoPreferenceStyle">@android:style/Preference.Holo.DialogPreference.YesNoPreference</item> <item name="dialogPreferenceStyle">@android:style/Preference.Holo.DialogPreference</item> <item name="editTextPreferenceStyle">@android:style/Preference.Holo.DialogPreference.EditTextPreference</item> @@ -1307,9 +1310,9 @@ <item name="actionOverflowButtonStyle">@android:style/Widget.Holo.Light.ActionButton.Overflow</item> <item name="actionModeBackground">@android:drawable/cab_background_holo_light</item> <item name="actionModeCloseDrawable">@android:drawable/cab_ic_close_holo</item> - <item name="actionBarTabStyle">@style/Widget.Holo.Light.ActionBarView_TabView</item> - <item name="actionBarTabBarStyle">@style/Widget.Holo.Light.ActionBarView_TabBar</item> - <item name="actionBarTabTextStyle">@style/Widget.Holo.Light.ActionBarView_TabText</item> + <item name="actionBarTabStyle">@style/Widget.Holo.Light.ActionBar.TabView</item> + <item name="actionBarTabBarStyle">@style/Widget.Holo.Light.ActionBar.TabBar</item> + <item name="actionBarTabTextStyle">@style/Widget.Holo.Light.ActionBar.TabText</item> <item name="actionModeStyle">@style/Widget.Holo.Light.ActionMode</item> <item name="actionModeCloseButtonStyle">@style/Widget.Holo.Light.ActionButton.CloseMode</item> <item name="actionBarStyle">@android:style/Widget.Holo.Light.ActionBar</item> diff --git a/core/tests/coretests/src/android/accessibilityservice/InterrogationActivityTest.java b/core/tests/coretests/src/android/accessibilityservice/InterrogationActivityTest.java index a20cc1f160ad..32606168c61e 100644 --- a/core/tests/coretests/src/android/accessibilityservice/InterrogationActivityTest.java +++ b/core/tests/coretests/src/android/accessibilityservice/InterrogationActivityTest.java @@ -29,7 +29,6 @@ import android.os.SystemClock; import android.provider.Settings; import android.test.ActivityInstrumentationTestCase2; import android.test.suitebuilder.annotation.LargeTest; -import android.util.Log; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityManager; import android.view.accessibility.AccessibilityNodeInfo; @@ -305,7 +304,14 @@ public class InterrogationActivityTest // focus the view assertTrue(button.performAction(ACTION_FOCUS)); - SystemClock.sleep(200); + + synchronized (sConnection) { + try { + sConnection.wait(500); + } catch (InterruptedException ie) { + /* ignore */ + } + } // check that last event source AccessibilityNodeInfo source = sLastAccessibilityEvent.getSource(); @@ -436,7 +442,10 @@ public class InterrogationActivityTest public void onInterrupt() {} public void onAccessibilityEvent(AccessibilityEvent event) { - sLastAccessibilityEvent= AccessibilityEvent.obtain(event); + sLastAccessibilityEvent = AccessibilityEvent.obtain(event); + synchronized (sConnection) { + sConnection.notifyAll(); + } } }; IAccessibilityManager manager = IAccessibilityManager.Stub.asInterface( diff --git a/core/tests/coretests/src/android/content/res/ConfigurationTest.java b/core/tests/coretests/src/android/content/res/ConfigurationTest.java new file mode 100644 index 000000000000..f1f745ea9be9 --- /dev/null +++ b/core/tests/coretests/src/android/content/res/ConfigurationTest.java @@ -0,0 +1,198 @@ +/* + * 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 android.content.res; + +import java.util.Locale; + +import android.test.AndroidTestCase; +import dalvik.annotation.TestLevel; +import dalvik.annotation.TestTargetNew; + +public class ConfigurationTest extends AndroidTestCase { + + @TestTargetNew( + level = TestLevel.COMPLETE, + method = "getLayoutDirectionFromLocale", + args = {Locale.class} + ) + public void testGetLayoutDirectionFromLocale() { + assertEquals(Configuration.LAYOUT_DIRECTION_UNDEFINED, + Configuration.getLayoutDirectionFromLocale(null)); + + assertEquals(Configuration.LAYOUT_DIRECTION_LTR, + Configuration.getLayoutDirectionFromLocale(Locale.ENGLISH)); + assertEquals(Configuration.LAYOUT_DIRECTION_LTR, + Configuration.getLayoutDirectionFromLocale(Locale.CANADA)); + assertEquals(Configuration.LAYOUT_DIRECTION_LTR, + Configuration.getLayoutDirectionFromLocale(Locale.CANADA_FRENCH)); + assertEquals(Configuration.LAYOUT_DIRECTION_LTR, + Configuration.getLayoutDirectionFromLocale(Locale.FRANCE)); + assertEquals(Configuration.LAYOUT_DIRECTION_LTR, + Configuration.getLayoutDirectionFromLocale(Locale.FRENCH)); + assertEquals(Configuration.LAYOUT_DIRECTION_LTR, + Configuration.getLayoutDirectionFromLocale(Locale.GERMAN)); + assertEquals(Configuration.LAYOUT_DIRECTION_LTR, + Configuration.getLayoutDirectionFromLocale(Locale.GERMANY)); + assertEquals(Configuration.LAYOUT_DIRECTION_LTR, + Configuration.getLayoutDirectionFromLocale(Locale.ITALIAN)); + assertEquals(Configuration.LAYOUT_DIRECTION_LTR, + Configuration.getLayoutDirectionFromLocale(Locale.ITALY)); + assertEquals(Configuration.LAYOUT_DIRECTION_LTR, + Configuration.getLayoutDirectionFromLocale(Locale.UK)); + assertEquals(Configuration.LAYOUT_DIRECTION_LTR, + Configuration.getLayoutDirectionFromLocale(Locale.US)); + + assertEquals(Configuration.LAYOUT_DIRECTION_UNDEFINED, + Configuration.getLayoutDirectionFromLocale(Locale.ROOT)); + + assertEquals(Configuration.LAYOUT_DIRECTION_LTR, + Configuration.getLayoutDirectionFromLocale(Locale.CHINA)); + assertEquals(Configuration.LAYOUT_DIRECTION_LTR, + Configuration.getLayoutDirectionFromLocale(Locale.CHINESE)); + assertEquals(Configuration.LAYOUT_DIRECTION_LTR, + Configuration.getLayoutDirectionFromLocale(Locale.JAPAN)); + assertEquals(Configuration.LAYOUT_DIRECTION_LTR, + Configuration.getLayoutDirectionFromLocale(Locale.JAPANESE)); + assertEquals(Configuration.LAYOUT_DIRECTION_LTR, + Configuration.getLayoutDirectionFromLocale(Locale.KOREA)); + assertEquals(Configuration.LAYOUT_DIRECTION_LTR, + Configuration.getLayoutDirectionFromLocale(Locale.KOREAN)); + assertEquals(Configuration.LAYOUT_DIRECTION_LTR, + Configuration.getLayoutDirectionFromLocale(Locale.PRC)); + assertEquals(Configuration.LAYOUT_DIRECTION_LTR, + Configuration.getLayoutDirectionFromLocale(Locale.SIMPLIFIED_CHINESE)); + assertEquals(Configuration.LAYOUT_DIRECTION_LTR, + Configuration.getLayoutDirectionFromLocale(Locale.TAIWAN)); + assertEquals(Configuration.LAYOUT_DIRECTION_LTR, + Configuration.getLayoutDirectionFromLocale(Locale.TRADITIONAL_CHINESE)); + + Locale locale = new Locale("ar"); + assertEquals(Configuration.LAYOUT_DIRECTION_RTL, + Configuration.getLayoutDirectionFromLocale(locale)); + locale = new Locale("ar", "AE"); + assertEquals(Configuration.LAYOUT_DIRECTION_RTL, + Configuration.getLayoutDirectionFromLocale(locale)); + locale = new Locale("ar", "BH"); + assertEquals(Configuration.LAYOUT_DIRECTION_RTL, + Configuration.getLayoutDirectionFromLocale(locale)); + locale = new Locale("ar", "DZ"); + assertEquals(Configuration.LAYOUT_DIRECTION_RTL, + Configuration.getLayoutDirectionFromLocale(locale)); + locale = new Locale("ar", "EG"); + assertEquals(Configuration.LAYOUT_DIRECTION_RTL, + Configuration.getLayoutDirectionFromLocale(locale)); + locale = new Locale("ar", "IQ"); + assertEquals(Configuration.LAYOUT_DIRECTION_RTL, + Configuration.getLayoutDirectionFromLocale(locale)); + locale = new Locale("ar", "JO"); + assertEquals(Configuration.LAYOUT_DIRECTION_RTL, + Configuration.getLayoutDirectionFromLocale(locale)); + locale = new Locale("ar", "KW"); + assertEquals(Configuration.LAYOUT_DIRECTION_RTL, + Configuration.getLayoutDirectionFromLocale(locale)); + locale = new Locale("ar", "LB"); + assertEquals(Configuration.LAYOUT_DIRECTION_RTL, + Configuration.getLayoutDirectionFromLocale(locale)); + locale = new Locale("ar", "LY"); + assertEquals(Configuration.LAYOUT_DIRECTION_RTL, + Configuration.getLayoutDirectionFromLocale(locale)); + locale = new Locale("ar", "MA"); + assertEquals(Configuration.LAYOUT_DIRECTION_RTL, + Configuration.getLayoutDirectionFromLocale(locale)); + locale = new Locale("ar", "OM"); + assertEquals(Configuration.LAYOUT_DIRECTION_RTL, + Configuration.getLayoutDirectionFromLocale(locale)); + locale = new Locale("ar", "QA"); + assertEquals(Configuration.LAYOUT_DIRECTION_RTL, + Configuration.getLayoutDirectionFromLocale(locale)); + locale = new Locale("ar", "SA"); + assertEquals(Configuration.LAYOUT_DIRECTION_RTL, + Configuration.getLayoutDirectionFromLocale(locale)); + locale = new Locale("ar", "SD"); + assertEquals(Configuration.LAYOUT_DIRECTION_RTL, + Configuration.getLayoutDirectionFromLocale(locale)); + locale = new Locale("ar", "SY"); + assertEquals(Configuration.LAYOUT_DIRECTION_RTL, + Configuration.getLayoutDirectionFromLocale(locale)); + locale = new Locale("ar", "TN"); + assertEquals(Configuration.LAYOUT_DIRECTION_RTL, + Configuration.getLayoutDirectionFromLocale(locale)); + locale = new Locale("ar", "YE"); + assertEquals(Configuration.LAYOUT_DIRECTION_RTL, + Configuration.getLayoutDirectionFromLocale(locale)); + + locale = new Locale("fa"); + assertEquals(Configuration.LAYOUT_DIRECTION_RTL, + Configuration.getLayoutDirectionFromLocale(locale)); + locale = new Locale("fa", "AF"); + assertEquals(Configuration.LAYOUT_DIRECTION_RTL, + Configuration.getLayoutDirectionFromLocale(locale)); + locale = new Locale("fa", "IR"); + assertEquals(Configuration.LAYOUT_DIRECTION_RTL, + Configuration.getLayoutDirectionFromLocale(locale)); + + locale = new Locale("iw"); + assertEquals(Configuration.LAYOUT_DIRECTION_RTL, + Configuration.getLayoutDirectionFromLocale(locale)); + locale = new Locale("iw", "IL"); + assertEquals(Configuration.LAYOUT_DIRECTION_RTL, + Configuration.getLayoutDirectionFromLocale(locale)); + locale = new Locale("he"); + assertEquals(Configuration.LAYOUT_DIRECTION_RTL, + Configuration.getLayoutDirectionFromLocale(locale)); + locale = new Locale("he", "IL"); + assertEquals(Configuration.LAYOUT_DIRECTION_RTL, + Configuration.getLayoutDirectionFromLocale(locale)); + + // The following test will not pass until we are able to take care about the scrip subtag + // thru having the "likelySubTags" file into ICU4C +// locale = new Locale("pa_Arab"); +// assertEquals(Configuration.LAYOUT_DIRECTION_RTL, +// Configuration.getLayoutDirectionFromLocale(locale)); +// locale = new Locale("pa_Arab", "PK"); +// assertEquals(Configuration.LAYOUT_DIRECTION_RTL, +// Configuration.getLayoutDirectionFromLocale(locale)); + + locale = new Locale("ps"); + assertEquals(Configuration.LAYOUT_DIRECTION_RTL, + Configuration.getLayoutDirectionFromLocale(locale)); + locale = new Locale("ps", "AF"); + assertEquals(Configuration.LAYOUT_DIRECTION_RTL, + Configuration.getLayoutDirectionFromLocale(locale)); + + // The following test will not work as the localized display name would be "Urdu" with ICU 4.4 + // We will need ICU 4.6 to get the correct localized display name +// locale = new Locale("ur"); +// assertEquals(Configuration.LAYOUT_DIRECTION_RTL, +// Configuration.getLayoutDirectionFromLocale(locale)); +// locale = new Locale("ur", "IN"); +// assertEquals(Configuration.LAYOUT_DIRECTION_RTL, +// Configuration.getLayoutDirectionFromLocale(locale)); +// locale = new Locale("ur", "PK"); +// assertEquals(Configuration.LAYOUT_DIRECTION_RTL, +// Configuration.getLayoutDirectionFromLocale(locale)); + + // The following test will not pass until we are able to take care about the scrip subtag + // thru having the "likelySubTags" file into ICU4C +// locale = new Locale("uz_Arab"); +// assertEquals(Configuration.LAYOUT_DIRECTION_RTL, +// Configuration.getLayoutDirectionFromLocale(locale)); +// locale = new Locale("uz_Arab", "AF"); +// assertEquals(Configuration.LAYOUT_DIRECTION_RTL, +// Configuration.getLayoutDirectionFromLocale(locale)); + } +} diff --git a/core/tests/coretests/src/android/net/NetworkStatsTest.java b/core/tests/coretests/src/android/net/NetworkStatsTest.java index 23eb9cf8a215..8a3e871edfa6 100644 --- a/core/tests/coretests/src/android/net/NetworkStatsTest.java +++ b/core/tests/coretests/src/android/net/NetworkStatsTest.java @@ -47,7 +47,7 @@ public class NetworkStatsTest extends TestCase { .addEntry(TEST_IFACE, 100, 1024, 0) .addEntry(TEST_IFACE, 101, 0, 1024).build(); - final NetworkStats result = after.subtract(before, true); + final NetworkStats result = after.subtract(before); // identical data should result in zero delta assertEquals(0, result.rx[0]); @@ -65,7 +65,7 @@ public class NetworkStatsTest extends TestCase { .addEntry(TEST_IFACE, 100, 1025, 2) .addEntry(TEST_IFACE, 101, 3, 1028).build(); - final NetworkStats result = after.subtract(before, true); + final NetworkStats result = after.subtract(before); // expect delta between measurements assertEquals(1, result.rx[0]); @@ -84,7 +84,7 @@ public class NetworkStatsTest extends TestCase { .addEntry(TEST_IFACE, 101, 0, 1024) .addEntry(TEST_IFACE, 102, 1024, 1024).build(); - final NetworkStats result = after.subtract(before, true); + final NetworkStats result = after.subtract(before); // its okay to have new rows assertEquals(0, result.rx[0]); diff --git a/data/etc/android.hardware.faketouch.multitouch.distinct.xml b/data/etc/android.hardware.faketouch.multitouch.distinct.xml new file mode 100644 index 000000000000..b6e8d09291f9 --- /dev/null +++ b/data/etc/android.hardware.faketouch.multitouch.distinct.xml @@ -0,0 +1,23 @@ +<?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. +--> + +<!-- This is the standard set of features for a indirect touch input device that supports + independently-trackable multiple-finger multitouch. --> +<permissions> + <feature name="android.hardware.faketouch.multitouch" /> + <feature name="android.hardware.faketouch.multitouch.distinct" /> + <feature name="android.hardware.faketouch" /> +</permissions> diff --git a/data/etc/android.hardware.faketouch.multitouch.jazzhand.xml b/data/etc/android.hardware.faketouch.multitouch.jazzhand.xml new file mode 100644 index 000000000000..7f0e70bad92e --- /dev/null +++ b/data/etc/android.hardware.faketouch.multitouch.jazzhand.xml @@ -0,0 +1,24 @@ +<?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. +--> + +<!-- This is the standard set of features for an indirect touch input device that supports + independently-trackable multiple-finger multitouch. --> +<permissions> + <feature name="android.hardware.faketouch.multitouch" /> + <feature name="android.hardware.faketouch.multitouch.distinct" /> + <feature name="android.hardware.faketouch.multitouch.jazzhand" /> + <feature name="android.hardware.faketouch" /> +</permissions> diff --git a/data/etc/android.hardware.faketouch.xml b/data/etc/android.hardware.faketouch.xml new file mode 100644 index 000000000000..cb9909782b80 --- /dev/null +++ b/data/etc/android.hardware.faketouch.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2011 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<!-- This is the standard set of features for a devices that does not have + a touch screen, but does have some other indirect input device such as + a track pad. --> +<permissions> + <feature name="android.hardware.faketouch" /> +</permissions> diff --git a/data/sounds/AllAudio.mk b/data/sounds/AllAudio.mk index 4e7a4033b875..2e18a109a5e0 100644 --- a/data/sounds/AllAudio.mk +++ b/data/sounds/AllAudio.mk @@ -18,3 +18,5 @@ $(call inherit-product, frameworks/base/data/sounds/OriginalAudio.mk) $(call inherit-product, frameworks/base/data/sounds/AudioPackage2.mk) $(call inherit-product, frameworks/base/data/sounds/AudioPackage3.mk) $(call inherit-product, frameworks/base/data/sounds/AudioPackage4.mk) +$(call inherit-product, frameworks/base/data/sounds/AudioPackage5.mk) +$(call inherit-product, frameworks/base/data/sounds/AudioPackage6.mk) diff --git a/graphics/java/android/graphics/ParcelSurfaceTexture.aidl b/graphics/java/android/graphics/ParcelSurfaceTexture.aidl new file mode 100644 index 000000000000..35ff285075fc --- /dev/null +++ b/graphics/java/android/graphics/ParcelSurfaceTexture.aidl @@ -0,0 +1,19 @@ +/** + * 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 android.graphics; + +parcelable ParcelSurfaceTexture; diff --git a/graphics/java/android/graphics/ParcelSurfaceTexture.java b/graphics/java/android/graphics/ParcelSurfaceTexture.java new file mode 100644 index 000000000000..5272cc6f7831 --- /dev/null +++ b/graphics/java/android/graphics/ParcelSurfaceTexture.java @@ -0,0 +1,102 @@ +/* + * 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 android.graphics; + +import android.graphics.SurfaceTexture; +import android.os.Parcel; +import android.os.Parcelable; + +/** + * + * @hide Pending review by API council. + */ +public final class ParcelSurfaceTexture implements Parcelable { + /** + * This field is used by native code, do not access or modify. + * + * @hide + */ + @SuppressWarnings({"UnusedDeclaration"}) + private int mISurfaceTexture; + + /** + * Create a new ParcelSurfaceTexture from a SurfaceTexture + * + * @param surfaceTexture The SurfaceTexture to transport. + * + * @return Returns a new ParcelSurfaceTexture for the given SurfaceTexture. + */ + public static ParcelSurfaceTexture fromSurfaceTexture(SurfaceTexture surfaceTexture) { + return new ParcelSurfaceTexture(surfaceTexture); + } + + /** + * @see android.os.Parcelable#describeContents() + */ + @Override + public int describeContents() { + return 0; + } + + /** + * @see android.os.Parcelable#writeToParcel(android.os.Parcel, int) + */ + @Override + public void writeToParcel(Parcel dest, int flags) { + nativeWriteToParcel(dest, flags); + } + + public static final Parcelable.Creator<ParcelSurfaceTexture> CREATOR = + new Parcelable.Creator<ParcelSurfaceTexture>() { + @Override + public ParcelSurfaceTexture createFromParcel(Parcel in) { + return new ParcelSurfaceTexture(in); + } + @Override + public ParcelSurfaceTexture[] newArray(int size) { + return new ParcelSurfaceTexture[size]; + } + }; + + private ParcelSurfaceTexture(Parcel in) { + nativeReadFromParcel(in); + } + private ParcelSurfaceTexture(SurfaceTexture surfaceTexture) { + nativeInit(surfaceTexture); + } + + @Override + protected void finalize() throws Throwable { + try { + nativeFinalize(); + } finally { + super.finalize(); + } + } + + private native void nativeInit(SurfaceTexture surfaceTexture); + private native void nativeFinalize(); + private native void nativeWriteToParcel(Parcel dest, int flags); + private native void nativeReadFromParcel(Parcel in); + + /* + * We use a class initializer to allow the native code to cache some + * field offsets. + */ + private static native void nativeClassInit(); + static { nativeClassInit(); } +} diff --git a/graphics/java/android/graphics/SurfaceTexture.java b/graphics/java/android/graphics/SurfaceTexture.java index 3c43a3923bd0..0ffd201500ac 100644 --- a/graphics/java/android/graphics/SurfaceTexture.java +++ b/graphics/java/android/graphics/SurfaceTexture.java @@ -118,6 +118,16 @@ public class SurfaceTexture { } /** + * Set the size of buffers returned by requestBuffers when a width and height + * of zero is requested. + * + * @hide Pending approval by API council. + */ + public void setDefaultBufferSize(int width, int height) { + nativeSetDefaultBufferSize(width, height); + } + + /** * Update the texture image to the most recent frame from the image stream. This may only be * called while the OpenGL ES context that owns the texture is bound to the thread. It will * implicitly bind its texture to the GL_TEXTURE_EXTERNAL_OES texture target. @@ -206,6 +216,7 @@ public class SurfaceTexture { private native void nativeFinalize(); private native void nativeGetTransformMatrix(float[] mtx); private native long nativeGetTimestamp(); + private native void nativeSetDefaultBufferSize(int width, int height); private native void nativeUpdateTexImage(); /* diff --git a/graphics/java/android/renderscript/BaseObj.java b/graphics/java/android/renderscript/BaseObj.java index a17e7351f58f..63e7dd1f74fa 100644 --- a/graphics/java/android/renderscript/BaseObj.java +++ b/graphics/java/android/renderscript/BaseObj.java @@ -134,5 +134,35 @@ public class BaseObj { mName = mRS.nGetName(getID()); } + /** + * Calculates the hash code value for a BaseObj. + * + * @return int + */ + @Override + public int hashCode() { + return mID; + } + + /** + * Compare the current BaseObj with another BaseObj for equality. + * + * @param obj The object to check equality with. + * + * @return boolean + */ + @Override + public boolean equals(Object obj) { + // Early-out check to see if both BaseObjs are actually the same + if (this == obj) + return true; + + if (getClass() != obj.getClass()) { + return false; + } + + BaseObj b = (BaseObj) obj; + return mID == b.mID; + } } diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestRelativeLayoutLtrActivity2.java b/include/android_runtime/android_graphics_ParcelSurfaceTexture.h index 476375c66d17..22f1c12a5106 100644 --- a/tests/BiDiTests/src/com/android/bidi/BiDiTestRelativeLayoutLtrActivity2.java +++ b/include/android_runtime/android_graphics_ParcelSurfaceTexture.h @@ -14,18 +14,19 @@ * limitations under the License. */ -package com.android.bidi; +#ifndef _ANDROID_GRAPHICS_PARCELSURFACETEXTURE_H +#define _ANDROID_GRAPHICS_PARCELSURFACETEXTURE_H -import android.app.Activity; -import android.os.Bundle; +#include <android/native_window.h> -public class BiDiTestRelativeLayoutLtrActivity2 extends Activity { +#include "jni.h" - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); +namespace android { - setContentView(R.layout.relative_layout_ltr_2); - } -} +extern sp<ANativeWindow> android_ParcelSurfaceTexture_getNativeWindow( + JNIEnv* env, jobject thiz); +extern bool android_ParcelSurfaceTexture_isInstanceOf(JNIEnv* env, jobject thiz); +} // namespace android + +#endif // _ANDROID_GRAPHICS_PARCELSURFACETEXTURE_H diff --git a/include/android_runtime/android_graphics_SurfaceTexture.h b/include/android_runtime/android_graphics_SurfaceTexture.h index 8e6fc6ee7fc2..acf1ca82b0a6 100644 --- a/include/android_runtime/android_graphics_SurfaceTexture.h +++ b/include/android_runtime/android_graphics_SurfaceTexture.h @@ -25,6 +25,8 @@ namespace android { extern sp<ANativeWindow> android_SurfaceTexture_getNativeWindow( JNIEnv* env, jobject thiz); +extern bool android_SurfaceTexture_isInstanceOf(JNIEnv* env, jobject thiz); + } // namespace android diff --git a/include/android_runtime/android_view_Surface.h b/include/android_runtime/android_view_Surface.h index c37932e74c4f..317f1e71c5f9 100644 --- a/include/android_runtime/android_view_Surface.h +++ b/include/android_runtime/android_view_Surface.h @@ -25,6 +25,7 @@ namespace android { extern sp<ANativeWindow> android_Surface_getNativeWindow( JNIEnv* env, jobject clazz); +extern bool android_Surface_isInstanceOf(JNIEnv* env, jobject obj); } // namespace android diff --git a/include/media/MediaPlayerInterface.h b/include/media/MediaPlayerInterface.h index f0401ccad7e0..18e8a5f39254 100644 --- a/include/media/MediaPlayerInterface.h +++ b/include/media/MediaPlayerInterface.h @@ -168,6 +168,10 @@ public: if (mNotify) mNotify(mCookie, msg, ext1, ext2, obj); } + virtual status_t dump(int fd, const Vector<String16> &args) const { + return INVALID_OPERATION; + } + private: friend class MediaPlayerService; diff --git a/include/utils/ResourceTypes.h b/include/utils/ResourceTypes.h index 8a92cd6e18f7..612ff93463a7 100644 --- a/include/utils/ResourceTypes.h +++ b/include/utils/ResourceTypes.h @@ -1988,7 +1988,8 @@ public: String16* outName, const String16* defType = NULL, const String16* defPackage = NULL, - const char** outErrorMsg = NULL); + const char** outErrorMsg = NULL, + bool* outPublicOnly = NULL); static bool stringToInt(const char16_t* s, size_t len, Res_value* outValue); static bool stringToFloat(const char16_t* s, size_t len, Res_value* outValue); diff --git a/keystore/java/android/security/IKeyChainAliasResponse.aidl b/keystore/java/android/security/IKeyChainAliasCallback.aidl index e0420017c1fc..1ea952166009 100644 --- a/keystore/java/android/security/IKeyChainAliasResponse.aidl +++ b/keystore/java/android/security/IKeyChainAliasCallback.aidl @@ -20,7 +20,7 @@ package android.security; * * @hide */ -interface IKeyChainAliasResponse { +interface IKeyChainAliasCallback { void alias(String alias); } diff --git a/keystore/java/android/security/KeyChain.java b/keystore/java/android/security/KeyChain.java index ba784edeed8e..4f1596df8b02 100644 --- a/keystore/java/android/security/KeyChain.java +++ b/keystore/java/android/security/KeyChain.java @@ -36,6 +36,7 @@ import java.io.IOException; import java.security.KeyFactory; import java.security.KeyPair; import java.security.NoSuchAlgorithmException; +import java.security.Principal; import java.security.PrivateKey; import java.security.cert.Certificate; import java.security.cert.CertificateException; @@ -47,8 +48,36 @@ import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; /** - * @hide + * The {@code KeyChain} class provides access to private keys and + * their corresponding certificate chains in credential storage. + * + * <p>Applications accessing the {@code KeyChain} normally go through + * these steps: + * + * <ol> + * + * <li>Receive a callback from an {@link javax.net.ssl.X509KeyManager + * X509KeyManager} that a private key is requested. + * + * <li>Call {@link #choosePrivateKeyAlias + * choosePrivateKeyAlias} to allow the user to select from a + * list of currently available private keys and corresponding + * certificate chains. The chosen alias will be returned by the + * callback {@link KeyChainAliasCallback#alias}, or null if no private + * key is available or the user cancels the request. + * + * <li>Call {@link #getPrivateKey} and {@link #getCertificateChain} to + * retrieve the credentials to return to the corresponding {@link + * javax.net.ssl.X509KeyManager} callbacks. + * + * </ol> + * + * <p>An application may remember the value of a selected alias to + * avoid prompting the user with {@link #choosePrivateKeyAlias + * choosePrivateKeyAlias} on subsequent connections. If the alias is + * no longer valid, null will be returned on lookups using that value */ +// TODO reference intent for credential installation when public public final class KeyChain { private static final String TAG = "KeyChain"; @@ -67,9 +96,58 @@ public final class KeyChain { * Launches an {@code Activity} for the user to select the alias * for a private key and certificate pair for authentication. The * selected alias or null will be returned via the - * IKeyChainAliasResponse callback. + * KeyChainAliasCallback callback. + * + * <p>{@code keyTypes} and {@code issuers} may be used to + * highlight suggested choices to the user, although to cope with + * sometimes erroneous values provided by servers, the user may be + * able to override these suggestions. + * + * <p>{@code host} and {@code port} may be used to give the user + * more context about the server requesting the credentials. + * + * <p>This method requires the caller to hold the permission + * {@link android.Manifest.permission#USE_CREDENTIALS}. + * + * @param activity The {@link Activity} context to use for + * launching the new sub-Activity to prompt the user to select + * a private key; used only to call startActivity(); must not + * be null. + * @param response Callback to invoke when the request completes; + * must not be null + * @param keyTypes The acceptable types of asymmetric keys such as + * "RSA" or "DSA", or a null array. + * @param issuers The acceptable certificate issuers for the + * certificate matching the private key, or null. + * @param host The host name of the server requesting the + * certificate, or null if unavailable. + * @param port The port number of the server requesting the + * certificate, or -1 if unavailable. */ - public static void choosePrivateKeyAlias(Activity activity, KeyChainAliasResponse response) { + public static void choosePrivateKeyAlias(Activity activity, KeyChainAliasCallback response, + String[] keyTypes, Principal[] issuers, + String host, int port) { + /* + * TODO currently keyTypes, issuers, host, and port are + * unused. They are meant to follow the semantics and purpose + * of X509KeyManager method arguments. + * + * keyTypes would allow the list to be filtered and typically + * will be set correctly by the server. In practice today, + * most all users will want only RSA, rarely DSA, and usually + * only a small number of certs will be available. + * + * issuers is typically not useful. Some servers historically + * will send the entire list of public CAs known to the + * server. Others will send none. If this is used, if there + * are no matches after applying the constraint, it should be + * ignored. + * + * host and port may be shown to the user if available, but it + * should be clear that they are not validated values, perhaps + * shown along with requesting application identity to clarify + * the source of the request. + */ if (activity == null) { throw new NullPointerException("activity == null"); } @@ -81,10 +159,10 @@ public final class KeyChain { activity.startActivity(intent); } - private static class AliasResponse extends IKeyChainAliasResponse.Stub { + private static class AliasResponse extends IKeyChainAliasCallback.Stub { private final Activity activity; - private final KeyChainAliasResponse keyChainAliasResponse; - private AliasResponse(Activity activity, KeyChainAliasResponse keyChainAliasResponse) { + private final KeyChainAliasCallback keyChainAliasResponse; + private AliasResponse(Activity activity, KeyChainAliasCallback keyChainAliasResponse) { this.activity = activity; this.keyChainAliasResponse = keyChainAliasResponse; } @@ -105,9 +183,9 @@ public final class KeyChain { } private static class AliasAccountManagerCallback implements AccountManagerCallback<Bundle> { - private final KeyChainAliasResponse keyChainAliasResponse; + private final KeyChainAliasCallback keyChainAliasResponse; private final String alias; - private AliasAccountManagerCallback(KeyChainAliasResponse keyChainAliasResponse, + private AliasAccountManagerCallback(KeyChainAliasCallback keyChainAliasResponse, String alias) { this.keyChainAliasResponse = keyChainAliasResponse; this.alias = alias; @@ -138,9 +216,16 @@ public final class KeyChain { /** * Returns the {@code PrivateKey} for the requested alias, or null * if no there is no result. + * + * <p>This method requires the caller to hold the permission + * {@link android.Manifest.permission#USE_CREDENTIALS}. + * + * @param alias The alias of the desired private key, typically + * returned via {@link KeyChainAliasCallback#alias}. + * @throws KeyChainException if the alias was valid but there was some problem accessing it. */ public static PrivateKey getPrivateKey(Context context, String alias) - throws InterruptedException, RemoteException { + throws KeyChainException, InterruptedException { if (alias == null) { throw new NullPointerException("alias == null"); } @@ -153,6 +238,11 @@ public final class KeyChain { IKeyChainService keyChainService = keyChainConnection.getService(); byte[] privateKeyBytes = keyChainService.getPrivateKey(alias, authToken); return toPrivateKey(privateKeyBytes); + } catch (RemoteException e) { + throw new KeyChainException(e); + } catch (RuntimeException e) { + // only certain RuntimeExceptions can be propagated across the IKeyChainService call + throw new KeyChainException(e); } finally { keyChainConnection.close(); } @@ -161,9 +251,16 @@ public final class KeyChain { /** * Returns the {@code X509Certificate} chain for the requested * alias, or null if no there is no result. + * + * <p>This method requires the caller to hold the permission + * {@link android.Manifest.permission#USE_CREDENTIALS}. + * + * @param alias The alias of the desired certificate chain, typically + * returned via {@link KeyChainAliasCallback#alias}. + * @throws KeyChainException if the alias was valid but there was some problem accessing it. */ public static X509Certificate[] getCertificateChain(Context context, String alias) - throws InterruptedException, RemoteException { + throws KeyChainException, InterruptedException { if (alias == null) { throw new NullPointerException("alias == null"); } @@ -176,6 +273,11 @@ public final class KeyChain { IKeyChainService keyChainService = keyChainConnection.getService(); byte[] certificateBytes = keyChainService.getCertificate(alias, authToken); return new X509Certificate[] { toCertificate(certificateBytes) }; + } catch (RemoteException e) { + throw new KeyChainException(e); + } catch (RuntimeException e) { + // only certain RuntimeExceptions can be propagated across the IKeyChainService call + throw new KeyChainException(e); } finally { keyChainConnection.close(); } diff --git a/keystore/java/android/security/KeyChainAliasResponse.java b/keystore/java/android/security/KeyChainAliasCallback.java index bcca123cd8d3..fc9e64b3236b 100644 --- a/keystore/java/android/security/KeyChainAliasResponse.java +++ b/keystore/java/android/security/KeyChainAliasCallback.java @@ -20,12 +20,10 @@ import java.security.PrivateKey; import java.security.cert.X509Certificate; /** - * The KeyChainAliasResponse is the callback for {@link - * KeyChain#chooseAlias}. - * - * @hide + * The KeyChainAliasCallback is the callback for {@link + * KeyChain#choosePrivateKeyAlias}. */ -public interface KeyChainAliasResponse { +public interface KeyChainAliasCallback { /** * Called with the alias of the certificate chosen by the user, or diff --git a/keystore/java/android/security/KeyChainException.java b/keystore/java/android/security/KeyChainException.java new file mode 100644 index 000000000000..ef97ffb4c436 --- /dev/null +++ b/keystore/java/android/security/KeyChainException.java @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.security; + +/** + * Thrown on problems accessing the {@link KeyChain}. + */ +public class KeyChainException extends Exception { + + /** + * Constructs a new {@code KeyChainException} that includes the + * current stack trace. + */ + public KeyChainException() { + } + + /** + * Constructs a new {@code KeyChainException} with the current stack + * trace and the specified detail message. + * + * @param detailMessage + * the detail message for this exception. + */ + public KeyChainException(String detailMessage) { + super(detailMessage); + } + + /** + * Constructs a new {@code KeyChainException} with the current stack + * trace, the specified detail message and the specified cause. + * + * @param message + * the detail message for this exception. + * @param cause + * the cause of this exception, may be {@code null}. + */ + public KeyChainException(String message, Throwable cause) { + super(message, cause); + } + + /** + * Constructs a new {@code KeyChainException} with the current stack + * trace and the specified cause. + * + * @param cause + * the cause of this exception, may be {@code null}. + */ + public KeyChainException(Throwable cause) { + super((cause == null ? null : cause.toString()), cause); + } +} diff --git a/libs/hwui/Matrix.cpp b/libs/hwui/Matrix.cpp index e7c0fe35194a..9fc5131ee931 100644 --- a/libs/hwui/Matrix.cpp +++ b/libs/hwui/Matrix.cpp @@ -67,6 +67,10 @@ bool Matrix4::isPureTranslate() { ALMOST_EQUAL(data[kScaleX], 1.0f) && ALMOST_EQUAL(data[kScaleY], 1.0f); } +bool Matrix4::isSimple() { + return mSimpleMatrix; +} + void Matrix4::load(const float* v) { memcpy(data, v, sizeof(data)); mSimpleMatrix = false; diff --git a/libs/hwui/Matrix.h b/libs/hwui/Matrix.h index 08f5d776d5f5..2fa6ab7757a7 100644 --- a/libs/hwui/Matrix.h +++ b/libs/hwui/Matrix.h @@ -111,6 +111,7 @@ public: } bool isPureTranslate(); + bool isSimple(); bool changesBounds(); diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp index 855805434015..6c9c0eb54ecf 100644 --- a/libs/hwui/OpenGLRenderer.cpp +++ b/libs/hwui/OpenGLRenderer.cpp @@ -1478,8 +1478,7 @@ void OpenGLRenderer::drawPatch(SkBitmap* bitmap, const int32_t* xDivs, const int * within that boundary region and how far into the region it is. */ void OpenGLRenderer::drawAARect(float left, float top, float right, float bottom, - int color, SkXfermode::Mode mode) -{ + int color, SkXfermode::Mode mode) { float inverseScaleX = 1.0f; float inverseScaleY = 1.0f; // The quad that we use needs to account for scaling. @@ -1935,7 +1934,7 @@ void OpenGLRenderer::drawRect(float left, float top, float right, float bottom, } int color = p->getColor(); - if (p->isAntiAlias()) { + if (p->isAntiAlias() && !mSnapshot->transform->isSimple()) { drawAARect(left, top, right, bottom, color, mode); } else { drawColorRect(left, top, right, bottom, color, mode); diff --git a/libs/rs/Android.mk b/libs/rs/Android.mk index 9c9fae3f05e8..9fabf8d1ab5c 100644 --- a/libs/rs/Android.mk +++ b/libs/rs/Android.mk @@ -149,24 +149,82 @@ include $(BUILD_SHARED_LIBRARY) # Now build a host version for serialization include $(CLEAR_VARS) +LOCAL_MODULE:= libRS +LOCAL_MODULE_TAGS := optional + +intermediates := $(call intermediates-dir-for,STATIC_LIBRARIES,libRS,HOST,) + +# Generate custom headers + +GEN := $(addprefix $(intermediates)/, \ + rsgApiStructs.h \ + rsgApiFuncDecl.h \ + ) + +$(GEN) : PRIVATE_PATH := $(LOCAL_PATH) +$(GEN) : PRIVATE_CUSTOM_TOOL = $(RSG_GENERATOR) $< $@ <$(PRIVATE_PATH)/rs.spec +$(GEN) : $(RSG_GENERATOR) $(LOCAL_PATH)/rs.spec +$(GEN): $(intermediates)/%.h : $(LOCAL_PATH)/%.h.rsg + $(transform-generated-source) + +LOCAL_GENERATED_SOURCES += $(GEN) + +# Generate custom source files + +GEN := $(addprefix $(intermediates)/, \ + rsgApi.cpp \ + rsgApiReplay.cpp \ + ) + +$(GEN) : PRIVATE_PATH := $(LOCAL_PATH) +$(GEN) : PRIVATE_CUSTOM_TOOL = $(RSG_GENERATOR) $< $@ <$(PRIVATE_PATH)/rs.spec +$(GEN) : $(RSG_GENERATOR) $(LOCAL_PATH)/rs.spec +$(GEN): $(intermediates)/%.cpp : $(LOCAL_PATH)/%.cpp.rsg + $(transform-generated-source) + +LOCAL_GENERATED_SOURCES += $(GEN) + LOCAL_CFLAGS += -Werror -Wall -Wno-unused-parameter -Wno-unused-variable LOCAL_CFLAGS += -DANDROID_RS_SERIALIZE +LOCAL_CFLAGS += -fPIC LOCAL_SRC_FILES:= \ + rsAdapter.cpp \ rsAllocation.cpp \ + rsAnimation.cpp \ rsComponent.cpp \ + rsContext.cpp \ + rsDevice.cpp \ rsElement.cpp \ + rsFBOCache.cpp \ + rsFifoSocket.cpp \ rsFileA3D.cpp \ + rsFont.cpp \ + rsLocklessFifo.cpp \ rsObjectBase.cpp \ + rsMatrix2x2.cpp \ + rsMatrix3x3.cpp \ + rsMatrix4x4.cpp \ rsMesh.cpp \ + rsMutex.cpp \ + rsProgram.cpp \ + rsProgramFragment.cpp \ + rsProgramStore.cpp \ + rsProgramRaster.cpp \ + rsProgramVertex.cpp \ + rsSampler.cpp \ + rsScript.cpp \ + rsScriptC.cpp \ + rsScriptC_Lib.cpp \ + rsScriptC_LibGL.cpp \ + rsSignal.cpp \ rsStream.cpp \ + rsThreadIO.cpp \ rsType.cpp LOCAL_STATIC_LIBRARIES := libcutils libutils LOCAL_LDLIBS := -lpthread -LOCAL_MODULE:= libRSserialize -LOCAL_MODULE_TAGS := optional include $(BUILD_HOST_STATIC_LIBRARY) diff --git a/libs/rs/RenderScript.h b/libs/rs/RenderScript.h index 3f2d67a440de..535f713c684c 100644 --- a/libs/rs/RenderScript.h +++ b/libs/rs/RenderScript.h @@ -55,15 +55,7 @@ void rsDeviceSetConfig(RsDevice dev, RsDeviceParam p, int32_t value); RsContext rsContextCreate(RsDevice dev, uint32_t version); RsContext rsContextCreateGL(RsDevice dev, uint32_t version, RsSurfaceConfig sc, uint32_t dpi); - - -#ifdef ANDROID_RS_SERIALIZE -#define NO_RS_FUNCS -#endif - -#ifndef NO_RS_FUNCS #include "rsgApiFuncDecl.h" -#endif #ifdef __cplusplus }; diff --git a/libs/rs/driver/rsdCore.cpp b/libs/rs/driver/rsdCore.cpp index 94d55a6d9deb..01cc369a8e01 100644 --- a/libs/rs/driver/rsdCore.cpp +++ b/libs/rs/driver/rsdCore.cpp @@ -36,6 +36,7 @@ #include <cutils/sched_policy.h> #include <sys/syscall.h> #include <string.h> +#include <bcc/bcc.h> using namespace android; using namespace android::renderscript; diff --git a/libs/rs/driver/rsdCore.h b/libs/rs/driver/rsdCore.h index 422bb1b07dc2..f393b602e1fc 100644 --- a/libs/rs/driver/rsdCore.h +++ b/libs/rs/driver/rsdCore.h @@ -18,7 +18,6 @@ #define RSD_CORE_H #include <rs_hal.h> -#include <bcc/bcc.h> #include "rsMutex.h" #include "rsSignal.h" diff --git a/libs/rs/rsAllocation.cpp b/libs/rs/rsAllocation.cpp index 05412c7b0b92..bff36603e9d9 100644 --- a/libs/rs/rsAllocation.cpp +++ b/libs/rs/rsAllocation.cpp @@ -168,13 +168,10 @@ void Allocation::elementData(Context *rsc, uint32_t x, uint32_t y, } void Allocation::addProgramToDirty(const Program *p) { -#ifndef ANDROID_RS_SERIALIZE mToDirtyList.push(p); -#endif //ANDROID_RS_SERIALIZE } void Allocation::removeProgramToDirty(const Program *p) { -#ifndef ANDROID_RS_SERIALIZE for (size_t ct=0; ct < mToDirtyList.size(); ct++) { if (mToDirtyList[ct] == p) { mToDirtyList.removeAt(ct); @@ -182,7 +179,6 @@ void Allocation::removeProgramToDirty(const Program *p) { } } rsAssert(0); -#endif //ANDROID_RS_SERIALIZE } void Allocation::dumpLOGV(const char *prefix) const { @@ -254,11 +250,9 @@ Allocation *Allocation::createFromStream(Context *rsc, IStream *stream) { } void Allocation::sendDirty(const Context *rsc) const { -#ifndef ANDROID_RS_SERIALIZE for (size_t ct=0; ct < mToDirtyList.size(); ct++) { mToDirtyList[ct]->forceDirty(); } -#endif //ANDROID_RS_SERIALIZE mRSC->mHal.funcs.allocation.markDirty(rsc, this); } @@ -312,8 +306,6 @@ void Allocation::resize2D(Context *rsc, uint32_t dimX, uint32_t dimY) { ///////////////// // -#ifndef ANDROID_RS_SERIALIZE - namespace android { namespace renderscript { @@ -413,25 +405,25 @@ void rsi_AllocationCopyToBitmap(Context *rsc, RsAllocation va, void *data, size_ } void rsi_Allocation1DData(Context *rsc, RsAllocation va, uint32_t xoff, uint32_t lod, - uint32_t count, const void *data, uint32_t sizeBytes) { + uint32_t count, const void *data, size_t sizeBytes) { Allocation *a = static_cast<Allocation *>(va); a->data(rsc, xoff, lod, count, data, sizeBytes); } void rsi_Allocation2DElementData(Context *rsc, RsAllocation va, uint32_t x, uint32_t y, uint32_t lod, RsAllocationCubemapFace face, - const void *data, uint32_t eoff, uint32_t sizeBytes) { + const void *data, size_t eoff, uint32_t sizeBytes) { // TODO: this seems wrong, eoff and sizeBytes may be swapped Allocation *a = static_cast<Allocation *>(va); a->elementData(rsc, x, y, data, eoff, sizeBytes); } void rsi_Allocation1DElementData(Context *rsc, RsAllocation va, uint32_t x, uint32_t lod, - const void *data, uint32_t eoff, uint32_t sizeBytes) { + const void *data, size_t eoff, uint32_t sizeBytes) { // TODO: this seems wrong, eoff and sizeBytes may be swapped Allocation *a = static_cast<Allocation *>(va); a->elementData(rsc, x, data, eoff, sizeBytes); } void rsi_Allocation2DData(Context *rsc, RsAllocation va, uint32_t xoff, uint32_t yoff, uint32_t lod, RsAllocationCubemapFace face, - uint32_t w, uint32_t h, const void *data, uint32_t sizeBytes) { + uint32_t w, uint32_t h, const void *data, size_t sizeBytes) { Allocation *a = static_cast<Allocation *>(va); a->data(rsc, xoff, yoff, lod, face, w, h, data, sizeBytes); } @@ -549,5 +541,3 @@ const void * rsaAllocationGetType(RsContext con, RsAllocation va) { return a->getType(); } - -#endif //ANDROID_RS_SERIALIZE diff --git a/libs/rs/rsAllocation.h b/libs/rs/rsAllocation.h index 5cf629257377..f538dd13bf99 100644 --- a/libs/rs/rsAllocation.h +++ b/libs/rs/rsAllocation.h @@ -59,7 +59,6 @@ public: static Allocation * createAllocation(Context *rsc, const Type *, uint32_t usages, RsAllocationMipmapControl mc = RS_ALLOCATION_MIPMAP_NONE); - virtual ~Allocation(); void updateCache(); @@ -121,14 +120,6 @@ protected: private: Allocation(Context *rsc, const Type *, uint32_t usages, RsAllocationMipmapControl mc); - - void upload2DTexture(bool isFirstUpload); - void update2DTexture(const void *ptr, uint32_t xoff, uint32_t yoff, - uint32_t lod, RsAllocationCubemapFace face, uint32_t w, uint32_t h); - - void allocScriptMemory(); - void freeScriptMemory(); - }; } diff --git a/libs/rs/rsContext.cpp b/libs/rs/rsContext.cpp index bab5c58da2bf..44e9d892fa42 100644 --- a/libs/rs/rsContext.cpp +++ b/libs/rs/rsContext.cpp @@ -92,9 +92,13 @@ uint32_t Context::runRootScript() { } uint64_t Context::getTime() const { +#ifndef ANDROID_RS_SERIALIZE struct timespec t; clock_gettime(CLOCK_MONOTONIC, &t); return t.tv_nsec + ((uint64_t)t.tv_sec * 1000 * 1000 * 1000); +#else + return 0; +#endif //ANDROID_RS_SERIALIZE } void Context::timerReset() { @@ -200,11 +204,11 @@ void Context::displayDebugStats() { void * Context::threadProc(void *vrsc) { Context *rsc = static_cast<Context *>(vrsc); +#ifndef ANDROID_RS_SERIALIZE rsc->mNativeThreadId = gettid(); - setpriority(PRIO_PROCESS, rsc->mNativeThreadId, ANDROID_PRIORITY_DISPLAY); rsc->mThreadPriority = ANDROID_PRIORITY_DISPLAY; - +#endif //ANDROID_RS_SERIALIZE rsc->props.mLogTimes = getProp("debug.rs.profile"); rsc->props.mLogScripts = getProp("debug.rs.script"); rsc->props.mLogObjects = getProp("debug.rs.object"); @@ -330,10 +334,16 @@ Context::Context() { mObjHead = NULL; mError = RS_ERROR_NONE; mDPI = 96; + mIsContextLite = false; } Context * Context::createContext(Device *dev, const RsSurfaceConfig *sc) { Context * rsc = new Context(); + + // Temporary to avoid breaking the tools + if (!dev) { + return rsc; + } if (!rsc->initContext(dev, sc)) { delete rsc; return NULL; @@ -341,6 +351,12 @@ Context * Context::createContext(Device *dev, const RsSurfaceConfig *sc) { return rsc; } +Context * Context::createContextLite() { + Context * rsc = new Context(); + rsc->mIsContextLite = true; + return rsc; +} + bool Context::initContext(Device *dev, const RsSurfaceConfig *sc) { pthread_mutex_lock(&gInitMutex); @@ -395,26 +411,28 @@ bool Context::initContext(Device *dev, const RsSurfaceConfig *sc) { Context::~Context() { LOGV("Context::~Context"); - mIO.coreFlush(); - rsAssert(mExit); - mExit = true; - mPaused = false; - void *res; + if (!mIsContextLite) { + mIO.coreFlush(); + rsAssert(mExit); + mExit = true; + mPaused = false; + void *res; - mIO.shutdown(); - int status = pthread_join(mThreadId, &res); + mIO.shutdown(); + int status = pthread_join(mThreadId, &res); - if (mHal.funcs.shutdownDriver) { - mHal.funcs.shutdownDriver(this); - } + if (mHal.funcs.shutdownDriver) { + mHal.funcs.shutdownDriver(this); + } - // Global structure cleanup. - pthread_mutex_lock(&gInitMutex); - if (mDev) { - mDev->removeContext(this); - mDev = NULL; + // Global structure cleanup. + pthread_mutex_lock(&gInitMutex); + if (mDev) { + mDev->removeContext(this); + mDev = NULL; + } + pthread_mutex_unlock(&gInitMutex); } - pthread_mutex_unlock(&gInitMutex); LOGV("Context::~Context done"); } @@ -542,7 +560,7 @@ void Context::dumpDebug() const { LOGE(" RS width %i, height %i", mWidth, mHeight); LOGE(" RS running %i, exit %i, paused %i", mRunning, mExit, mPaused); - LOGE(" RS pThreadID %li, nativeThreadID %i", mThreadId, mNativeThreadId); + LOGE(" RS pThreadID %li, nativeThreadID %i", (long int)mThreadId, mNativeThreadId); } /////////////////////////////////////////////////////////////////////////////////////////// @@ -595,7 +613,7 @@ void rsi_ContextBindFont(Context *rsc, RsFont vfont) { rsc->setFont(font); } -void rsi_AssignName(Context *rsc, RsObjectBase obj, const char *name, uint32_t name_length) { +void rsi_AssignName(Context *rsc, RsObjectBase obj, const char *name, size_t name_length) { ObjectBase *ob = static_cast<ObjectBase *>(obj); rsc->assignName(ob, name, name_length); } @@ -627,7 +645,7 @@ void rsi_ContextDump(Context *rsc, int32_t bits) { } void rsi_ContextDestroyWorker(Context *rsc) { - rsc->destroyWorkerThreadResources();; + rsc->destroyWorkerThreadResources(); } void rsi_ContextDestroy(Context *rsc) { diff --git a/libs/rs/rsContext.h b/libs/rs/rsContext.h index 4ba00fec6efe..309fe9532bba 100644 --- a/libs/rs/rsContext.h +++ b/libs/rs/rsContext.h @@ -24,7 +24,6 @@ #include "rs_hal.h" -#ifndef ANDROID_RS_SERIALIZE #include "rsMutex.h" #include "rsThreadIO.h" #include "rsMatrix4x4.h" @@ -42,8 +41,6 @@ #include "rsgApiStructs.h" #include "rsLocklessFifo.h" -#endif // ANDROID_RS_SERIALIZE - // --------------------------------------------------------------------------- namespace android { @@ -67,8 +64,6 @@ namespace renderscript { #define CHECK_OBJ_OR_NULL(o) #endif -#ifndef ANDROID_RS_SERIALIZE - class Context { public: struct Hal { @@ -79,6 +74,7 @@ public: Hal mHal; static Context * createContext(Device *, const RsSurfaceConfig *sc); + static Context * createContextLite(); ~Context(); static pthread_mutex_t gInitMutex; @@ -243,6 +239,7 @@ private: static void * helperThreadProc(void *); bool mHasSurface; + bool mIsContextLite; Vector<ObjectBase *> mNames; @@ -259,46 +256,6 @@ private: uint32_t mAverageFPS; }; -#else - -class Context { -public: - Context() { - mObjHead = NULL; - } - ~Context() { - ObjectBase::zeroAllUserRef(this); - } - - struct Hal { - void * drv; - - RsdHalFunctions funcs; - }; - Hal mHal; - - ElementState mStateElement; - TypeState mStateType; - - struct { - bool mLogTimes; - bool mLogScripts; - bool mLogObjects; - bool mLogShaders; - bool mLogShadersAttr; - bool mLogShadersUniforms; - bool mLogVisual; - } props; - - void setError(RsError e, const char *msg = NULL) { } - - mutable const ObjectBase * mObjHead; - -protected: - -}; -#endif //ANDROID_RS_SERIALIZE - } // renderscript } // android #endif diff --git a/libs/rs/rsFifoSocket.cpp b/libs/rs/rsFifoSocket.cpp index 848bba5ab064..8b8008d5c0a2 100644 --- a/libs/rs/rsFifoSocket.cpp +++ b/libs/rs/rsFifoSocket.cpp @@ -70,9 +70,9 @@ size_t FifoSocket::read(void *data, size_t bytes) { } void FifoSocket::readReturn(const void *data, size_t bytes) { - LOGE("readReturn %p %i", data, bytes); + LOGE("readReturn %p %Zu", data, bytes); size_t ret = ::send(sv[1], data, bytes, 0); - LOGE("readReturn %i", ret); + LOGE("readReturn %Zu", ret); rsAssert(ret == bytes); } diff --git a/libs/rs/rsFont.cpp b/libs/rs/rsFont.cpp index b625504dc2a0..ce674f420b11 100644 --- a/libs/rs/rsFont.cpp +++ b/libs/rs/rsFont.cpp @@ -21,9 +21,11 @@ #include "rsProgramFragment.h" #include <cutils/properties.h> +#ifndef ANDROID_RS_SERIALIZE #include <ft2build.h> #include FT_FREETYPE_H #include FT_BITMAP_H +#endif //ANDROID_RS_SERIALIZE using namespace android; using namespace android::renderscript; @@ -35,6 +37,7 @@ Font::Font(Context *rsc) : ObjectBase(rsc), mCachedGlyphs(NULL) { } bool Font::init(const char *name, float fontSize, uint32_t dpi, const void *data, uint32_t dataLen) { +#ifndef ANDROID_RS_SERIALIZE if (mInitialized) { LOGE("Reinitialization of fonts not supported"); return false; @@ -65,6 +68,7 @@ bool Font::init(const char *name, float fontSize, uint32_t dpi, const void *data mHasKerning = FT_HAS_KERNING(mFace); mInitialized = true; +#endif //ANDROID_RS_SERIALIZE return true; } @@ -230,6 +234,7 @@ Font::CachedGlyphInfo* Font::getCachedUTFChar(int32_t utfChar) { } void Font::updateGlyphCache(CachedGlyphInfo *glyph) { +#ifndef ANDROID_RS_SERIALIZE FT_Error error = FT_Load_Glyph( mFace, glyph->mGlyphIndex, FT_LOAD_RENDER ); if (error) { LOGE("Couldn't load glyph."); @@ -270,15 +275,16 @@ void Font::updateGlyphCache(CachedGlyphInfo *glyph) { glyph->mBitmapMinV = (float)startY / (float)cacheHeight; glyph->mBitmapMaxU = (float)endX / (float)cacheWidth; glyph->mBitmapMaxV = (float)endY / (float)cacheHeight; +#endif //ANDROID_RS_SERIALIZE } Font::CachedGlyphInfo *Font::cacheGlyph(uint32_t glyph) { CachedGlyphInfo *newGlyph = new CachedGlyphInfo(); mCachedGlyphs.add(glyph, newGlyph); - +#ifndef ANDROID_RS_SERIALIZE newGlyph->mGlyphIndex = FT_Get_Char_Index(mFace, glyph); newGlyph->mIsValid = false; - +#endif //ANDROID_RS_SERIALIZE updateGlyphCache(newGlyph); return newGlyph; @@ -309,9 +315,11 @@ Font * Font::create(Context *rsc, const char *name, float fontSize, uint32_t dpi } Font::~Font() { +#ifndef ANDROID_RS_SERIALIZE if (mFace) { FT_Done_Face(mFace); } +#endif for (uint32_t i = 0; i < mCachedGlyphs.size(); i ++) { CachedGlyphInfo *glyph = mCachedGlyphs.valueAt(i); @@ -324,7 +332,9 @@ FontState::FontState() { mMaxNumberOfQuads = 1024; mCurrentQuadIndex = 0; mRSC = NULL; +#ifndef ANDROID_RS_SERIALIZE mLibrary = NULL; +#endif //ANDROID_RS_SERIALIZE // Get the renderer properties char property[PROPERTY_VALUE_MAX]; @@ -363,7 +373,7 @@ FontState::~FontState() { rsAssert(!mActiveFonts.size()); } - +#ifndef ANDROID_RS_SERIALIZE FT_Library FontState::getLib() { if (!mLibrary) { FT_Error error = FT_Init_FreeType(&mLibrary); @@ -375,6 +385,8 @@ FT_Library FontState::getLib() { return mLibrary; } +#endif //ANDROID_RS_SERIALIZE + void FontState::init(Context *rsc) { mRSC = rsc; @@ -393,6 +405,7 @@ void FontState::flushAllAndInvalidate() { } } +#ifndef ANDROID_RS_SERIALIZE bool FontState::cacheBitmap(FT_Bitmap *bitmap, uint32_t *retOriginX, uint32_t *retOriginY) { // If the glyph is too tall, don't cache it if ((uint32_t)bitmap->rows > mCacheLines[mCacheLines.size()-1]->mMaxHeight) { @@ -466,6 +479,7 @@ bool FontState::cacheBitmap(FT_Bitmap *bitmap, uint32_t *retOriginX, uint32_t *r return true; } +#endif //ANDROID_RS_SERIALIZE void FontState::initRenderState() { String8 shaderString("varying vec2 varTex0;\n"); @@ -791,13 +805,15 @@ void FontState::deinit(Context *rsc) { mCacheLines.clear(); mDefault.clear(); - +#ifndef ANDROID_RS_SERIALIZE if (mLibrary) { FT_Done_FreeType( mLibrary ); mLibrary = NULL; } +#endif //ANDROID_RS_SERIALIZE } +#ifndef ANDROID_RS_SERIALIZE bool FontState::CacheTextureLine::fitBitmap(FT_Bitmap_ *bitmap, uint32_t *retOriginX, uint32_t *retOriginY) { if ((uint32_t)bitmap->rows > mMaxHeight) { return false; @@ -813,6 +829,7 @@ bool FontState::CacheTextureLine::fitBitmap(FT_Bitmap_ *bitmap, uint32_t *retOri return false; } +#endif //ANDROID_RS_SERIALIZE namespace android { namespace renderscript { diff --git a/libs/rs/rsFont.h b/libs/rs/rsFont.h index d18c0d91566d..b0e1430e228b 100644 --- a/libs/rs/rsFont.h +++ b/libs/rs/rsFont.h @@ -199,8 +199,10 @@ protected: float mWhiteThreshold; // Free type library, we only need one copy +#ifndef ANDROID_RS_SERIALIZE FT_LibraryRec_ *mLibrary; FT_LibraryRec_ *getLib(); +#endif //ANDROID_RS_SERIALIZE Vector<Font*> mActiveFonts; // Render state for the font @@ -217,7 +219,9 @@ protected: return (uint8_t*)mTextTexture->getPtr(); } +#ifndef ANDROID_RS_SERIALIZE bool cacheBitmap(FT_Bitmap_ *bitmap, uint32_t *retOriginX, uint32_t *retOriginY); +#endif //ANDROID_RS_SERIALIZE const Type* getCacheTextureType() { return mTextTexture->getType(); } diff --git a/libs/rs/rsMesh.cpp b/libs/rs/rsMesh.cpp index 62e388cb3159..359d09fdcd86 100644 --- a/libs/rs/rsMesh.cpp +++ b/libs/rs/rsMesh.cpp @@ -161,8 +161,6 @@ Mesh *Mesh::createFromStream(Context *rsc, IStream *stream) { return mesh; } -#ifndef ANDROID_RS_SERIALIZE - void Mesh::render(Context *rsc) const { for (uint32_t ct = 0; ct < mHal.state.primitivesCount; ct ++) { renderPrimitive(rsc, ct); @@ -255,9 +253,9 @@ namespace android { namespace renderscript { RsMesh rsi_MeshCreate(Context *rsc, - RsAllocation *vtx, uint32_t vtxCount, - RsAllocation *idx, uint32_t idxCount, - uint32_t *primType, uint32_t primTypeCount) { + RsAllocation * vtx, size_t vtxCount, + RsAllocation * idx, size_t idxCount, + uint32_t * primType, size_t primTypeCount) { rsAssert(idxCount == primTypeCount); Mesh *sm = new Mesh(rsc, vtxCount, idxCount); sm->incUserRef(); @@ -309,5 +307,3 @@ void rsaMeshGetIndices(RsContext con, RsMesh mv, RsAllocation *va, uint32_t *pri } } } - -#endif diff --git a/libs/rs/rsProgramFragment.cpp b/libs/rs/rsProgramFragment.cpp index 0823d8220a10..356ff778f126 100644 --- a/libs/rs/rsProgramFragment.cpp +++ b/libs/rs/rsProgramFragment.cpp @@ -127,8 +127,8 @@ namespace android { namespace renderscript { RsProgramFragment rsi_ProgramFragmentCreate(Context *rsc, const char * shaderText, - uint32_t shaderLength, const uint32_t * params, - uint32_t paramLength) { + size_t shaderLength, const uint32_t * params, + size_t paramLength) { ProgramFragment *pf = new ProgramFragment(rsc, shaderText, shaderLength, params, paramLength); pf->incUserRef(); //LOGE("rsi_ProgramFragmentCreate %p", pf); diff --git a/libs/rs/rsProgramVertex.cpp b/libs/rs/rsProgramVertex.cpp index e6790cb3aee4..058a4564e03f 100644 --- a/libs/rs/rsProgramVertex.cpp +++ b/libs/rs/rsProgramVertex.cpp @@ -223,8 +223,8 @@ namespace android { namespace renderscript { RsProgramVertex rsi_ProgramVertexCreate(Context *rsc, const char * shaderText, - uint32_t shaderLength, const uint32_t * params, - uint32_t paramLength) { + size_t shaderLength, const uint32_t * params, + size_t paramLength) { ProgramVertex *pv = new ProgramVertex(rsc, shaderText, shaderLength, params, paramLength); pv->incUserRef(); return pv; diff --git a/libs/rs/rsScript.cpp b/libs/rs/rsScript.cpp index 7641cab03c27..f62c72edfe21 100644 --- a/libs/rs/rsScript.cpp +++ b/libs/rs/rsScript.cpp @@ -53,7 +53,7 @@ void Script::setSlot(uint32_t slot, Allocation *a) { } } -void Script::setVar(uint32_t slot, const void *val, uint32_t len) { +void Script::setVar(uint32_t slot, const void *val, size_t len) { //LOGE("setVar %i %p %i", slot, val, len); if (slot >= mHal.info.exportedVariableCount) { LOGE("Script::setVar unable to set allocation, invalid slot index"); @@ -82,14 +82,14 @@ void rsi_ScriptBindAllocation(Context * rsc, RsScript vs, RsAllocation va, uint3 //LOGE("rsi_ScriptBindAllocation %i %p %p", slot, a, a->getPtr()); } -void rsi_ScriptSetTimeZone(Context * rsc, RsScript vs, const char * timeZone, uint32_t length) { +void rsi_ScriptSetTimeZone(Context * rsc, RsScript vs, const char * timeZone, size_t length) { Script *s = static_cast<Script *>(vs); s->mEnviroment.mTimeZone = timeZone; } void rsi_ScriptForEach(Context *rsc, RsScript vs, uint32_t slot, RsAllocation vain, RsAllocation vaout, - const void *params, uint32_t paramLen) { + const void *params, size_t paramLen) { Script *s = static_cast<Script *>(vs); s->runForEach(rsc, static_cast<const Allocation *>(vain), static_cast<Allocation *>(vaout), @@ -108,7 +108,7 @@ void rsi_ScriptInvokeData(Context *rsc, RsScript vs, uint32_t slot, void *data) s->Invoke(rsc, slot, NULL, 0); } -void rsi_ScriptInvokeV(Context *rsc, RsScript vs, uint32_t slot, const void *data, uint32_t len) { +void rsi_ScriptInvokeV(Context *rsc, RsScript vs, uint32_t slot, const void *data, size_t len) { Script *s = static_cast<Script *>(vs); s->Invoke(rsc, slot, data, len); } @@ -139,7 +139,7 @@ void rsi_ScriptSetVarD(Context *rsc, RsScript vs, uint32_t slot, double value) { s->setVar(slot, &value, sizeof(value)); } -void rsi_ScriptSetVarV(Context *rsc, RsScript vs, uint32_t slot, const void *data, uint32_t len) { +void rsi_ScriptSetVarV(Context *rsc, RsScript vs, uint32_t slot, const void *data, size_t len) { Script *s = static_cast<Script *>(vs); s->setVar(slot, data, len); } diff --git a/libs/rs/rsScript.h b/libs/rs/rsScript.h index 088c8d1c69bf..c0324ddf6cca 100644 --- a/libs/rs/rsScript.h +++ b/libs/rs/rsScript.h @@ -70,7 +70,7 @@ public: void initSlots(); void setSlot(uint32_t slot, Allocation *a); - void setVar(uint32_t slot, const void *val, uint32_t len); + void setVar(uint32_t slot, const void *val, size_t len); void setVarObj(uint32_t slot, ObjectBase *val); virtual void runForEach(Context *rsc, @@ -80,7 +80,7 @@ public: size_t usrBytes, const RsScriptCall *sc = NULL) = 0; - virtual void Invoke(Context *rsc, uint32_t slot, const void *data, uint32_t len) = 0; + virtual void Invoke(Context *rsc, uint32_t slot, const void *data, size_t len) = 0; virtual void setupScript(Context *rsc) = 0; virtual uint32_t run(Context *) = 0; protected: diff --git a/libs/rs/rsScriptC.cpp b/libs/rs/rsScriptC.cpp index 6d0701d18720..b230bb5b3a73 100644 --- a/libs/rs/rsScriptC.cpp +++ b/libs/rs/rsScriptC.cpp @@ -19,11 +19,6 @@ #include "utils/Timers.h" #include "utils/StopWatch.h" -#include <GLES/gl.h> -#include <GLES/glext.h> - -#include <bcc/bcc.h> - using namespace android; using namespace android::renderscript; @@ -129,7 +124,7 @@ void ScriptC::runForEach(Context *rsc, rsc->mHal.funcs.script.invokeForEach(rsc, this, ain, aout, usr, usrBytes, sc); } -void ScriptC::Invoke(Context *rsc, uint32_t slot, const void *data, uint32_t len) { +void ScriptC::Invoke(Context *rsc, uint32_t slot, const void *data, size_t len) { if (slot >= mHal.info.exportedFunctionCount) { rsc->setError(RS_ERROR_BAD_SCRIPT, "Calling invoke on bad script"); return; @@ -269,7 +264,7 @@ namespace renderscript { RsScript rsi_ScriptCCreate(Context *rsc, const char *resName, size_t resName_length, const char *cacheDir, size_t cacheDir_length, - const char *text, uint32_t text_length) + const char *text, size_t text_length) { ScriptC *s = new ScriptC(rsc); diff --git a/libs/rs/rsScriptC.h b/libs/rs/rsScriptC.h index 4c85745e4ea8..5c191d93cf46 100644 --- a/libs/rs/rsScriptC.h +++ b/libs/rs/rsScriptC.h @@ -39,7 +39,7 @@ public: const Allocation *ptrToAllocation(const void *) const; - virtual void Invoke(Context *rsc, uint32_t slot, const void *data, uint32_t len); + virtual void Invoke(Context *rsc, uint32_t slot, const void *data, size_t len); virtual uint32_t run(Context *); diff --git a/libs/rs/rsThreadIO.cpp b/libs/rs/rsThreadIO.cpp index 442955672475..ab164c312af6 100644 --- a/libs/rs/rsThreadIO.cpp +++ b/libs/rs/rsThreadIO.cpp @@ -149,7 +149,7 @@ RsMessageToClientType ThreadIO::getClientHeader(size_t *receiveLen, uint32_t *us mToClientSocket.read(&mLastClientHeader, sizeof(mLastClientHeader)); } else { size_t bytesData = 0; - const uint32_t *d = (const uint32_t *)mToClient.get(&mLastClientHeader.cmdID, &bytesData); + const uint32_t *d = (const uint32_t *)mToClient.get(&mLastClientHeader.cmdID, (uint32_t*)&bytesData); if (bytesData >= sizeof(uint32_t)) { mLastClientHeader.userID = d[0]; mLastClientHeader.bytes = bytesData - sizeof(uint32_t); diff --git a/libs/rs/rs_hal.h b/libs/rs/rs_hal.h index 44c7e716f73c..7bb09bbf5597 100644 --- a/libs/rs/rs_hal.h +++ b/libs/rs/rs_hal.h @@ -18,7 +18,6 @@ #define RS_HAL_H #include <RenderScriptDefines.h> -#include <ui/egl/android_natives.h> namespace android { namespace renderscript { diff --git a/libs/utils/BackupHelpers.cpp b/libs/utils/BackupHelpers.cpp index f933199fe8d1..87549fe97771 100644 --- a/libs/utils/BackupHelpers.cpp +++ b/libs/utils/BackupHelpers.cpp @@ -525,6 +525,7 @@ int write_tarfile(const String8& packageName, const String8& domain, String8 prefix; const int isdir = S_ISDIR(s.st_mode); + if (isdir) s.st_size = 0; // directories get no actual data in the tar stream // !!! TODO: use mmap when possible to avoid churning the buffer cache // !!! TODO: this will break with symlinks; need to use readlink(2) diff --git a/libs/utils/RefBase.cpp b/libs/utils/RefBase.cpp index dd0052ab995c..58e0811f21a0 100644 --- a/libs/utils/RefBase.cpp +++ b/libs/utils/RefBase.cpp @@ -418,18 +418,20 @@ void RefBase::weakref_type::decWeak(const void* id) if (c != 1) return; if ((impl->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK) { - if (impl->mStrong == INITIAL_STRONG_VALUE) - if (impl->mBase) + if (impl->mStrong == INITIAL_STRONG_VALUE) { + if (impl->mBase) { impl->mBase->destroy(); - else { + } + } else { // LOGV("Freeing refs %p of old RefBase %p\n", this, impl->mBase); delete impl; } } else { impl->mBase->onLastWeakRef(id); if ((impl->mFlags&OBJECT_LIFETIME_FOREVER) != OBJECT_LIFETIME_FOREVER) { - if (impl->mBase) + if (impl->mBase) { impl->mBase->destroy(); + } } } } @@ -551,8 +553,10 @@ RefBase::RefBase() RefBase::~RefBase() { - if (mRefs->mWeak == 0) { - delete mRefs; + if ((mRefs->mFlags & OBJECT_LIFETIME_WEAK) == OBJECT_LIFETIME_WEAK) { + if (mRefs->mWeak == 0) { + delete mRefs; + } } } diff --git a/libs/utils/ResourceTypes.cpp b/libs/utils/ResourceTypes.cpp index 4a6a3dbc3552..cb6c24627eca 100644 --- a/libs/utils/ResourceTypes.cpp +++ b/libs/utils/ResourceTypes.cpp @@ -2663,6 +2663,9 @@ uint32_t ResTable::identifierForName(const char16_t* name, size_t nameLen, goto nope; } } + if (outTypeSpecFlags) { + *outTypeSpecFlags = ResTable_typeSpec::SPEC_PUBLIC; + } return m->id; nope: ; @@ -2677,6 +2680,9 @@ nope: index); return 0; } + if (outTypeSpecFlags) { + *outTypeSpecFlags = ResTable_typeSpec::SPEC_PUBLIC; + } return Res_MAKEARRAY(index); } } @@ -2687,6 +2693,8 @@ nope: return 0; } + bool fakePublic = false; + // Figure out the package and type we are looking in... const char16_t* packageEnd = NULL; @@ -2698,7 +2706,13 @@ nope: else if (*p == '/') typeEnd = p; p++; } - if (*name == '@') name++; + if (*name == '@') { + name++; + if (*name == '*') { + fakePublic = true; + name++; + } + } if (name >= nameEnd) { return 0; } @@ -2803,6 +2817,9 @@ nope: if (dtohl(entry->key.index) == (size_t)ei) { if (outTypeSpecFlags) { *outTypeSpecFlags = typeConfigs->typeSpecFlags[i]; + if (fakePublic) { + *outTypeSpecFlags |= ResTable_typeSpec::SPEC_PUBLIC; + } } return Res_MAKEID(group->id-1, ti, i); } @@ -2819,7 +2836,8 @@ bool ResTable::expandResourceRef(const uint16_t* refStr, size_t refLen, String16* outName, const String16* defType, const String16* defPackage, - const char** outErrorMsg) + const char** outErrorMsg, + bool* outPublicOnly) { const char16_t* packageEnd = NULL; const char16_t* typeEnd = NULL; @@ -2836,6 +2854,16 @@ bool ResTable::expandResourceRef(const uint16_t* refStr, size_t refLen, p = refStr; if (*p == '@') p++; + if (outPublicOnly != NULL) { + *outPublicOnly = true; + } + if (*p == '*') { + p++; + if (outPublicOnly != NULL) { + *outPublicOnly = false; + } + } + if (packageEnd) { *outPackage = String16(p, packageEnd-p); p = packageEnd+1; diff --git a/libs/utils/StreamingZipInflater.cpp b/libs/utils/StreamingZipInflater.cpp index 5a162cc49e9b..00498bd1fcb8 100644 --- a/libs/utils/StreamingZipInflater.cpp +++ b/libs/utils/StreamingZipInflater.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -#define LOG_NDEBUG 1 +//#define LOG_NDEBUG 0 #define LOG_TAG "szipinf" #include <utils/Log.h> @@ -77,7 +77,7 @@ StreamingZipInflater::~StreamingZipInflater() { } void StreamingZipInflater::initInflateState() { - LOGD("Initializing inflate state"); + LOGV("Initializing inflate state"); memset(&mInflateState, 0, sizeof(mInflateState)); mInflateState.zalloc = Z_NULL; @@ -152,13 +152,13 @@ ssize_t StreamingZipInflater::read(void* outBuf, size_t count) { mInflateState.avail_out = mOutBufSize; /* - LOGD("Inflating to outbuf: avail_in=%u avail_out=%u next_in=%p next_out=%p", + LOGV("Inflating to outbuf: avail_in=%u avail_out=%u next_in=%p next_out=%p", mInflateState.avail_in, mInflateState.avail_out, mInflateState.next_in, mInflateState.next_out); */ int result = Z_OK; if (mStreamNeedsInit) { - LOGD("Initializing zlib to inflate"); + LOGV("Initializing zlib to inflate"); result = inflateInit2(&mInflateState, -MAX_WBITS); mStreamNeedsInit = false; } @@ -192,7 +192,7 @@ int StreamingZipInflater::readNextChunk() { size_t toRead = min_of(mInBufSize, mInTotalSize - mInNextChunkOffset); if (toRead > 0) { ssize_t didRead = ::read(mFd, mInBuf, toRead); - //LOGD("Reading input chunk, size %08x didread %08x", toRead, didRead); + //LOGV("Reading input chunk, size %08x didread %08x", toRead, didRead); if (didRead < 0) { // TODO: error LOGE("Error reading asset data"); diff --git a/media/libmedia/MediaScanner.cpp b/media/libmedia/MediaScanner.cpp index 28c8642687d9..45bdff4cd4a4 100644 --- a/media/libmedia/MediaScanner.cpp +++ b/media/libmedia/MediaScanner.cpp @@ -89,7 +89,7 @@ status_t MediaScanner::doProcessDirectory( if (pathRemaining >= 8 /* strlen(".nomedia") */ ) { strcpy(fileSpot, ".nomedia"); if (access(path, F_OK) == 0) { - LOGD("found .nomedia, setting noMedia flag\n"); + LOGV("found .nomedia, setting noMedia flag\n"); noMedia = true; } diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp index 54a6547181c2..a77dff1615d4 100644 --- a/media/libmediaplayerservice/MediaPlayerService.cpp +++ b/media/libmediaplayerservice/MediaPlayerService.cpp @@ -368,6 +368,9 @@ status_t MediaPlayerService::Client::dump(int fd, const Vector<String16>& args) mPid, mConnId, mStatus, mLoop?"true": "false"); result.append(buffer); write(fd, result.string(), result.size()); + if (mPlayer != NULL) { + mPlayer->dump(fd, args); + } if (mAudioOutput != 0) { mAudioOutput->dump(fd, args); } diff --git a/media/libmediaplayerservice/StagefrightPlayer.cpp b/media/libmediaplayerservice/StagefrightPlayer.cpp index 02ec9117f5a5..870e290ee09e 100644 --- a/media/libmediaplayerservice/StagefrightPlayer.cpp +++ b/media/libmediaplayerservice/StagefrightPlayer.cpp @@ -214,4 +214,8 @@ status_t StagefrightPlayer::getMetadata( return OK; } +status_t StagefrightPlayer::dump(int fd, const Vector<String16> &args) const { + return mPlayer->dump(fd, args); +} + } // namespace android diff --git a/media/libmediaplayerservice/StagefrightPlayer.h b/media/libmediaplayerservice/StagefrightPlayer.h index ddd37e4a06c8..85a546dc89e8 100644 --- a/media/libmediaplayerservice/StagefrightPlayer.h +++ b/media/libmediaplayerservice/StagefrightPlayer.h @@ -61,6 +61,8 @@ public: virtual status_t getMetadata( const media::Metadata::Filter& ids, Parcel *records); + virtual status_t dump(int fd, const Vector<String16> &args) const; + private: AwesomePlayer *mPlayer; diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp index 3a58d3fd8bfc..aa7edccb2ffb 100644 --- a/media/libstagefright/AwesomePlayer.cpp +++ b/media/libstagefright/AwesomePlayer.cpp @@ -265,7 +265,7 @@ status_t AwesomePlayer::setDataSource_l( // This isn't something that should be passed to the server. mUriHeaders.removeItemsAt(index); - mFlags |= INCOGNITO; + modifyFlags(INCOGNITO, SET); } } @@ -279,6 +279,12 @@ status_t AwesomePlayer::setDataSource_l( // ::finishSetDataSource_l to avoid blocking the calling thread in // setDataSource for any significant time. + { + Mutex::Autolock autoLock(mStatsLock); + mStats.mFd = -1; + mStats.mURI = mUri; + } + return OK; } @@ -298,6 +304,12 @@ status_t AwesomePlayer::setDataSource( mFileSource = dataSource; + { + Mutex::Autolock autoLock(mStatsLock); + mStats.mFd = fd; + mStats.mURI = String8(); + } + return setDataSource_l(dataSource); } @@ -336,6 +348,10 @@ status_t AwesomePlayer::setDataSource_l(const sp<MediaExtractor> &extractor) { int32_t bitrate; if (!meta->findInt32(kKeyBitRate, &bitrate)) { + const char *mime; + CHECK(meta->findCString(kKeyMIMEType, &mime)); + LOGW("track of type '%s' does not publish bitrate", mime); + totalBitRate = -1; break; } @@ -347,6 +363,14 @@ status_t AwesomePlayer::setDataSource_l(const sp<MediaExtractor> &extractor) { LOGV("mBitrate = %lld bits/sec", mBitrate); + { + Mutex::Autolock autoLock(mStatsLock); + mStats.mBitrate = mBitrate; + mStats.mTracks.clear(); + mStats.mAudioTrackIndex = -1; + mStats.mVideoTrackIndex = -1; + } + bool haveAudio = false; bool haveVideo = false; for (size_t i = 0; i < extractor->countTracks(); ++i) { @@ -370,10 +394,27 @@ status_t AwesomePlayer::setDataSource_l(const sp<MediaExtractor> &extractor) { mDisplayHeight = displayHeight; } + { + Mutex::Autolock autoLock(mStatsLock); + mStats.mVideoTrackIndex = mStats.mTracks.size(); + mStats.mTracks.push(); + TrackStat *stat = + &mStats.mTracks.editItemAt(mStats.mVideoTrackIndex); + stat->mMIME = mime; + } } else if (!haveAudio && !strncasecmp(mime, "audio/", 6)) { setAudioSource(extractor->getTrack(i)); haveAudio = true; + { + Mutex::Autolock autoLock(mStatsLock); + mStats.mAudioTrackIndex = mStats.mTracks.size(); + mStats.mTracks.push(); + TrackStat *stat = + &mStats.mTracks.editItemAt(mStats.mAudioTrackIndex); + stat->mMIME = mime; + } + if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_VORBIS)) { // Only do this for vorbis audio, none of the other audio // formats even support this ringtone specific hack and @@ -383,7 +424,7 @@ status_t AwesomePlayer::setDataSource_l(const sp<MediaExtractor> &extractor) { int32_t loop; if (fileMeta != NULL && fileMeta->findInt32(kKeyAutoLoop, &loop) && loop != 0) { - mFlags |= AUTO_LOOPING; + modifyFlags(AUTO_LOOPING, SET); } } } else if (!strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP)) { @@ -431,7 +472,7 @@ void AwesomePlayer::reset_l() { } if (mFlags & PREPARING) { - mFlags |= PREPARE_CANCELLED; + modifyFlags(PREPARE_CANCELLED, SET); if (mConnectingDataSource != NULL) { LOGI("interrupting the connection process"); mConnectingDataSource->disconnect(); @@ -494,7 +535,7 @@ void AwesomePlayer::reset_l() { } mDurationUs = -1; - mFlags = 0; + modifyFlags(0, ASSIGN); mExtractorFlags = 0; mTimeSourceDeltaUs = 0; mVideoTimeUs = 0; @@ -510,6 +551,22 @@ void AwesomePlayer::reset_l() { mBitrate = -1; mLastVideoTimeUs = -1; + + { + Mutex::Autolock autoLock(mStatsLock); + mStats.mFd = -1; + mStats.mURI = String8(); + mStats.mBitrate = -1; + mStats.mAudioTrackIndex = -1; + mStats.mVideoTrackIndex = -1; + mStats.mNumVideoFramesDecoded = 0; + mStats.mNumVideoFramesDropped = 0; + mStats.mVideoWidth = -1; + mStats.mVideoHeight = -1; + mStats.mFlags = 0; + mStats.mTracks.clear(); + } + } void AwesomePlayer::notifyListener_l(int msg, int ext1, int ext2) { @@ -631,7 +688,7 @@ void AwesomePlayer::onBufferingUpdate() { && (cachedDataRemaining < kLowWaterMarkBytes)) { LOGI("cache is running low (< %d) , pausing.", kLowWaterMarkBytes); - mFlags |= CACHE_UNDERRUN; + modifyFlags(CACHE_UNDERRUN, SET); pause_l(); ensureCacheIsFetching_l(); sendCacheStats(); @@ -640,7 +697,7 @@ void AwesomePlayer::onBufferingUpdate() { if (mFlags & CACHE_UNDERRUN) { LOGI("cache has filled up (> %d), resuming.", kHighWaterMarkBytes); - mFlags &= ~CACHE_UNDERRUN; + modifyFlags(CACHE_UNDERRUN, CLEAR); play_l(); notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_END); } else if (mFlags & PREPARING) { @@ -690,7 +747,7 @@ void AwesomePlayer::onBufferingUpdate() { && (cachedDurationUs < kLowWaterMarkUs)) { LOGI("cache is running low (%.2f secs) , pausing.", cachedDurationUs / 1E6); - mFlags |= CACHE_UNDERRUN; + modifyFlags(CACHE_UNDERRUN, SET); pause_l(); ensureCacheIsFetching_l(); sendCacheStats(); @@ -699,7 +756,7 @@ void AwesomePlayer::onBufferingUpdate() { if (mFlags & CACHE_UNDERRUN) { LOGI("cache has filled up (%.2f secs), resuming.", cachedDurationUs / 1E6); - mFlags &= ~CACHE_UNDERRUN; + modifyFlags(CACHE_UNDERRUN, CLEAR); play_l(); notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_END); } else if (mFlags & PREPARING) { @@ -742,7 +799,7 @@ void AwesomePlayer::onStreamDone() { pause_l(true /* at eos */); - mFlags |= AT_EOS; + modifyFlags(AT_EOS, SET); return; } @@ -766,20 +823,20 @@ void AwesomePlayer::onStreamDone() { pause_l(true /* at eos */); - mFlags |= AT_EOS; + modifyFlags(AT_EOS, SET); } } status_t AwesomePlayer::play() { Mutex::Autolock autoLock(mLock); - mFlags &= ~CACHE_UNDERRUN; + modifyFlags(CACHE_UNDERRUN, CLEAR); return play_l(); } status_t AwesomePlayer::play_l() { - mFlags &= ~SEEK_PREVIEW; + modifyFlags(SEEK_PREVIEW, CLEAR); if (mFlags & PLAYING) { return OK; @@ -793,8 +850,8 @@ status_t AwesomePlayer::play_l() { } } - mFlags |= PLAYING; - mFlags |= FIRST_FRAME; + modifyFlags(PLAYING, SET); + modifyFlags(FIRST_FRAME, SET); if (mDecryptHandle != NULL) { int64_t position; @@ -828,7 +885,7 @@ status_t AwesomePlayer::play_l() { delete mAudioPlayer; mAudioPlayer = NULL; - mFlags &= ~(PLAYING | FIRST_FRAME); + modifyFlags((PLAYING | FIRST_FRAME), CLEAR); if (mDecryptHandle != NULL) { mDrmManagerClient->setPlaybackStatus( @@ -880,7 +937,7 @@ status_t AwesomePlayer::startAudioPlayer_l() { } if (!(mFlags & AUDIOPLAYER_STARTED)) { - mFlags |= AUDIOPLAYER_STARTED; + modifyFlags(AUDIOPLAYER_STARTED, SET); bool wasSeeking = mAudioPlayer->isSeeking(); @@ -904,7 +961,7 @@ status_t AwesomePlayer::startAudioPlayer_l() { mAudioPlayer->resume(); } - mFlags |= AUDIO_RUNNING; + modifyFlags(AUDIO_RUNNING, SET); mWatchForAudioEOS = true; @@ -951,6 +1008,12 @@ void AwesomePlayer::notifyVideoSize_l() { usableHeight = mDisplayHeight; } + { + Mutex::Autolock autoLock(mStatsLock); + mStats.mVideoWidth = usableWidth; + mStats.mVideoHeight = usableHeight; + } + int32_t rotationDegrees; if (!mVideoTrack->getFormat()->findInt32( kKeyRotation, &rotationDegrees)) { @@ -1013,7 +1076,7 @@ void AwesomePlayer::initRenderer_l() { status_t AwesomePlayer::pause() { Mutex::Autolock autoLock(mLock); - mFlags &= ~CACHE_UNDERRUN; + modifyFlags(CACHE_UNDERRUN, CLEAR); return pause_l(); } @@ -1035,15 +1098,15 @@ status_t AwesomePlayer::pause_l(bool at_eos) { mAudioPlayer->pause(); } - mFlags &= ~AUDIO_RUNNING; + modifyFlags(AUDIO_RUNNING, CLEAR); } if (mFlags & TEXTPLAYER_STARTED) { mTextPlayer->pause(); - mFlags &= ~TEXT_RUNNING; + modifyFlags(TEXT_RUNNING, CLEAR); } - mFlags &= ~PLAYING; + modifyFlags(PLAYING, CLEAR); if (mDecryptHandle != NULL) { mDrmManagerClient->setPlaybackStatus(mDecryptHandle, @@ -1125,7 +1188,7 @@ void AwesomePlayer::setNativeWindow_l(const sp<ANativeWindow> &native) { mSeeking = SEEK; mSeekNotificationSent = true; mSeekTimeUs = mLastVideoTimeUs; - mFlags &= ~(AT_EOS | AUDIO_AT_EOS | VIDEO_AT_EOS); + modifyFlags((AT_EOS | AUDIO_AT_EOS | VIDEO_AT_EOS), CLEAR); } if (wasPlaying) { @@ -1143,10 +1206,10 @@ void AwesomePlayer::setAudioSink( status_t AwesomePlayer::setLooping(bool shouldLoop) { Mutex::Autolock autoLock(mLock); - mFlags = mFlags & ~LOOPING; + modifyFlags(LOOPING, CLEAR); if (shouldLoop) { - mFlags |= LOOPING; + modifyFlags(LOOPING, SET); } return OK; @@ -1200,15 +1263,15 @@ status_t AwesomePlayer::setTimedTextTrackIndex(int32_t index) { return err; } - mFlags |= TEXT_RUNNING; - mFlags |= TEXTPLAYER_STARTED; + modifyFlags(TEXT_RUNNING, SET); + modifyFlags(TEXTPLAYER_STARTED, SET); return OK; } else { // to turn off the text track display if (mFlags & TEXT_RUNNING) { - mFlags &= ~TEXT_RUNNING; + modifyFlags(TEXT_RUNNING, CLEAR); } if (mFlags & TEXTPLAYER_STARTED) { - mFlags &= ~TEXTPLAYER_STARTED; + modifyFlags(TEXTPLAYER_STARTED, CLEAR); } return mTextPlayer->setTimedTextTrackIndex(index); @@ -1235,7 +1298,7 @@ status_t AwesomePlayer::seekTo_l(int64_t timeUs) { } if (mFlags & CACHE_UNDERRUN) { - mFlags &= ~CACHE_UNDERRUN; + modifyFlags(CACHE_UNDERRUN, CLEAR); play_l(); } @@ -1250,7 +1313,7 @@ status_t AwesomePlayer::seekTo_l(int64_t timeUs) { mSeeking = SEEK; mSeekNotificationSent = false; mSeekTimeUs = timeUs; - mFlags &= ~(AT_EOS | AUDIO_AT_EOS | VIDEO_AT_EOS); + modifyFlags((AT_EOS | AUDIO_AT_EOS | VIDEO_AT_EOS), CLEAR); seekAudioIfNecessary_l(); @@ -1266,7 +1329,7 @@ status_t AwesomePlayer::seekTo_l(int64_t timeUs) { mSeekNotificationSent = true; if ((mFlags & PREPARED) && mVideoSource != NULL) { - mFlags |= SEEK_PREVIEW; + modifyFlags(SEEK_PREVIEW, SET); postVideoEvent_l(); } } @@ -1344,6 +1407,19 @@ status_t AwesomePlayer::initAudioDecoder() { return OK; } + if (mAudioSource != NULL) { + Mutex::Autolock autoLock(mStatsLock); + TrackStat *stat = &mStats.mTracks.editItemAt(mStats.mAudioTrackIndex); + + const char *component; + if (!mAudioSource->getFormat() + ->findCString(kKeyDecoderComponent, &component)) { + component = "none"; + } + + stat->mDecoderName = component; + } + return mAudioSource != NULL ? OK : UNKNOWN_ERROR; } @@ -1423,6 +1499,17 @@ status_t AwesomePlayer::initVideoDecoder(uint32_t flags) { } } + if (mVideoSource != NULL) { + Mutex::Autolock autoLock(mStatsLock); + TrackStat *stat = &mStats.mTracks.editItemAt(mStats.mVideoTrackIndex); + + const char *component; + CHECK(mVideoSource->getFormat() + ->findCString(kKeyDecoderComponent, &component)); + + stat->mDecoderName = component; + } + return mVideoSource != NULL ? OK : UNKNOWN_ERROR; } @@ -1452,7 +1539,7 @@ void AwesomePlayer::finishSeekIfNecessary(int64_t videoTimeUs) { mSeekNotificationSent = true; } - mFlags |= FIRST_FRAME; + modifyFlags(FIRST_FRAME, SET); mSeeking = NO_SEEK; if (mDecryptHandle != NULL) { @@ -1491,7 +1578,7 @@ void AwesomePlayer::onVideoEvent() { if (mAudioPlayer != NULL && (mFlags & AUDIO_RUNNING)) { mAudioPlayer->pause(); - mFlags &= ~AUDIO_RUNNING; + modifyFlags(AUDIO_RUNNING, CLEAR); } mAudioSource->pause(); } @@ -1540,7 +1627,7 @@ void AwesomePlayer::onVideoEvent() { startAudioPlayer_l(); } - mFlags |= VIDEO_AT_EOS; + modifyFlags(VIDEO_AT_EOS, SET); postStreamDoneEvent_l(err); return; } @@ -1556,6 +1643,11 @@ void AwesomePlayer::onVideoEvent() { break; } + + { + Mutex::Autolock autoLock(mStatsLock); + ++mStats.mNumVideoFramesDecoded; + } } int64_t timeUs; @@ -1588,13 +1680,13 @@ void AwesomePlayer::onVideoEvent() { if ((mFlags & TEXTPLAYER_STARTED) && !(mFlags & (TEXT_RUNNING | SEEK_PREVIEW))) { mTextPlayer->resume(); - mFlags |= TEXT_RUNNING; + modifyFlags(TEXT_RUNNING, SET); } TimeSource *ts = (mFlags & AUDIO_AT_EOS) ? &mSystemTimeSource : mTimeSource; if (mFlags & FIRST_FRAME) { - mFlags &= ~FIRST_FRAME; + modifyFlags(FIRST_FRAME, CLEAR); mTimeSourceDeltaUs = ts->getRealTimeUs() - timeUs; } @@ -1646,6 +1738,11 @@ void AwesomePlayer::onVideoEvent() { mVideoBuffer->release(); mVideoBuffer = NULL; + { + Mutex::Autolock autoLock(mStatsLock); + ++mStats.mNumVideoFramesDropped; + } + postVideoEvent_l(); return; } @@ -1672,7 +1769,7 @@ void AwesomePlayer::onVideoEvent() { mVideoBuffer = NULL; if (wasSeeking != NO_SEEK && (mFlags & SEEK_PREVIEW)) { - mFlags &= ~SEEK_PREVIEW; + modifyFlags(SEEK_PREVIEW, CLEAR); return; } @@ -1746,8 +1843,8 @@ void AwesomePlayer::onCheckAudioStatus() { status_t finalStatus; if (mWatchForAudioEOS && mAudioPlayer->reachedEOS(&finalStatus)) { mWatchForAudioEOS = false; - mFlags |= AUDIO_AT_EOS; - mFlags |= FIRST_FRAME; + modifyFlags(AUDIO_AT_EOS, SET); + modifyFlags(FIRST_FRAME, SET); postStreamDoneEvent_l(finalStatus); } } @@ -1801,7 +1898,7 @@ status_t AwesomePlayer::prepareAsync_l() { mQueueStarted = true; } - mFlags |= PREPARING; + modifyFlags(PREPARING, SET); mAsyncPrepareEvent = new AwesomeEvent( this, &AwesomePlayer::onPrepareAsyncEvent); @@ -1988,7 +2085,7 @@ void AwesomePlayer::abortPrepare(status_t err) { } mPrepareResult = err; - mFlags &= ~(PREPARING|PREPARE_CANCELLED|PREPARING_CONNECTED); + modifyFlags((PREPARING|PREPARE_CANCELLED|PREPARING_CONNECTED), CLEAR); mAsyncPrepareEvent = NULL; mPreparedCondition.broadcast(); } @@ -2036,7 +2133,7 @@ void AwesomePlayer::onPrepareAsyncEvent() { } } - mFlags |= PREPARING_CONNECTED; + modifyFlags(PREPARING_CONNECTED, SET); if (isStreamingHTTP() || mRTSPController != NULL) { postBufferingEvent_l(); @@ -2057,8 +2154,8 @@ void AwesomePlayer::finishAsyncPrepare_l() { } mPrepareResult = OK; - mFlags &= ~(PREPARING|PREPARE_CANCELLED|PREPARING_CONNECTED); - mFlags |= PREPARED; + modifyFlags((PREPARING|PREPARE_CANCELLED|PREPARING_CONNECTED), CLEAR); + modifyFlags(PREPARED, SET); mAsyncPrepareEvent = NULL; mPreparedCondition.broadcast(); } @@ -2126,4 +2223,75 @@ bool AwesomePlayer::isStreamingHTTP() const { return mCachedSource != NULL || mWVMExtractor != NULL; } +status_t AwesomePlayer::dump(int fd, const Vector<String16> &args) const { + Mutex::Autolock autoLock(mStatsLock); + + FILE *out = fdopen(dup(fd), "w"); + + fprintf(out, " AwesomePlayer\n"); + if (mStats.mFd < 0) { + fprintf(out, " URI(%s)", mStats.mURI.string()); + } else { + fprintf(out, " fd(%d)", mStats.mFd); + } + + fprintf(out, ", flags(0x%08x)", mStats.mFlags); + + if (mStats.mBitrate >= 0) { + fprintf(out, ", bitrate(%lld bps)", mStats.mBitrate); + } + + fprintf(out, "\n"); + + for (size_t i = 0; i < mStats.mTracks.size(); ++i) { + const TrackStat &stat = mStats.mTracks.itemAt(i); + + fprintf(out, " Track %d\n", i + 1); + fprintf(out, " MIME(%s)", stat.mMIME.string()); + + if (!stat.mDecoderName.isEmpty()) { + fprintf(out, ", decoder(%s)", stat.mDecoderName.string()); + } + + fprintf(out, "\n"); + + if ((ssize_t)i == mStats.mVideoTrackIndex) { + fprintf(out, + " videoDimensions(%d x %d), " + "numVideoFramesDecoded(%lld), " + "numVideoFramesDropped(%lld)\n", + mStats.mVideoWidth, + mStats.mVideoHeight, + mStats.mNumVideoFramesDecoded, + mStats.mNumVideoFramesDropped); + } + } + + fclose(out); + out = NULL; + + return OK; +} + +void AwesomePlayer::modifyFlags(unsigned value, FlagMode mode) { + switch (mode) { + case SET: + mFlags |= value; + break; + case CLEAR: + mFlags &= ~value; + break; + case ASSIGN: + mFlags = value; + break; + default: + TRESPASS(); + } + + { + Mutex::Autolock autoLock(mStatsLock); + mStats.mFlags = mFlags; + } +} + } // namespace android diff --git a/media/libstagefright/CameraSource.cpp b/media/libstagefright/CameraSource.cpp index a1f04d3fa1b0..61bb2a89b44f 100644 --- a/media/libstagefright/CameraSource.cpp +++ b/media/libstagefright/CameraSource.cpp @@ -701,12 +701,11 @@ void CameraSource::dataCallbackTimestamp(int64_t timestampUs, return; } - if (mNumFramesReceived > 0 && - timestampUs - mLastFrameTimestampUs > mGlitchDurationThresholdUs) { - if (mNumGlitches % 10 == 0) { // Don't spam the log - LOGV("Long delay detected in video recording"); + if (mNumFramesReceived > 0) { + CHECK(timestampUs > mLastFrameTimestampUs); + if (timestampUs - mLastFrameTimestampUs > mGlitchDurationThresholdUs) { + ++mNumGlitches; } - ++mNumGlitches; } // May need to skip frame or modify timestamp. Currently implemented @@ -732,6 +731,7 @@ void CameraSource::dataCallbackTimestamp(int64_t timestampUs, } ++mNumFramesReceived; + CHECK(data != NULL && data->size() > 0); mFramesReceived.push_back(data); int64_t timeUs = mStartTimeUs + (timestampUs - mFirstFrameTimeUs); mFrameTimes.push_back(timeUs); diff --git a/media/libstagefright/HTTPStream.cpp b/media/libstagefright/HTTPStream.cpp index 2caf211ee564..a156da69b6cd 100644 --- a/media/libstagefright/HTTPStream.cpp +++ b/media/libstagefright/HTTPStream.cpp @@ -139,6 +139,9 @@ static ssize_t MySendReceive( int s, void *data, size_t size, int flags, bool sendData) { ssize_t result = 0; + if (s < 0) { + return -1; + } while (size > 0) { fd_set rs, ws, es; FD_ZERO(&rs); diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp index d0f67308b97c..a953487eb4aa 100644 --- a/media/libstagefright/MPEG4Writer.cpp +++ b/media/libstagefright/MPEG4Writer.cpp @@ -131,11 +131,11 @@ private: size_t mNumSttsTableEntries; struct SttsTableEntry { - SttsTableEntry(uint32_t count, uint32_t durationUs) - : sampleCount(count), sampleDurationUs(durationUs) {} + SttsTableEntry(uint32_t count, uint32_t duration) + : sampleCount(count), sampleDuration(duration) {} uint32_t sampleCount; - uint32_t sampleDurationUs; + uint32_t sampleDuration; // time scale based }; List<SttsTableEntry> mSttsTableEntries; @@ -216,7 +216,9 @@ private: void updateTrackSizeEstimate(); void addOneStscTableEntry(size_t chunkId, size_t sampleId); void addOneStssTableEntry(size_t sampleId); - void addOneSttsTableEntry(size_t sampleCount, int64_t durationUs); + + // Duration is time scale based + void addOneSttsTableEntry(size_t sampleCount, int32_t timescaledDur); void sendTrackSummary(bool hasMultipleTracks); // Write the boxes @@ -1164,9 +1166,9 @@ void MPEG4Writer::Track::addOneStssTableEntry(size_t sampleId) { } void MPEG4Writer::Track::addOneSttsTableEntry( - size_t sampleCount, int64_t durationUs) { + size_t sampleCount, int32_t duration) { - SttsTableEntry sttsEntry(sampleCount, durationUs); + SttsTableEntry sttsEntry(sampleCount, duration); mSttsTableEntries.push_back(sttsEntry); ++mNumSttsTableEntries; } @@ -1308,6 +1310,7 @@ void MPEG4Writer::writeAllChunks() { size_t outstandingChunks = 0; Chunk chunk; while (findChunkToWrite(&chunk)) { + writeChunkToFile(&chunk); ++outstandingChunks; } @@ -2131,7 +2134,7 @@ status_t MPEG4Writer::Track::threadEntry() { if (mNumSamples == 3 || currDurationTicks != lastDurationTicks) { LOGV("%s lastDurationUs: %lld us, currDurationTicks: %lld us", mIsAudio? "Audio": "Video", lastDurationUs, currDurationTicks); - addOneSttsTableEntry(sampleCount, lastDurationUs); + addOneSttsTableEntry(sampleCount, lastDurationTicks); sampleCount = 1; } else { ++sampleCount; @@ -2217,17 +2220,18 @@ status_t MPEG4Writer::Track::threadEntry() { // frame's duration. if (mNumSamples == 1) { lastDurationUs = 0; // A single sample's duration + lastDurationTicks = 0; } else { ++sampleCount; // Count for the last sample } if (mNumSamples <= 2) { - addOneSttsTableEntry(1, lastDurationUs); + addOneSttsTableEntry(1, lastDurationTicks); if (sampleCount - 1 > 0) { - addOneSttsTableEntry(sampleCount - 1, lastDurationUs); + addOneSttsTableEntry(sampleCount - 1, lastDurationTicks); } } else { - addOneSttsTableEntry(sampleCount, lastDurationUs); + addOneSttsTableEntry(sampleCount, lastDurationTicks); } mTrackDurationUs += lastDurationUs; @@ -2772,19 +2776,15 @@ void MPEG4Writer::Track::writeSttsBox() { CHECK(mStartTimestampUs > moovStartTimeUs); trackStartTimeOffsetUs = mStartTimestampUs - moovStartTimeUs; } - int64_t prevTimestampUs = trackStartTimeOffsetUs; - for (List<SttsTableEntry>::iterator it = mSttsTableEntries.begin(); - it != mSttsTableEntries.end(); ++it) { - mOwner->writeInt32(it->sampleCount); + List<SttsTableEntry>::iterator it = mSttsTableEntries.begin(); + CHECK(it != mSttsTableEntries.end() && it->sampleCount == 1); + mOwner->writeInt32(it->sampleCount); + int32_t dur = (trackStartTimeOffsetUs * mTimeScale + 500000LL) / 1000000LL; + mOwner->writeInt32(dur + it->sampleDuration); - // Make sure that we are calculating the sample duration the exactly - // same way as we made decision on how to create stts entries. - int64_t currTimestampUs = prevTimestampUs + it->sampleDurationUs; - int32_t dur = ((currTimestampUs * mTimeScale + 500000LL) / 1000000LL - - (prevTimestampUs * mTimeScale + 500000LL) / 1000000LL); - prevTimestampUs += (it->sampleCount * it->sampleDurationUs); - - mOwner->writeInt32(dur); + while (++it != mSttsTableEntries.end()) { + mOwner->writeInt32(it->sampleCount); + mOwner->writeInt32(it->sampleDuration); } mOwner->endBox(); // stts } diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp index 9c69a6f8449b..72d0d085e41d 100644 --- a/media/libstagefright/OMXCodec.cpp +++ b/media/libstagefright/OMXCodec.cpp @@ -1643,25 +1643,26 @@ status_t OMXCodec::allocateBuffersOnPort(OMX_U32 portIndex) { return PERMISSION_DENIED; } + status_t err = OK; + if (mIsMetaDataStoredInVideoBuffers && portIndex == kPortIndexInput) { + err = mOMX->storeMetaDataInBuffers(mNode, kPortIndexInput, OMX_TRUE); + if (err != OK) { + LOGE("Storing meta data in video buffers is not supported"); + return err; + } + } + OMX_PARAM_PORTDEFINITIONTYPE def; InitOMXParams(&def); def.nPortIndex = portIndex; - status_t err = mOMX->getParameter( + err = mOMX->getParameter( mNode, OMX_IndexParamPortDefinition, &def, sizeof(def)); if (err != OK) { return err; } - if (mIsMetaDataStoredInVideoBuffers && portIndex == kPortIndexInput) { - err = mOMX->storeMetaDataInBuffers(mNode, kPortIndexInput, OMX_TRUE); - if (err != OK) { - LOGE("Storing meta data in video buffers is not supported"); - return err; - } - } - CODEC_LOGI("allocating %lu buffers of size %lu on %s port", def.nBufferCountActual, def.nBufferSize, portIndex == kPortIndexInput ? "input" : "output"); diff --git a/media/libstagefright/codecs/on2/h264dec/SoftAVC.cpp b/media/libstagefright/codecs/on2/h264dec/SoftAVC.cpp index 259fbc9a452a..830d2e018b2a 100644 --- a/media/libstagefright/codecs/on2/h264dec/SoftAVC.cpp +++ b/media/libstagefright/codecs/on2/h264dec/SoftAVC.cpp @@ -49,6 +49,8 @@ SoftAVC::SoftAVC( mPictureSize(mWidth * mHeight * 3 / 2), mCropLeft(0), mCropTop(0), + mCropWidth(mWidth), + mCropHeight(mHeight), mFirstPicture(NULL), mFirstPictureId(-1), mPicId(0), @@ -230,8 +232,8 @@ OMX_ERRORTYPE SoftAVC::getConfig( rectParams->nLeft = mCropLeft; rectParams->nTop = mCropTop; - rectParams->nWidth = mWidth; - rectParams->nHeight = mHeight; + rectParams->nWidth = mCropWidth; + rectParams->nHeight = mCropHeight; return OMX_ErrorNone; } @@ -367,6 +369,8 @@ bool SoftAVC::handlePortSettingChangeEvent(const H264SwDecInfo *info) { mWidth = info->picWidth; mHeight = info->picHeight; mPictureSize = mWidth * mHeight * 3 / 2; + mCropWidth = mWidth; + mCropHeight = mHeight; updatePortDefinitions(); notify(OMX_EventPortSettingsChanged, 1, 0, NULL); mOutputPortSettingsChange = AWAITING_DISABLED; @@ -379,14 +383,12 @@ bool SoftAVC::handlePortSettingChangeEvent(const H264SwDecInfo *info) { bool SoftAVC::handleCropRectEvent(const CropParams *crop) { if (mCropLeft != crop->cropLeftOffset || mCropTop != crop->cropTopOffset || - mWidth != crop->cropOutWidth || - mHeight != crop->cropOutHeight) { - + mCropWidth != crop->cropOutWidth || + mCropHeight != crop->cropOutHeight) { mCropLeft = crop->cropLeftOffset; mCropTop = crop->cropTopOffset; - mWidth = crop->cropOutWidth; - mHeight = crop->cropOutHeight; - mPictureSize = mWidth * mHeight * 3 / 2; + mCropWidth = crop->cropOutWidth; + mCropHeight = crop->cropOutHeight; notify(OMX_EventPortSettingsChanged, 1, OMX_IndexConfigCommonOutputCrop, NULL); diff --git a/media/libstagefright/codecs/on2/h264dec/SoftAVC.h b/media/libstagefright/codecs/on2/h264dec/SoftAVC.h index a7340c0ad076..3439efdf8b8a 100644 --- a/media/libstagefright/codecs/on2/h264dec/SoftAVC.h +++ b/media/libstagefright/codecs/on2/h264dec/SoftAVC.h @@ -67,6 +67,7 @@ private: uint32_t mWidth, mHeight, mPictureSize; uint32_t mCropLeft, mCropTop; + uint32_t mCropWidth, mCropHeight; uint8_t *mFirstPicture; int32_t mFirstPictureId; diff --git a/media/libstagefright/include/AwesomePlayer.h b/media/libstagefright/include/AwesomePlayer.h index aebcdd15dbc2..f6df3801c2fe 100644 --- a/media/libstagefright/include/AwesomePlayer.h +++ b/media/libstagefright/include/AwesomePlayer.h @@ -105,6 +105,8 @@ struct AwesomePlayer { status_t setTimedTextTrackIndex(int32_t index); + status_t dump(int fd, const Vector<String16> &args) const; + private: friend struct AwesomeEvent; friend struct PreviewPlayer; @@ -142,6 +144,7 @@ private: mutable Mutex mLock; Mutex mMiscStateLock; + mutable Mutex mStatsLock; OMXClient mClient; TimedEventQueue mQueue; @@ -294,6 +297,33 @@ private: bool isStreamingHTTP() const; void sendCacheStats(); + enum FlagMode { + SET, + CLEAR, + ASSIGN + }; + void modifyFlags(unsigned value, FlagMode mode); + + struct TrackStat { + String8 mMIME; + String8 mDecoderName; + }; + + // protected by mStatsLock + struct Stats { + int mFd; + String8 mURI; + int64_t mBitrate; + ssize_t mAudioTrackIndex; + ssize_t mVideoTrackIndex; + int64_t mNumVideoFramesDecoded; + int64_t mNumVideoFramesDropped; + int32_t mVideoWidth; + int32_t mVideoHeight; + uint32_t mFlags; + Vector<TrackStat> mTracks; + } mStats; + AwesomePlayer(const AwesomePlayer &); AwesomePlayer &operator=(const AwesomePlayer &); }; diff --git a/native/android/native_window.cpp b/native/android/native_window.cpp index 8d42edb502e7..2c0e88eef996 100644 --- a/native/android/native_window.cpp +++ b/native/android/native_window.cpp @@ -20,12 +20,20 @@ #include <android/native_window_jni.h> #include <surfaceflinger/Surface.h> #include <android_runtime/android_view_Surface.h> +#include <android_runtime/android_graphics_ParcelSurfaceTexture.h> #include <android_runtime/android_graphics_SurfaceTexture.h> using namespace android; ANativeWindow* ANativeWindow_fromSurface(JNIEnv* env, jobject surface) { - sp<ANativeWindow> win = android_Surface_getNativeWindow(env, surface); + sp<ANativeWindow> win; + if (android_Surface_isInstanceOf(env, surface)) { + win = android_Surface_getNativeWindow(env, surface); + } else if (android_SurfaceTexture_isInstanceOf(env, surface)) { + win = android_SurfaceTexture_getNativeWindow(env, surface); + } else if (android_ParcelSurfaceTexture_isInstanceOf(env, surface)) { + win = android_ParcelSurfaceTexture_getNativeWindow(env, surface); + } if (win != NULL) { win->incStrong((void*)ANativeWindow_acquire); } diff --git a/nfc-extras/java/com/android/nfc_extras/NfcAdapterExtras.java b/nfc-extras/java/com/android/nfc_extras/NfcAdapterExtras.java index 6001be92a322..7775dbf9167a 100644 --- a/nfc-extras/java/com/android/nfc_extras/NfcAdapterExtras.java +++ b/nfc-extras/java/com/android/nfc_extras/NfcAdapterExtras.java @@ -207,20 +207,4 @@ public final class NfcAdapterExtras { public NfcExecutionEnvironment getEmbeddedExecutionEnvironment() { return sEmbeddedEe; } - - public void registerTearDownApdus(String packageName, ApduList apdus) { - try { - sService.registerTearDownApdus(packageName, apdus); - } catch (RemoteException e) { - attemptDeadServiceRecovery(e); - } - } - - public void unregisterTearDownApdus(String packageName) { - try { - sService.unregisterTearDownApdus(packageName); - } catch (RemoteException e) { - attemptDeadServiceRecovery(e); - } - } } diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java index 0f5f0958fd05..9cbf704c8511 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java @@ -17,6 +17,8 @@ package com.android.providers.settings; import com.android.internal.content.PackageHelper; +import com.android.internal.telephony.BaseCommands; +import com.android.internal.telephony.Phone; import com.android.internal.telephony.RILConstants; import com.android.internal.util.XmlUtils; import com.android.internal.widget.LockPatternUtils; @@ -1300,8 +1302,13 @@ public class DatabaseHelper extends SQLiteOpenHelper { } // Set the preferred network mode to 0 = Global, CDMA default - int type = SystemProperties.getInt("ro.telephony.default_network", - RILConstants.PREFERRED_NETWORK_MODE); + int type; + if (BaseCommands.getLteOnCdmaModeStatic() == Phone.LTE_ON_CDMA_TRUE) { + type = Phone.NT_MODE_GLOBAL; + } else { + type = SystemProperties.getInt("ro.telephony.default_network", + RILConstants.PREFERRED_NETWORK_MODE); + } loadSetting(stmt, Settings.Secure.PREFERRED_NETWORK_MODE, type); // Enable or disable Cell Broadcast SMS diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml index 86ffb4d1ea06..91a8855e3684 100644 --- a/packages/SystemUI/res/values/styles.xml +++ b/packages/SystemUI/res/values/styles.xml @@ -16,25 +16,25 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android"> - <style name="TextAppearance.StatusBar.Title" parent="@android:style/TextAppearance.StatusBar"> + <style name="TextAppearance.StatusBar.Title" parent="@*android:style/TextAppearance.StatusBar"> <item name="android:textAppearance">?android:attr/textAppearanceSmall</item> <item name="android:textStyle">bold</item> <item name="android:textColor">?android:attr/textColorPrimary</item> </style> <style name="TextAppearance.StatusBar.IntruderAlert" - parent="@android:style/TextAppearance.StatusBar"> + parent="@*android:style/TextAppearance.StatusBar"> </style> <style name="TextAppearance.StatusBar.SystemPanel" - parent="@android:style/TextAppearance.StatusBar"> + parent="@*android:style/TextAppearance.StatusBar"> <item name="android:textAppearance">?android:attr/textAppearance</item> <item name="android:textStyle">normal</item> <item name="android:textColor">#FF808080</item> </style> <style name="TextAppearance.StatusBar.TextButton" - parent="@android:style/TextAppearance.StatusBar"> + parent="@*android:style/TextAppearance.StatusBar"> <item name="android:textAppearance">?android:attr/textAppearance</item> <item name="android:textStyle">normal</item> <item name="android:textColor">#FFFFFFFF</item> diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CompatModeButton.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CompatModeButton.java index 9b44f7893cde..c3052e8c3d2c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CompatModeButton.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CompatModeButton.java @@ -54,8 +54,9 @@ public class CompatModeButton extends ImageView implements View.OnClickListener } public void refresh() { - setVisibility( - (mAM.getFrontActivityScreenCompatMode() == ActivityManager.COMPAT_MODE_NEVER) + int mode = mAM.getFrontActivityScreenCompatMode(); + setVisibility((mode == ActivityManager.COMPAT_MODE_NEVER + || mode == ActivityManager.COMPAT_MODE_ALWAYS) ? View.GONE : View.VISIBLE ); diff --git a/policy/src/com/android/internal/policy/impl/LockScreen.java b/policy/src/com/android/internal/policy/impl/LockScreen.java index 7331bda1d3a1..0178395be45f 100644 --- a/policy/src/com/android/internal/policy/impl/LockScreen.java +++ b/policy/src/com/android/internal/policy/impl/LockScreen.java @@ -22,6 +22,7 @@ import com.android.internal.widget.LockPatternUtils; import com.android.internal.widget.SlidingTab; import com.android.internal.widget.WaveView; import com.android.internal.widget.WaveView.OnTriggerListener; +import com.android.internal.widget.multiwaveview.MultiWaveView; import android.app.ActivityManager; import android.content.Context; @@ -91,6 +92,8 @@ class LockScreen extends LinearLayout implements KeyguardScreen, private WaveView mEnergyWave; private SlidingTabMethods mSlidingTabMethods; private WaveViewMethods mWaveViewMethods; + private MultiWaveView mMultiWaveView; + private MultiWaveViewMethods mMultiWaveViewMethods; /** * The status of this lock screen. @@ -166,34 +169,9 @@ class LockScreen extends LinearLayout implements KeyguardScreen, if (whichHandle == SlidingTab.OnTriggerListener.LEFT_HANDLE) { mCallback.goToUnlockScreen(); } else if (whichHandle == SlidingTab.OnTriggerListener.RIGHT_HANDLE) { - // toggle silent mode - mSilentMode = !mSilentMode; - if (mSilentMode) { - final boolean vibe = (Settings.System.getInt( - getContext().getContentResolver(), - Settings.System.VIBRATE_IN_SILENT, 1) == 1); - - mAudioManager.setRingerMode(vibe - ? AudioManager.RINGER_MODE_VIBRATE - : AudioManager.RINGER_MODE_SILENT); - } else { - mAudioManager.setRingerMode(AudioManager.RINGER_MODE_NORMAL); - } - + toggleRingMode(); updateRightTabResources(); - - String message = mSilentMode ? - getContext().getString(R.string.global_action_silent_mode_on_status) : - getContext().getString(R.string.global_action_silent_mode_off_status); - - final int toastIcon = mSilentMode - ? R.drawable.ic_lock_ringer_off - : R.drawable.ic_lock_ringer_on; - - final int toastColor = mSilentMode - ? getContext().getResources().getColor(R.color.keyguard_text_color_soundoff) - : getContext().getResources().getColor(R.color.keyguard_text_color_soundon); - toastMessage(mScreenLocked, message, toastColor, toastIcon); + doSilenceRingToast(); mCallback.pokeWakelock(); } } @@ -214,19 +192,14 @@ class LockScreen extends LinearLayout implements KeyguardScreen, } } - class WaveViewMethods implements WaveView.OnTriggerListener { - private static final int WAIT_FOR_ANIMATION_TIMEOUT = 0; - private static final int STAY_ON_WHILE_GRABBED_TIMEOUT = 30000; + private static final int WAIT_FOR_ANIMATION_TIMEOUT = 0; + private static final int STAY_ON_WHILE_GRABBED_TIMEOUT = 30000; + class WaveViewMethods implements WaveView.OnTriggerListener { /** {@inheritDoc} */ public void onTrigger(View v, int whichHandle) { if (whichHandle == WaveView.OnTriggerListener.CENTER_HANDLE) { - // Delay hiding lock screen long enough for animation to finish - postDelayed(new Runnable() { - public void run() { - mCallback.goToUnlockScreen(); - } - }, WAIT_FOR_ANIMATION_TIMEOUT); + requestUnlockScreen(); } } @@ -243,6 +216,80 @@ class LockScreen extends LinearLayout implements KeyguardScreen, } } + class MultiWaveViewMethods implements MultiWaveView.OnTriggerListener { + public void onGrabbed(View v, int handle) { + + } + public void onReleased(View v, int handle) { + + } + public void onTrigger(View v, int target) { + if (target == 0) { // TODO: Use resources to determine which handle was used + mCallback.goToUnlockScreen(); + } else if (target == 2) { + toggleRingMode(); + updateResources(); + doSilenceRingToast(); + mCallback.pokeWakelock(); + } + + } + + private void updateResources() { + mMultiWaveView.setTargetResources(mSilentMode ? R.array.lockscreen_targets_when_silent + : R.array.lockscreen_targets_when_soundon); + } + + public void onGrabbedStateChange(View v, int handle) { + // Don't poke the wake lock when returning to a state where the handle is + // not grabbed since that can happen when the system (instead of the user) + // cancels the grab. + if (handle != MultiWaveView.OnTriggerListener.NO_HANDLE) { + mCallback.pokeWakelock(); + } + } + } + + private void requestUnlockScreen() { + // Delay hiding lock screen long enough for animation to finish + postDelayed(new Runnable() { + public void run() { + mCallback.goToUnlockScreen(); + } + }, WAIT_FOR_ANIMATION_TIMEOUT); + } + + private void doSilenceRingToast() { + String message = mSilentMode ? + getContext().getString(R.string.global_action_silent_mode_on_status) : + getContext().getString(R.string.global_action_silent_mode_off_status); + + final int toastIcon = mSilentMode + ? R.drawable.ic_lock_ringer_off + : R.drawable.ic_lock_ringer_on; + + final int toastColor = mSilentMode + ? getContext().getResources().getColor(R.color.keyguard_text_color_soundoff) + : getContext().getResources().getColor(R.color.keyguard_text_color_soundon); + toastMessage(mScreenLocked, message, toastColor, toastIcon); + } + + private void toggleRingMode() { + // toggle silent mode + mSilentMode = !mSilentMode; + if (mSilentMode) { + final boolean vibe = (Settings.System.getInt( + getContext().getContentResolver(), + Settings.System.VIBRATE_IN_SILENT, 1) == 1); + + mAudioManager.setRingerMode(vibe + ? AudioManager.RINGER_MODE_VIBRATE + : AudioManager.RINGER_MODE_SILENT); + } else { + mAudioManager.setRingerMode(AudioManager.RINGER_MODE_NORMAL); + } + } + /** * In general, we enable unlocking the insecure key guard with the menu key. However, there are * some cases where we wish to disable it, notably when the menu button placement or technology @@ -319,9 +366,9 @@ class LockScreen extends LinearLayout implements KeyguardScreen, mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE); mSilentMode = isSilentMode(); - mSlidingTab = (SlidingTab) findViewById(R.id.tab_selector); - mEnergyWave = (WaveView) findViewById(R.id.wave_view); - if (mSlidingTab != null) { + View unlockWidget = findViewById(R.id.unlock_widget); + if (unlockWidget instanceof SlidingTab) { + mSlidingTab = (SlidingTab) unlockWidget; mSlidingTab.setHoldAfterTrigger(true, false); mSlidingTab.setLeftHintText(R.string.lockscreen_unlock_label); mSlidingTab.setLeftTabResources( @@ -332,11 +379,17 @@ class LockScreen extends LinearLayout implements KeyguardScreen, mSlidingTabMethods = new SlidingTabMethods(); mSlidingTab.setOnTriggerListener(mSlidingTabMethods); mSlidingTabMethods.updateRightTabResources(); - } else if (mEnergyWave != null) { + } else if (unlockWidget instanceof WaveView) { + mEnergyWave = (WaveView) unlockWidget; mWaveViewMethods = new WaveViewMethods(); mEnergyWave.setOnTriggerListener(mWaveViewMethods); + } else if (unlockWidget instanceof MultiWaveView) { + mMultiWaveView = (MultiWaveView) unlockWidget; + mMultiWaveViewMethods = new MultiWaveViewMethods(); + mMultiWaveViewMethods.updateResources(); // update silence/ring resources + mMultiWaveView.setOnTriggerListener(mMultiWaveViewMethods); } else { - throw new IllegalStateException("Must have either SlidingTab or WaveView defined"); + throw new IllegalStateException("Unrecognized unlock widget: " + unlockWidget); } resetStatusInfo(updateMonitor); @@ -538,7 +591,7 @@ class LockScreen extends LinearLayout implements KeyguardScreen, // layout mScreenLocked.setVisibility(View.VISIBLE); - mEmergencyCallText.setVisibility(View.VISIBLE); + mLockPatternUtils.updateEmergencyCallText(mEmergencyCallText); enableUnlock(); // do not need to show the e-call button; user may unlock break; @@ -552,8 +605,8 @@ class LockScreen extends LinearLayout implements KeyguardScreen, // layout mScreenLocked.setVisibility(View.VISIBLE); - mEmergencyCallText.setVisibility(View.VISIBLE); - mEmergencyCallButton.setVisibility(View.VISIBLE); + mLockPatternUtils.updateEmergencyCallText(mEmergencyCallText); + mLockPatternUtils.updateEmergencyCallButtonState(mEmergencyCallButton); disableUnlock(); break; @@ -579,14 +632,13 @@ class LockScreen extends LinearLayout implements KeyguardScreen, mScreenLocked.setText(R.string.lockscreen_sim_puk_locked_instructions); // layout + mLockPatternUtils.updateEmergencyCallText(mEmergencyCallText); + mLockPatternUtils.updateEmergencyCallButtonState(mEmergencyCallButton); if (mLockPatternUtils.isPukUnlockScreenEnable()) { mScreenLocked.setVisibility(View.INVISIBLE); - mEmergencyCallText.setVisibility(View.GONE); enableUnlock(); } else { mScreenLocked.setVisibility(View.VISIBLE); - mEmergencyCallText.setVisibility(View.VISIBLE); - mEmergencyCallButton.setVisibility(View.VISIBLE); disableUnlock(); } break; diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java index 852021948a9c..9dd2625db20c 100755 --- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java @@ -873,7 +873,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN; lp.format = PixelFormat.TRANSLUCENT; lp.setTitle("PointerLocation"); - WindowManagerImpl wm = (WindowManagerImpl) + WindowManager wm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE); wm.addView(addView, lp); @@ -896,7 +896,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { mPointerLocationInputChannel = null; } - WindowManagerImpl wm = (WindowManagerImpl) + WindowManager wm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE); wm.removeView(removeView); } @@ -1189,8 +1189,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { com.android.internal.R.styleable.Window_windowAnimationStyle, 0); params.setTitle("Starting " + packageName); - WindowManagerImpl wm = (WindowManagerImpl) - context.getSystemService(Context.WINDOW_SERVICE); + WindowManager wm = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE); View view = win.getDecorView(); if (win.isFloating()) { @@ -1235,7 +1234,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { TAG, "Removing starting window for " + appToken + ": " + window); if (window != null) { - WindowManagerImpl wm = (WindowManagerImpl) mContext.getSystemService(Context.WINDOW_SERVICE); + WindowManager wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE); wm.removeView(window); } } diff --git a/services/input/InputReader.cpp b/services/input/InputReader.cpp index 09b24a8ef1ed..fcc619857c0a 100644 --- a/services/input/InputReader.cpp +++ b/services/input/InputReader.cpp @@ -4185,7 +4185,11 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, // approches 1.0. Recall that dot(v1, v2) = cos(angle) * mag(v1) * mag(v2). PointerGesture::Delta& delta1 = mPointerGesture.referenceDeltas[id1]; PointerGesture::Delta& delta2 = mPointerGesture.referenceDeltas[id2]; - float dot = delta1.dx * delta2.dx + delta1.dy * delta2.dy; + float dx1 = delta1.dx * mLocked.pointerGestureXZoomScale; + float dy1 = delta1.dy * mLocked.pointerGestureYZoomScale; + float dx2 = delta2.dx * mLocked.pointerGestureXZoomScale; + float dy2 = delta2.dy * mLocked.pointerGestureYZoomScale; + float dot = dx1 * dx2 + dy1 * dy2; float cosine = dot / (dist1 * dist2); // denominator always > 0 if (cosine >= mConfig->pointerGestureSwipeTransitionAngleCosine) { // Pointers are moving in the same direction. Switch to SWIPE. diff --git a/services/input/InputReader.h b/services/input/InputReader.h index 36cd89cfb576..55315f70fb25 100644 --- a/services/input/InputReader.h +++ b/services/input/InputReader.h @@ -143,7 +143,7 @@ struct InputReaderConfiguration { pointerGestureTapSlop(10.0f), // 10 pixels pointerGestureMultitouchSettleInterval(100 * 1000000LL), // 100 ms pointerGestureMultitouchMinDistance(15), // 15 pixels - pointerGestureSwipeTransitionAngleCosine(0.5f), // cosine of 45degrees + pointerGestureSwipeTransitionAngleCosine(0.2588f), // cosine of 75 degrees pointerGestureSwipeMaxWidthRatio(0.25f), pointerGestureMovementSpeedRatio(0.8f), pointerGestureZoomSpeedRatio(0.3f) { } diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java index c28732e8d2b4..3aa1239c8df9 100644 --- a/services/java/com/android/server/BackupManagerService.java +++ b/services/java/com/android/server/BackupManagerService.java @@ -1939,6 +1939,18 @@ class BackupManagerService extends IBackupManager.Stub { long mode; // e.g. 0666 (actually int) long mtime; // last mod time, UTC time_t (actually int) long size; // bytes of content + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(128); + sb.append("FileMetadata{"); + sb.append(packageName); sb.append(','); + sb.append(type); sb.append(','); + sb.append(domain); sb.append(':'); sb.append(path); sb.append(','); + sb.append(size); + sb.append('}'); + return sb.toString(); + } } enum RestorePolicy { @@ -1956,6 +1968,8 @@ class BackupManagerService extends IBackupManager.Stub { ApplicationInfo mTargetApp; ParcelFileDescriptor[] mPipes = null; + long mBytes; + // possible handling states for a given package in the restore dataset final HashMap<String, RestorePolicy> mPackagePolicies = new HashMap<String, RestorePolicy>(); @@ -2029,6 +2043,7 @@ class BackupManagerService extends IBackupManager.Stub { } try { + mBytes = 0; byte[] buffer = new byte[32 * 1024]; FileInputStream instream = new FileInputStream(mInputFile.getFileDescriptor()); @@ -2037,7 +2052,7 @@ class BackupManagerService extends IBackupManager.Stub { didRestore = restoreOneFile(instream, buffer); } while (didRestore); - if (DEBUG) Slog.v(TAG, "Done consuming input tarfile"); + if (DEBUG) Slog.v(TAG, "Done consuming input tarfile, total bytes=" + mBytes); } finally { tearDownPipes(); tearDownAgent(mTargetApp); @@ -2045,6 +2060,7 @@ class BackupManagerService extends IBackupManager.Stub { try { mInputFile.close(); } catch (IOException e) { + Slog.w(TAG, "Close of restore data pipe threw", e); /* nothing we can do about this */ } synchronized (mCurrentOpLock) { @@ -2258,6 +2274,7 @@ class BackupManagerService extends IBackupManager.Stub { int toRead = (toCopy > buffer.length) ? buffer.length : (int)toCopy; int nRead = instream.read(buffer, 0, toRead); + if (nRead >= 0) mBytes += nRead; if (nRead <= 0) break; toCopy -= nRead; @@ -2267,8 +2284,7 @@ class BackupManagerService extends IBackupManager.Stub { try { pipe.write(buffer, 0, nRead); } catch (IOException e) { - Slog.e(TAG, - "Failed to write to restore pipe", e); + Slog.e(TAG, "Failed to write to restore pipe", e); pipeOkay = false; } } @@ -2304,6 +2320,7 @@ class BackupManagerService extends IBackupManager.Stub { int toRead = (bytesToConsume > buffer.length) ? buffer.length : (int)bytesToConsume; long nRead = instream.read(buffer, 0, toRead); + if (nRead >= 0) mBytes += nRead; if (nRead <= 0) break; bytesToConsume -= nRead; } @@ -2325,15 +2342,13 @@ class BackupManagerService extends IBackupManager.Stub { void tearDownPipes() { if (mPipes != null) { - if (mPipes[0] != null) { - try { - mPipes[0].close(); - mPipes[0] = null; - mPipes[1].close(); - mPipes[1] = null; - } catch (IOException e) { - Slog.w(TAG, "Couldn't close agent pipes", e); - } + try { + mPipes[0].close(); + mPipes[0] = null; + mPipes[1].close(); + mPipes[1] = null; + } catch (IOException e) { + Slog.w(TAG, "Couldn't close agent pipes", e); } mPipes = null; } @@ -2447,6 +2462,7 @@ class BackupManagerService extends IBackupManager.Stub { while (size > 0) { long toRead = (buffer.length < size) ? buffer.length : size; int didRead = instream.read(buffer, 0, (int)toRead); + if (didRead >= 0) mBytes += didRead; apkStream.write(buffer, 0, didRead); size -= didRead; } @@ -2529,7 +2545,8 @@ class BackupManagerService extends IBackupManager.Stub { long partial = (size + 512) % 512; if (partial > 0) { byte[] buffer = new byte[512]; - instream.read(buffer, 0, 512 - (int)partial); + int nRead = instream.read(buffer, 0, 512 - (int)partial); + if (nRead >= 0) mBytes += nRead; } } @@ -2545,6 +2562,7 @@ class BackupManagerService extends IBackupManager.Stub { while (nRead < info.size) { nRead += instream.read(buffer, nRead, (int)info.size - nRead); } + if (nRead >= 0) mBytes += nRead; RestorePolicy policy = RestorePolicy.IGNORE; String[] str = new String[1]; @@ -2729,9 +2747,17 @@ class BackupManagerService extends IBackupManager.Stub { switch (typeChar) { case '0': info.type = FullBackup.TYPE_FILE; break; - case '5': info.type = FullBackup.TYPE_DIRECTORY; break; + case '5': { + info.type = FullBackup.TYPE_DIRECTORY; + if (info.size != 0) { + Slog.w(TAG, "Directory entry with nonzero size in header"); + info.size = 0; + } + break; + } case 0: { // presume EOF + if (DEBUG) Slog.w(TAG, "Saw type=0 in tar header block, info=" + info); return null; } default: { @@ -2788,6 +2814,7 @@ class BackupManagerService extends IBackupManager.Stub { boolean readTarHeader(InputStream instream, byte[] block) throws IOException { int nRead = instream.read(block, 0, 512); + if (nRead >= 0) mBytes += nRead; if (nRead > 0 && nRead != 512) { // if we read only a partial block, then things are // clearly screwed up. terminate the restore. @@ -2810,6 +2837,7 @@ class BackupManagerService extends IBackupManager.Stub { int numBlocks = (int)((info.size + 511) >> 9); byte[] data = new byte[numBlocks * 512]; int nRead = instream.read(data); + if (nRead >= 0) mBytes += nRead; if (nRead != data.length) { return false; } diff --git a/services/java/com/android/server/DevicePolicyManagerService.java b/services/java/com/android/server/DevicePolicyManagerService.java index 3181a9d061b5..d54930870564 100644 --- a/services/java/com/android/server/DevicePolicyManagerService.java +++ b/services/java/com/android/server/DevicePolicyManagerService.java @@ -172,6 +172,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { long passwordExpirationDate = DEF_PASSWORD_EXPIRATION_DATE; boolean encryptionRequested = false; + boolean disableCamera = false; // TODO: review implementation decisions with frameworks team boolean specifiesGlobalProxy = false; @@ -274,6 +275,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { out.attribute(null, "value", Boolean.toString(encryptionRequested)); out.endTag(null, "encryption-requested"); } + if (disableCamera) { + out.startTag(null, "disable-camera"); + out.attribute(null, "value", Boolean.toString(disableCamera)); + out.endTag(null, "disable-camera"); + } } void readFromXml(XmlPullParser parser) @@ -339,6 +345,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } else if ("encryption-requested".equals(tag)) { encryptionRequested = Boolean.parseBoolean( parser.getAttributeValue(null, "value")); + } else if ("disable-camera".equals(tag)) { + disableCamera = Boolean.parseBoolean( + parser.getAttributeValue(null, "value")); } else { Slog.w(TAG, "Unknown admin tag: " + tag); } @@ -393,6 +402,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } pw.print(prefix); pw.print("encryptionRequested="); pw.println(encryptionRequested); + pw.print(prefix); pw.print("disableCamera="); + pw.println(disableCamera); } } @@ -424,6 +435,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } if (removed) { validatePasswordOwnerLocked(); + syncDeviceCapabilitiesLocked(); saveSettingsLocked(); } } @@ -578,6 +590,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { mAdminList.remove(admin); mAdminMap.remove(adminReceiver); validatePasswordOwnerLocked(); + syncDeviceCapabilitiesLocked(); if (doProxyCleanup) { resetGlobalProxy(); } @@ -801,6 +814,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } validatePasswordOwnerLocked(); + syncDeviceCapabilitiesLocked(); long timeMs = getMaximumTimeToLock(null); if (timeMs <= 0) { @@ -844,6 +858,28 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } + /** + * Pushes down policy information to the system for any policies related to general device + * capabilities that need to be enforced by lower level services (e.g. Camera services). + */ + void syncDeviceCapabilitiesLocked() { + // Ensure the status of the camera is synced down to the system. Interested native services + // should monitor this value and act accordingly. + boolean systemState = SystemProperties.getBoolean(SYSTEM_PROP_DISABLE_CAMERA, false); + boolean cameraDisabled = getCameraDisabled(null); + if (cameraDisabled != systemState) { + long token = Binder.clearCallingIdentity(); + try { + String value = cameraDisabled ? "1" : "0"; + Slog.v(TAG, "Change in camera state [" + + SYSTEM_PROP_DISABLE_CAMERA + "] = " + value); + SystemProperties.set(SYSTEM_PROP_DISABLE_CAMERA, value); + } finally { + Binder.restoreCallingIdentity(token); + } + } + } + public void systemReady() { synchronized (this) { loadSettingsLocked(); @@ -1982,6 +2018,53 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { private void setEncryptionRequested(boolean encrypt) { } + /** + * The system property used to share the state of the camera. The native camera service + * is expected to read this property and act accordingly. + */ + public static final String SYSTEM_PROP_DISABLE_CAMERA = "sys.secpolicy.camera.disabled"; + + /** + * Disables all device cameras according to the specified admin. + */ + public void setCameraDisabled(ComponentName who, boolean disabled) { + synchronized (this) { + if (who == null) { + throw new NullPointerException("ComponentName is null"); + } + ActiveAdmin ap = getActiveAdminForCallerLocked(who, + DeviceAdminInfo.USES_POLICY_DISABLE_CAMERA); + if (ap.disableCamera != disabled) { + ap.disableCamera = disabled; + saveSettingsLocked(); + } + syncDeviceCapabilitiesLocked(); + } + } + + /** + * Gets whether or not all device cameras are disabled for a given admin, or disabled for any + * active admins. + */ + public boolean getCameraDisabled(ComponentName who) { + synchronized (this) { + if (who != null) { + ActiveAdmin admin = getActiveAdminUncheckedLocked(who); + return (admin != null) ? admin.disableCamera : false; + } + + // Determine whether or not the device camera is disabled for any active admins. + final int N = mAdminList.size(); + for (int i = 0; i < N; i++) { + ActiveAdmin admin = mAdminList.get(i); + if (admin.disableCamera) { + return true; + } + } + return false; + } + } + @Override protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java index f4308cdd4a45..fbde9d138ecf 100644 --- a/services/java/com/android/server/InputMethodManagerService.java +++ b/services/java/com/android/server/InputMethodManagerService.java @@ -17,7 +17,9 @@ package com.android.server; import com.android.internal.content.PackageMonitor; +import com.android.internal.os.AtomicFile; import com.android.internal.os.HandlerCaller; +import com.android.internal.util.FastXmlSerializer; import com.android.internal.view.IInputContext; import com.android.internal.view.IInputMethod; import com.android.internal.view.IInputMethodCallback; @@ -25,10 +27,11 @@ import com.android.internal.view.IInputMethodClient; import com.android.internal.view.IInputMethodManager; import com.android.internal.view.IInputMethodSession; import com.android.internal.view.InputBindResult; - import com.android.server.EventLogTags; +import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; +import org.xmlpull.v1.XmlSerializer; import android.app.ActivityManagerNative; import android.app.AlertDialog; @@ -37,9 +40,9 @@ import android.content.ComponentName; import android.content.ContentResolver; import android.content.Context; import android.content.DialogInterface; -import android.content.IntentFilter; import android.content.DialogInterface.OnCancelListener; import android.content.Intent; +import android.content.IntentFilter; import android.content.ServiceConnection; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; @@ -51,6 +54,7 @@ import android.content.res.TypedArray; import android.database.ContentObserver; import android.inputmethodservice.InputMethodService; import android.os.Binder; +import android.os.Environment; import android.os.Handler; import android.os.IBinder; import android.os.IInterface; @@ -68,9 +72,10 @@ import android.text.style.SuggestionSpan; import android.util.EventLog; import android.util.LruCache; import android.util.Pair; -import android.util.Slog; import android.util.PrintWriterPrinter; import android.util.Printer; +import android.util.Slog; +import android.util.Xml; import android.view.IWindowManager; import android.view.WindowManager; import android.view.inputmethod.EditorInfo; @@ -80,15 +85,19 @@ import android.view.inputmethod.InputMethodInfo; import android.view.inputmethod.InputMethodManager; import android.view.inputmethod.InputMethodSubtype; +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.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.List; -import java.util.Map; +import java.util.Set; import java.util.TreeMap; /** @@ -134,6 +143,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub final StatusBarManagerService mStatusBar; final IWindowManager mIWindowManager; final HandlerCaller mCaller; + private final InputMethodFileManager mFileManager; final InputBindResult mNoBinding = new InputBindResult(null, null, -1); @@ -407,10 +417,15 @@ public class InputMethodManagerService extends IInputMethodManager.Stub if (curInputMethodId != null) { for (int i=0; i<N; i++) { InputMethodInfo imi = mMethodList.get(i); - if (imi.getId().equals(curInputMethodId)) { + final String imiId = imi.getId(); + if (imiId.equals(curInputMethodId)) { curIm = imi; } + int change = isPackageDisappearing(imi.getPackageName()); + if (isPackageModified(imi.getPackageName())) { + mFileManager.deleteAllInputMethodSubtypes(imiId); + } if (change == PACKAGE_TEMPORARY_CHANGE || change == PACKAGE_PERMANENT_CHANGE) { Slog.i(TAG, "Input method uninstalled, disabling: " @@ -471,9 +486,11 @@ public class InputMethodManagerService extends IInputMethodManager.Stub mMethod = method; } + @Override public void finishedEvent(int seq, boolean handled) throws RemoteException { } + @Override public void sessionCreated(IInputMethodSession session) throws RemoteException { onSessionCreated(mMethod, session); } @@ -486,10 +503,14 @@ public class InputMethodManagerService extends IInputMethodManager.Stub mIWindowManager = IWindowManager.Stub.asInterface( ServiceManager.getService(Context.WINDOW_SERVICE)); mCaller = new HandlerCaller(context, new HandlerCaller.Callback() { + @Override public void executeMessage(Message msg) { handleMessage(msg); } }); + synchronized (mMethodMap) { + mFileManager = new InputMethodFileManager(mMethodMap); + } (new MyPackageMonitor()).register(mContext, true); @@ -566,12 +587,14 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } } + @Override public List<InputMethodInfo> getInputMethodList() { synchronized (mMethodMap) { return new ArrayList<InputMethodInfo>(mMethodList); } } + @Override public List<InputMethodInfo> getEnabledInputMethodList() { synchronized (mMethodMap) { return mSettings.getEnabledInputMethodListLocked(); @@ -602,6 +625,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub return InputMethodSubtype.sort(mContext, 0, imi, enabledSubtypes); } + @Override public List<InputMethodSubtype> getEnabledInputMethodSubtypeList(InputMethodInfo imi, boolean allowsImplicitlySelectedSubtypes) { synchronized (mMethodMap) { @@ -609,6 +633,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } } + @Override public void addClient(IInputMethodClient client, IInputContext inputContext, int uid, int pid) { synchronized (mMethodMap) { @@ -617,6 +642,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } } + @Override public void removeClient(IInputMethodClient client) { synchronized (mMethodMap) { mClients.remove(client.asBinder()); @@ -840,6 +866,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub return null; } + @Override public InputBindResult startInput(IInputMethodClient client, IInputContext inputContext, EditorInfo attribute, boolean initial, boolean needResult) { @@ -854,9 +881,11 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } } + @Override public void finishInput(IInputMethodClient client) { } + @Override public void onServiceConnected(ComponentName name, IBinder service) { synchronized (mMethodMap) { if (mCurIntent != null && name.equals(mCurIntent.getComponent())) { @@ -947,6 +976,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub mStatusBar.setIconVisibility("ime", false); } + @Override public void onServiceDisconnected(ComponentName name) { synchronized (mMethodMap) { if (DEBUG) Slog.v(TAG, "Service disconnected: " + name @@ -1012,6 +1042,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } } + @Override public void registerSuggestionSpansForNotification(SuggestionSpan[] spans) { synchronized (mMethodMap) { final InputMethodInfo currentImi = mMethodMap.get(mCurMethodId); @@ -1025,6 +1056,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } } + @Override public boolean notifySuggestionPicked(SuggestionSpan span, String originalString, int index) { synchronized (mMethodMap) { final InputMethodInfo targetImi = mSecureSuggestionSpans.get(span); @@ -1485,6 +1517,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } } + @Override public InputMethodSubtype getLastInputMethodSubtype() { synchronized (mMethodMap) { final Pair<String, String> lastIme = mSettings.getLastInputMethodAndSubtypeLocked(); @@ -1503,6 +1536,22 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } } + @Override + public boolean setAdditionalInputMethodSubtypes(IBinder token, InputMethodSubtype[] subtypes) { + if (token == null || mCurToken != token) { + return false; + } + if (subtypes == null || subtypes.length == 0) return false; + synchronized (mMethodMap) { + final InputMethodInfo imi = mMethodMap.get(mCurMethodId); + if (imi == null) return false; + final int N = subtypes.length; + mFileManager.addInputMethodSubtypes(mCurMethodId, subtypes); + buildInputMethodListLocked(mMethodList, mMethodMap); + return true; + } + } + private void setInputMethodWithSubtypeId(IBinder token, String id, int subtypeId) { synchronized (mMethodMap) { if (token == null) { @@ -1749,6 +1798,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub new Intent(InputMethod.SERVICE_INTERFACE), PackageManager.GET_META_DATA); + final HashMap<String, List<InputMethodSubtype>> additionalSubtypes = + mFileManager.getAllAdditionalInputMethodSubtypes(); for (int i = 0; i < services.size(); ++i) { ResolveInfo ri = services.get(i); ServiceInfo si = ri.serviceInfo; @@ -1764,7 +1815,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub if (DEBUG) Slog.d(TAG, "Checking " + compName); try { - InputMethodInfo p = new InputMethodInfo(mContext, ri); + InputMethodInfo p = new InputMethodInfo(mContext, ri, additionalSubtypes); list.add(p); final String id = p.getId(); map.put(id, p); @@ -2399,6 +2450,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } // TODO: We should change the return type from List to List<Parcelable> + @Override public List getShortcutInputMethodsAndSubtypes() { synchronized (mMethodMap) { ArrayList<Object> ret = new ArrayList<Object>(); @@ -2821,6 +2873,200 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } } + private static class InputMethodFileManager { + private static final String SYSTEM_PATH = "system"; + private static final String INPUT_METHOD_PATH = "inputmethod"; + private static final String ADDITIONAL_SUBTYPES_FILE_NAME = "subtypes.xml"; + private static final String NODE_SUBTYPES = "subtypes"; + private static final String NODE_SUBTYPE = "subtype"; + private static final String NODE_IMI = "imi"; + private static final String ATTR_ID = "id"; + private static final String ATTR_LABEL = "label"; + private static final String ATTR_ICON = "icon"; + private static final String ATTR_IME_SUBTYPE_LOCALE = "imeSubtypeLocale"; + private static final String ATTR_IME_SUBTYPE_MODE = "imeSubtypeMode"; + private static final String ATTR_IME_SUBTYPE_EXTRA_VALUE = "imeSubtypeExtraValue"; + private static final String ATTR_IS_AUXILIARY = "isAuxiliary"; + private final AtomicFile mAdditionalInputMethodSubtypeFile; + private final HashMap<String, InputMethodInfo> mMethodMap; + private final HashMap<String, List<InputMethodSubtype>> mSubtypesMap = + new HashMap<String, List<InputMethodSubtype>>(); + public InputMethodFileManager(HashMap<String, InputMethodInfo> methodMap) { + if (methodMap == null) { + throw new NullPointerException("methodMap is null"); + } + mMethodMap = methodMap; + final File systemDir = new File(Environment.getDataDirectory(), SYSTEM_PATH); + final File inputMethodDir = new File(systemDir, INPUT_METHOD_PATH); + if (!inputMethodDir.mkdirs()) { + Slog.w(TAG, "Couldn't create dir.: " + inputMethodDir.getAbsolutePath()); + } + final File subtypeFile = new File(inputMethodDir, ADDITIONAL_SUBTYPES_FILE_NAME); + mAdditionalInputMethodSubtypeFile = new AtomicFile(subtypeFile); + if (!subtypeFile.exists()) { + // If "subtypes.xml" doesn't exist, create a blank file. + writeAdditionalInputMethodSubtypes(mSubtypesMap, mAdditionalInputMethodSubtypeFile, + methodMap); + } else { + readAdditionalInputMethodSubtypes(mSubtypesMap, mAdditionalInputMethodSubtypeFile); + } + } + + private void deleteAllInputMethodSubtypes(String imiId) { + synchronized (mMethodMap) { + mSubtypesMap.remove(imiId); + writeAdditionalInputMethodSubtypes(mSubtypesMap, mAdditionalInputMethodSubtypeFile, + mMethodMap); + } + } + + public void addInputMethodSubtypes( + String imiId, InputMethodSubtype[] additionalSubtypes) { + synchronized (mMethodMap) { + final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>(); + final int N = additionalSubtypes.length; + for (int i = 0; i < N; ++i) { + final InputMethodSubtype subtype = additionalSubtypes[i]; + if (!subtypes.contains(subtype)) { + subtypes.add(subtype); + } + } + mSubtypesMap.put(imiId, subtypes); + writeAdditionalInputMethodSubtypes(mSubtypesMap, mAdditionalInputMethodSubtypeFile, + mMethodMap); + } + } + + public HashMap<String, List<InputMethodSubtype>> getAllAdditionalInputMethodSubtypes() { + synchronized (mMethodMap) { + return mSubtypesMap; + } + } + + private static void writeAdditionalInputMethodSubtypes( + HashMap<String, List<InputMethodSubtype>> allSubtypes, AtomicFile subtypesFile, + HashMap<String, InputMethodInfo> methodMap) { + // Safety net for the case that this function is called before methodMap is set. + final boolean isSetMethodMap = methodMap != null && methodMap.size() > 0; + FileOutputStream fos = null; + try { + fos = subtypesFile.startWrite(); + final XmlSerializer out = new FastXmlSerializer(); + out.setOutput(fos, "utf-8"); + out.startDocument(null, true); + out.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true); + out.startTag(null, NODE_SUBTYPES); + for (String imiId : allSubtypes.keySet()) { + if (isSetMethodMap && !methodMap.containsKey(imiId)) { + Slog.w(TAG, "IME uninstalled or not valid.: " + imiId); + continue; + } + out.startTag(null, NODE_IMI); + out.attribute(null, ATTR_ID, imiId); + final List<InputMethodSubtype> subtypesList = allSubtypes.get(imiId); + final int N = subtypesList.size(); + for (int i = 0; i < N; ++i) { + final InputMethodSubtype subtype = subtypesList.get(i); + out.startTag(null, NODE_SUBTYPE); + out.attribute(null, ATTR_ICON, String.valueOf(subtype.getIconResId())); + out.attribute(null, ATTR_LABEL, String.valueOf(subtype.getNameResId())); + out.attribute(null, ATTR_IME_SUBTYPE_LOCALE, subtype.getLocale()); + out.attribute(null, ATTR_IME_SUBTYPE_MODE, subtype.getMode()); + out.attribute(null, ATTR_IME_SUBTYPE_EXTRA_VALUE, subtype.getExtraValue()); + out.attribute(null, ATTR_IS_AUXILIARY, + String.valueOf(subtype.isAuxiliary() ? 1 : 0)); + out.endTag(null, NODE_SUBTYPE); + } + out.endTag(null, NODE_IMI); + } + out.endTag(null, NODE_SUBTYPES); + out.endDocument(); + subtypesFile.finishWrite(fos); + } catch (java.io.IOException e) { + Slog.w(TAG, "Error writing subtypes", e); + if (fos != null) { + subtypesFile.failWrite(fos); + } + } + } + + private static void readAdditionalInputMethodSubtypes( + HashMap<String, List<InputMethodSubtype>> allSubtypes, AtomicFile subtypesFile) { + if (allSubtypes == null || subtypesFile == null) return; + allSubtypes.clear(); + FileInputStream fis = null; + try { + fis = subtypesFile.openRead(); + final XmlPullParser parser = Xml.newPullParser(); + parser.setInput(fis, null); + int type = parser.getEventType(); + // Skip parsing until START_TAG + while ((type = parser.next()) != XmlPullParser.START_TAG + && type != XmlPullParser.END_DOCUMENT) {} + String firstNodeName = parser.getName(); + if (!NODE_SUBTYPES.equals(firstNodeName)) { + throw new XmlPullParserException("Xml doesn't start with subtypes"); + } + final int depth =parser.getDepth(); + String currentImiId = null; + ArrayList<InputMethodSubtype> tempSubtypesArray = null; + while (((type = parser.next()) != XmlPullParser.END_TAG + || parser.getDepth() > depth) && type != XmlPullParser.END_DOCUMENT) { + if (type != XmlPullParser.START_TAG) + continue; + final String nodeName = parser.getName(); + if (NODE_IMI.equals(nodeName)) { + currentImiId = parser.getAttributeValue(null, ATTR_ID); + if (TextUtils.isEmpty(currentImiId)) { + Slog.w(TAG, "Invalid imi id found in subtypes.xml"); + continue; + } + tempSubtypesArray = new ArrayList<InputMethodSubtype>(); + allSubtypes.put(currentImiId, tempSubtypesArray); + } else if (NODE_SUBTYPE.equals(nodeName)) { + if (TextUtils.isEmpty(currentImiId) || tempSubtypesArray == null) { + Slog.w(TAG, "IME uninstalled or not valid.: " + currentImiId); + continue; + } + final int icon = Integer.valueOf( + parser.getAttributeValue(null, ATTR_ICON)); + final int label = Integer.valueOf( + parser.getAttributeValue(null, ATTR_LABEL)); + final String imeSubtypeLocale = + parser.getAttributeValue(null, ATTR_IME_SUBTYPE_LOCALE); + final String imeSubtypeMode = + parser.getAttributeValue(null, ATTR_IME_SUBTYPE_MODE); + final String imeSubtypeExtraValue = + parser.getAttributeValue(null, ATTR_IME_SUBTYPE_EXTRA_VALUE); + final boolean isAuxiliary = + Boolean.valueOf(parser.getAttributeValue(null, ATTR_IS_AUXILIARY)); + final InputMethodSubtype subtype = + new InputMethodSubtype(label, icon, imeSubtypeLocale, + imeSubtypeMode, imeSubtypeExtraValue, isAuxiliary); + tempSubtypesArray.add(subtype); + } + } + } catch (XmlPullParserException e) { + Slog.w(TAG, "Error reading subtypes: " + e); + return; + } catch (java.io.IOException e) { + Slog.w(TAG, "Error reading subtypes: " + e); + return; + } catch (NumberFormatException e) { + Slog.w(TAG, "Error reading subtypes: " + e); + return; + } finally { + if (fis != null) { + try { + fis.close(); + } catch (java.io.IOException e1) { + Slog.w(TAG, "Failed to close."); + } + } + } + } + } + // ---------------------------------------------------------------------- @Override diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java index 4e2501b460e7..cb55451f5494 100644 --- a/services/java/com/android/server/WifiService.java +++ b/services/java/com/android/server/WifiService.java @@ -84,7 +84,7 @@ import com.android.internal.R; public class WifiService extends IWifiManager.Stub { private static final String TAG = "WifiService"; - private static final boolean DBG = true; + private static final boolean DBG = false; private final WifiStateMachine mWifiStateMachine; diff --git a/services/java/com/android/server/WifiWatchdogService.java b/services/java/com/android/server/WifiWatchdogService.java index 6c7895e35b14..56bfbe00fb09 100644 --- a/services/java/com/android/server/WifiWatchdogService.java +++ b/services/java/com/android/server/WifiWatchdogService.java @@ -78,9 +78,9 @@ import java.util.Scanner; */ public class WifiWatchdogService { private static final String TAG = "WifiWatchdogService"; - private static final boolean V = false || false; - private static final boolean D = true || false; - + private static final boolean V = false; + private static final boolean D = true; + private Context mContext; private ContentResolver mContentResolver; private WifiManager mWifiManager; @@ -108,17 +108,16 @@ public class WifiWatchdogService { private String mSsid; /** * The number of access points in the current network ({@link #mSsid}) that - * have been checked. Only touched in the main thread! + * have been checked. Only touched in the main thread, using getter/setter methods. */ - private int mNumApsChecked; + private int mBssidCheckCount; /** Whether the current AP check should be canceled. */ private boolean mShouldCancel; - + WifiWatchdogService(Context context) { mContext = context; mContentResolver = context.getContentResolver(); mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); - createThread(); // The content observer to listen needs a handler, which createThread creates @@ -410,6 +409,9 @@ public class WifiWatchdogService { * Successful "ignored" pings are *not* ignored (they count in the total number * of pings), but failures are really ignored. */ + + // TODO: This is confusing logic and should be rewitten + // Here, successful 'ignored' pings are interpreted as a success in the below loop pingCounter++; successCounter++; } @@ -451,6 +453,7 @@ public class WifiWatchdogService { } } + //TODO: Integer division might cause problems down the road... int packetLossPercentage = 100 * (numPings - successCounter) / numPings; if (D) { Slog.d(TAG, packetLossPercentage @@ -470,7 +473,7 @@ public class WifiWatchdogService { return false; } - if (false && V) { + if (V) { myLogV("backgroundCheckDnsConnectivity: Background checking " + dns.getHostAddress() + " for connectivity"); } @@ -731,8 +734,8 @@ public class WifiWatchdogService { * Checks to make sure we haven't exceeded the max number of checks * we're allowed per network */ - mNumApsChecked++; - if (mNumApsChecked > getMaxApChecks()) { + incrementBssidCheckCount(); + if (getBssidCheckCount() > getMaxApChecks()) { if (V) { Slog.v(TAG, " Passed the max attempts (" + getMaxApChecks() + "), going to sleep for " + mSsid); @@ -823,7 +826,7 @@ public class WifiWatchdogService { // Reset the cancel state since this is the entry point of this action mShouldCancel = false; - if (false && V) { + if (V) { myLogV("handleBackgroundCheckAp: AccessPoint: " + ap); } @@ -962,7 +965,7 @@ public class WifiWatchdogService { if (forceIdleState || (mState != WatchdogState.SLEEP)) { mState = WatchdogState.IDLE; } - mNumApsChecked = 0; + resetBssidCheckCount(); } /** @@ -990,6 +993,18 @@ public class WifiWatchdogService { SWITCHING_AP } + private int getBssidCheckCount() { + return mBssidCheckCount; + } + + private void incrementBssidCheckCount() { + mBssidCheckCount++; + } + + private void resetBssidCheckCount() { + this.mBssidCheckCount = 0; + } + /** * The main thread for the watchdog monitoring. This will be turned into a * {@link Looper} thread. @@ -1120,6 +1135,9 @@ public class WifiWatchdogService { @Override public void handleMessage(Message msg) { + if (V) { + myLogV("handleMessage: " + msg.what); + } switch (msg.what) { case MESSAGE_NETWORK_CHANGED: handleNetworkChanged((String) msg.obj); @@ -1263,34 +1281,36 @@ public class WifiWatchdogService { /** * Describes an access point by its SSID and BSSID. + * */ private static class AccessPoint { String ssid; String bssid; + /** + * @param ssid cannot be null + * @param bssid cannot be null + */ AccessPoint(String ssid, String bssid) { + if (ssid == null || bssid == null) { + Slog.e(TAG, String.format("(%s) INVALID ACCESSPOINT: (%s, %s)", + Thread.currentThread().getName(),ssid,bssid)); + } this.ssid = ssid; this.bssid = bssid; } - - private boolean hasNull() { - return ssid == null || bssid == null; - } @Override public boolean equals(Object o) { if (!(o instanceof AccessPoint)) return false; AccessPoint otherAp = (AccessPoint) o; - boolean iHaveNull = hasNull(); + // Either we both have a null, or our SSIDs and BSSIDs are equal - return (iHaveNull && otherAp.hasNull()) || - (otherAp.bssid != null && ssid.equals(otherAp.ssid) - && bssid.equals(otherAp.bssid)); + return ssid.equals(otherAp.ssid) && bssid.equals(otherAp.bssid); } @Override public int hashCode() { - if (ssid == null || bssid == null) return 0; return ssid.hashCode() + bssid.hashCode(); } @@ -1365,7 +1385,7 @@ public class WifiWatchdogService { return false; } catch (Exception e) { - if (V || false) { + if (V) { Slog.d(TAG, "DnsPinger.isReachable got an unknown exception", e); } return false; diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index da9f1d6844b5..4f0265c6b432 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -1281,7 +1281,7 @@ public final class ActivityManagerService extends ActivityManagerNative mCompatModeDialog.dismiss(); mCompatModeDialog = null; } - if (ar != null) { + if (ar != null && false) { if (mCompatModePackages.getPackageAskCompatModeLocked( ar.packageName)) { int mode = mCompatModePackages.computeCompatModeLocked( diff --git a/services/java/com/android/server/net/NetworkIdentity.java b/services/java/com/android/server/net/NetworkIdentity.java index 79feb95f3463..f7a7c49730cf 100644 --- a/services/java/com/android/server/net/NetworkIdentity.java +++ b/services/java/com/android/server/net/NetworkIdentity.java @@ -66,7 +66,7 @@ public class NetworkIdentity { case VERSION_CURRENT: { type = in.readInt(); subType = in.readInt(); - subscriberId = in.readUTF(); + subscriberId = readOptionalString(in); break; } default: { @@ -79,7 +79,7 @@ public class NetworkIdentity { out.writeInt(VERSION_CURRENT); out.writeInt(type); out.writeInt(subType); - out.writeUTF(subscriberId); + writeOptionalString(out, subscriberId); } @Override @@ -205,4 +205,21 @@ public class NetworkIdentity { return new NetworkIdentity(type, subType, subscriberId); } + private static void writeOptionalString(DataOutputStream out, String value) throws IOException { + if (value != null) { + out.writeByte(1); + out.writeUTF(value); + } else { + out.writeByte(0); + } + } + + private static String readOptionalString(DataInputStream in) throws IOException { + if (in.readByte() != 0) { + return in.readUTF(); + } else { + return null; + } + } + } diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java index 3892de81319b..8db283947137 100644 --- a/services/java/com/android/server/net/NetworkStatsService.java +++ b/services/java/com/android/server/net/NetworkStatsService.java @@ -48,6 +48,7 @@ import android.net.NetworkInfo; import android.net.NetworkState; import android.net.NetworkStats; import android.net.NetworkStatsHistory; +import android.os.Environment; import android.os.Handler; import android.os.HandlerThread; import android.os.INetworkManagementService; @@ -60,15 +61,26 @@ import android.util.Slog; import android.util.SparseArray; import android.util.TrustedTime; +import com.android.internal.os.AtomicFile; import com.google.android.collect.Lists; import com.google.android.collect.Maps; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.File; import java.io.FileDescriptor; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; import java.io.PrintWriter; +import java.net.ProtocolException; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; +import libcore.io.IoUtils; + /** * Collect and persist detailed network statistics, and provide this data to * other system services. @@ -77,6 +89,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private static final String TAG = "NetworkStatsService"; private static final boolean LOGD = true; + /** File header magic number: "ANET" */ + private static final int FILE_MAGIC = 0x414E4554; + private static final int VERSION_CURRENT = 1; + private final Context mContext; private final INetworkManagementService mNetworkManager; private final IAlarmManager mAlarmManager; @@ -84,7 +100,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private IConnectivityManager mConnManager; - private static final String ACTION_NETWORK_STATS_POLL = + // @VisibleForTesting + public static final String ACTION_NETWORK_STATS_POLL = "com.android.server.action.NETWORK_STATS_POLL"; private PendingIntent mPollIntent; @@ -98,14 +115,15 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private LongSecureSetting mPollInterval = new LongSecureSetting( NETSTATS_POLL_INTERVAL, 15 * MINUTE_IN_MILLIS); private LongSecureSetting mPersistThreshold = new LongSecureSetting( - NETSTATS_PERSIST_THRESHOLD, 64 * KB_IN_BYTES); + NETSTATS_PERSIST_THRESHOLD, 16 * KB_IN_BYTES); + // TODO: adjust these timings for production builds private LongSecureSetting mSummaryBucketDuration = new LongSecureSetting( - NETSTATS_SUMMARY_BUCKET_DURATION, 6 * HOUR_IN_MILLIS); + NETSTATS_SUMMARY_BUCKET_DURATION, 1 * HOUR_IN_MILLIS); private LongSecureSetting mSummaryMaxHistory = new LongSecureSetting( NETSTATS_SUMMARY_MAX_HISTORY, 90 * DAY_IN_MILLIS); private LongSecureSetting mDetailBucketDuration = new LongSecureSetting( - NETSTATS_DETAIL_BUCKET_DURATION, 6 * HOUR_IN_MILLIS); + NETSTATS_DETAIL_BUCKET_DURATION, 2 * HOUR_IN_MILLIS); private LongSecureSetting mDetailMaxHistory = new LongSecureSetting( NETSTATS_DETAIL_MAX_HISTORY, 90 * DAY_IN_MILLIS); @@ -129,6 +147,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private final HandlerThread mHandlerThread; private final Handler mHandler; + private final AtomicFile mSummaryFile; + // TODO: collect detailed uid stats, storing tag-granularity data until next // dropbox, and uid summary for a specific bucket count. @@ -137,11 +157,15 @@ public class NetworkStatsService extends INetworkStatsService.Stub { public NetworkStatsService( Context context, INetworkManagementService networkManager, IAlarmManager alarmManager) { // TODO: move to using cached NtpTrustedTime - this(context, networkManager, alarmManager, new NtpTrustedTime()); + this(context, networkManager, alarmManager, new NtpTrustedTime(), getSystemDir()); + } + + private static File getSystemDir() { + return new File(Environment.getDataDirectory(), "system"); } public NetworkStatsService(Context context, INetworkManagementService networkManager, - IAlarmManager alarmManager, TrustedTime time) { + IAlarmManager alarmManager, TrustedTime time, File systemDir) { mContext = checkNotNull(context, "missing Context"); mNetworkManager = checkNotNull(networkManager, "missing INetworkManagementService"); mAlarmManager = checkNotNull(alarmManager, "missing IAlarmManager"); @@ -150,11 +174,15 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mHandlerThread = new HandlerThread(TAG); mHandlerThread.start(); mHandler = new Handler(mHandlerThread.getLooper()); + + mSummaryFile = new AtomicFile(new File(systemDir, "netstats.bin")); } public void systemReady() { - // read historical stats from disk - readStatsLocked(); + synchronized (mStatsLock) { + // read historical stats from disk + readStatsLocked(); + } // watch other system services that claim interfaces final IntentFilter ifaceFilter = new IntentFilter(); @@ -180,6 +208,16 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mConnManager = checkNotNull(connManager, "missing IConnectivityManager"); } + private void shutdownLocked() { + mContext.unregisterReceiver(mIfaceReceiver); + mContext.unregisterReceiver(mPollReceiver); + mContext.unregisterReceiver(mShutdownReceiver); + + writeStatsLocked(); + mSummaryStats.clear(); + mDetailStats.clear(); + } + /** * Clear any existing {@link #ACTION_NETWORK_STATS_POLL} alarms, and * reschedule based on current {@link #mPollInterval} value. @@ -227,7 +265,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } @Override - public NetworkStats getSummaryPerUid(long start, long end, int networkTemplate) { + public NetworkStats getSummaryForAllUid(long start, long end, int networkTemplate) { // TODO: create relaxed permission for reading stats mContext.enforceCallingOrSelfPermission(UPDATE_DEVICE_STATS, TAG); @@ -281,7 +319,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { public void onReceive(Context context, Intent intent) { // verified SHUTDOWN permission above. synchronized (mStatsLock) { - writeStatsLocked(); + shutdownLocked(); } } }; @@ -440,13 +478,74 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private void readStatsLocked() { if (LOGD) Slog.v(TAG, "readStatsLocked()"); - // TODO: read historical stats from disk using AtomicFile + + // clear any existing stats and read from disk + mSummaryStats.clear(); + + FileInputStream fis = null; + try { + fis = mSummaryFile.openRead(); + final DataInputStream in = new DataInputStream(fis); + + // verify file magic header intact + final int magic = in.readInt(); + if (magic != FILE_MAGIC) { + throw new ProtocolException("unexpected magic: " + magic); + } + + final int version = in.readInt(); + switch (version) { + case VERSION_CURRENT: { + // file format is pairs of interfaces and stats: + // summary := size *(InterfaceIdentity NetworkStatsHistory) + + final int size = in.readInt(); + for (int i = 0; i < size; i++) { + final InterfaceIdentity ident = new InterfaceIdentity(in); + final NetworkStatsHistory history = new NetworkStatsHistory(in); + mSummaryStats.put(ident, history); + } + break; + } + default: { + throw new ProtocolException("unexpected version: " + version); + } + } + } catch (FileNotFoundException e) { + // missing stats is okay, probably first boot + } catch (IOException e) { + Slog.e(TAG, "problem reading network stats", e); + } finally { + IoUtils.closeQuietly(fis); + } } private void writeStatsLocked() { if (LOGD) Slog.v(TAG, "writeStatsLocked()"); - // TODO: persist historical stats to disk using AtomicFile + // TODO: consider duplicating stats and releasing lock while writing + + FileOutputStream fos = null; + try { + fos = mSummaryFile.startWrite(); + final DataOutputStream out = new DataOutputStream(fos); + + out.writeInt(FILE_MAGIC); + out.writeInt(VERSION_CURRENT); + + out.writeInt(mSummaryStats.size()); + for (InterfaceIdentity ident : mSummaryStats.keySet()) { + final NetworkStatsHistory history = mSummaryStats.get(ident); + ident.writeToStream(out); + history.writeToStream(out); + } + + mSummaryFile.finishWrite(fos); + } catch (IOException e) { + if (fos != null) { + mSummaryFile.failWrite(fos); + } + } } @Override @@ -466,6 +565,12 @@ public class NetworkStatsService extends INetworkStatsService.Stub { return; } + if (argSet.contains("poll")) { + performPollLocked(); + pw.println("Forced poll"); + return; + } + pw.println("Active interfaces:"); for (String iface : mActiveIface.keySet()) { final InterfaceIdentity ident = mActiveIface.get(iface); @@ -545,7 +650,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { */ private static NetworkStats computeStatsDelta(NetworkStats before, NetworkStats current) { if (before != null) { - return current.subtract(before, false); + return current.subtractClamped(before); } else { return current; } diff --git a/services/java/com/android/server/wm/BlackFrame.java b/services/java/com/android/server/wm/BlackFrame.java index f9f575812643..d8fd7fe84a73 100644 --- a/services/java/com/android/server/wm/BlackFrame.java +++ b/services/java/com/android/server/wm/BlackFrame.java @@ -38,6 +38,9 @@ public class BlackFrame { top = t; surface = new Surface(session, 0, "BlackSurface", -1, w, h, PixelFormat.OPAQUE, Surface.FX_SURFACE_DIM); + if (WindowManagerService.SHOW_TRANSACTIONS || + WindowManagerService.SHOW_SURFACE_ALLOC) Slog.i(WindowManagerService.TAG, + " BLACK " + surface + ": CREATE layer=" + layer); surface.setAlpha(1.0f); surface.setLayer(layer); } @@ -104,6 +107,10 @@ public class BlackFrame { if (mBlackSurfaces != null) { for (int i=0; i<mBlackSurfaces.length; i++) { if (mBlackSurfaces[i] != null) { + if (WindowManagerService.SHOW_TRANSACTIONS || + WindowManagerService.SHOW_SURFACE_ALLOC) Slog.i( + WindowManagerService.TAG, + " BLACK " + mBlackSurfaces[i].surface + ": DESTROY"); mBlackSurfaces[i].surface.destroy(); mBlackSurfaces[i] = null; } diff --git a/services/java/com/android/server/wm/DimAnimator.java b/services/java/com/android/server/wm/DimAnimator.java index a266d70de7a9..a3293e8bbe87 100644 --- a/services/java/com/android/server/wm/DimAnimator.java +++ b/services/java/com/android/server/wm/DimAnimator.java @@ -41,8 +41,9 @@ class DimAnimator { DimAnimator (SurfaceSession session) { if (mDimSurface == null) { - if (WindowManagerService.SHOW_TRANSACTIONS) Slog.i(WindowManagerService.TAG, " DIM " - + mDimSurface + ": CREATE"); + if (WindowManagerService.SHOW_TRANSACTIONS || + WindowManagerService.SHOW_SURFACE_ALLOC) Slog.i(WindowManagerService.TAG, + " DIM " + mDimSurface + ": CREATE"); try { mDimSurface = new Surface(session, 0, "DimAnimator", diff --git a/services/java/com/android/server/wm/DimSurface.java b/services/java/com/android/server/wm/DimSurface.java index 220c7fb1c7f2..d7bb8b388d0d 100644 --- a/services/java/com/android/server/wm/DimSurface.java +++ b/services/java/com/android/server/wm/DimSurface.java @@ -32,8 +32,9 @@ class DimSurface { DimSurface(SurfaceSession session) { if (mDimSurface == null) { - if (WindowManagerService.SHOW_TRANSACTIONS) Slog.i(WindowManagerService.TAG, " DIM " - + mDimSurface + ": CREATE"); + if (WindowManagerService.SHOW_TRANSACTIONS || + WindowManagerService.SHOW_SURFACE_ALLOC) Slog.i(WindowManagerService.TAG, + " DIM " + mDimSurface + ": CREATE"); try { mDimSurface = new Surface(session, 0, "DimSurface", diff --git a/services/java/com/android/server/wm/ScreenRotationAnimation.java b/services/java/com/android/server/wm/ScreenRotationAnimation.java index b01ddd31be3d..847091843c52 100644 --- a/services/java/com/android/server/wm/ScreenRotationAnimation.java +++ b/services/java/com/android/server/wm/ScreenRotationAnimation.java @@ -102,6 +102,10 @@ class ScreenRotationAnimation { Slog.w(TAG, "Unable to allocate freeze surface", e); } + if (WindowManagerService.SHOW_TRANSACTIONS || + WindowManagerService.SHOW_SURFACE_ALLOC) Slog.i(WindowManagerService.TAG, + " FREEZE " + mSurface + ": CREATE"); + setRotation(display.getRotation()); if (mSurface != null) { @@ -284,6 +288,9 @@ class ScreenRotationAnimation { public void kill() { if (mSurface != null) { + if (WindowManagerService.SHOW_TRANSACTIONS || + WindowManagerService.SHOW_SURFACE_ALLOC) Slog.i(WindowManagerService.TAG, + " FREEZE " + mSurface + ": DESTROY"); mSurface.destroy(); mSurface = null; } diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java index 521e1d62fba3..1c87f5b4002d 100644 --- a/services/java/com/android/server/wm/WindowManagerService.java +++ b/services/java/com/android/server/wm/WindowManagerService.java @@ -19,6 +19,7 @@ package com.android.server.wm; import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW; import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW; import static android.view.WindowManager.LayoutParams.FLAG_BLUR_BEHIND; +import static android.view.WindowManager.LayoutParams.FLAG_COMPATIBLE_WINDOW; import static android.view.WindowManager.LayoutParams.FLAG_DIM_BEHIND; import static android.view.WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON; import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; @@ -160,6 +161,7 @@ public class WindowManagerService extends IWindowManager.Stub static final boolean DEBUG_REORDER = false; static final boolean DEBUG_WALLPAPER = false; static final boolean DEBUG_DRAG = false; + static final boolean SHOW_SURFACE_ALLOC = false; static final boolean SHOW_TRANSACTIONS = false; static final boolean HIDE_STACK_CRAWLS = true; @@ -462,6 +464,10 @@ public class WindowManagerService extends IWindowManager.Stub Display mDisplay; + final DisplayMetrics mDisplayMetrics = new DisplayMetrics(); + final DisplayMetrics mTmpDisplayMetrics = new DisplayMetrics(); + final DisplayMetrics mCompatDisplayMetrics = new DisplayMetrics(); + H mH = new H(); WindowState mCurrentFocus = null; @@ -2488,6 +2494,8 @@ public class WindowManagerService extends IWindowManager.Stub if (DEBUG_LAYOUT) Slog.v(TAG, "Relayout " + win + ": " + win.mAttrs); + win.mEnforceSizeCompat = (win.mAttrs.flags & FLAG_COMPATIBLE_WINDOW) != 0; + if ((attrChanges & WindowManager.LayoutParams.ALPHA_CHANGED) != 0) { win.mAlpha = attrs.alpha; } @@ -5057,7 +5065,7 @@ public class WindowManagerService extends IWindowManager.Stub mWaitingForConfig = true; mLayoutNeeded = true; startFreezingDisplayLocked(inTransaction); - Slog.i(TAG, "Setting rotation to " + rotation + ", animFlags=" + animFlags); + //Slog.i(TAG, "Setting rotation to " + rotation + ", animFlags=" + animFlags); mInputManager.setDisplayOrientation(0, rotation); if (mDisplayEnabled) { // NOTE: We disable the rotation in the emulator because @@ -5527,6 +5535,56 @@ public class WindowManagerService extends IWindowManager.Stub return curSize; } + private int computeSmallestWidth(boolean rotated, int dw, int dh, float density) { + // We need to determine the smallest width that will occur under normal + // operation. To this, start with the base screen size and compute the + // width under the different possible rotations. We need to un-rotate + // the current screen dimensions before doing this. + int unrotDw, unrotDh; + if (rotated) { + unrotDw = dh; + unrotDh = dw; + } else { + unrotDw = dw; + unrotDh = dh; + } + int sw = reduceConfigWidthSize(unrotDw, Surface.ROTATION_0, density, unrotDw); + sw = reduceConfigWidthSize(sw, Surface.ROTATION_90, density, unrotDh); + sw = reduceConfigWidthSize(sw, Surface.ROTATION_180, density, unrotDw); + sw = reduceConfigWidthSize(sw, Surface.ROTATION_270, density, unrotDh); + return sw; + } + + private int reduceCompatConfigWidthSize(int curSize, int rotation, DisplayMetrics dm, + int dw, int dh) { + dm.unscaledWidthPixels = mPolicy.getNonDecorDisplayWidth(rotation, dw); + dm.unscaledHeightPixels = mPolicy.getNonDecorDisplayHeight(rotation, dh); + float scale = CompatibilityInfo.computeCompatibleScaling(dm, null); + int size = (int)(((dm.unscaledWidthPixels / scale) / dm.density) + .5f); + if (curSize == 0 || size < curSize) { + curSize = size; + } + return curSize; + } + + private int computeCompatSmallestWidth(boolean rotated, DisplayMetrics dm, int dw, int dh) { + mTmpDisplayMetrics.setTo(dm); + dm = mTmpDisplayMetrics; + int unrotDw, unrotDh; + if (rotated) { + unrotDw = dh; + unrotDh = dw; + } else { + unrotDw = dw; + unrotDh = dh; + } + int sw = reduceCompatConfigWidthSize(0, Surface.ROTATION_0, dm, unrotDw, unrotDh); + sw = reduceCompatConfigWidthSize(sw, Surface.ROTATION_90, dm, unrotDh, unrotDw); + sw = reduceCompatConfigWidthSize(sw, Surface.ROTATION_180, dm, unrotDw, unrotDh); + sw = reduceCompatConfigWidthSize(sw, Surface.ROTATION_270, dm, unrotDh, unrotDw); + return sw; + } + boolean computeNewConfigurationLocked(Configuration config) { if (mDisplay == null) { return false; @@ -5572,7 +5630,7 @@ public class WindowManagerService extends IWindowManager.Stub } config.orientation = orientation; - DisplayMetrics dm = new DisplayMetrics(); + DisplayMetrics dm = mDisplayMetrics; mDisplay.getRealMetrics(dm); // Override display width and height with what we are computing, @@ -5582,10 +5640,16 @@ public class WindowManagerService extends IWindowManager.Stub dm.heightPixels = dm.unscaledHeightPixels = mAppDisplayHeight = mPolicy.getNonDecorDisplayHeight(mRotation, dh); - mCompatibleScreenScale = CompatibilityInfo.computeCompatibleScaling(dm, null); + mCompatibleScreenScale = CompatibilityInfo.computeCompatibleScaling(dm, + mCompatDisplayMetrics); config.screenWidthDp = (int)(mPolicy.getConfigDisplayWidth(mRotation, dw) / dm.density); config.screenHeightDp = (int)(mPolicy.getConfigDisplayHeight(mRotation, dh) / dm.density); + config.smallestScreenWidthDp = computeSmallestWidth(rotated, dw, dh, dm.density); + + config.compatScreenWidthDp = (int)(config.screenWidthDp / mCompatibleScreenScale); + config.compatScreenHeightDp = (int)(config.screenHeightDp / mCompatibleScreenScale); + config.compatSmallestScreenWidthDp = computeCompatSmallestWidth(rotated, dm, dw, dh); // We need to determine the smallest width that will occur under normal // operation. To this, start with the base screen size and compute the @@ -8061,7 +8125,7 @@ public class WindowManagerService extends IWindowManager.Stub if (mDimAnimator == null) { mDimAnimator = new DimAnimator(mFxSession); } - mDimAnimator.show(dw, dh); + mDimAnimator.show(innerDw, innerDh); mDimAnimator.updateParameters(mContext.getResources(), w, currentTime); } @@ -8451,7 +8515,8 @@ public class WindowManagerService extends IWindowManager.Stub // surface and ask the app to request another one. Slog.w(TAG, "Looks like we have reclaimed some memory, clearing surface for retry."); if (surface != null) { - if (SHOW_TRANSACTIONS) logSurface(win, "RECOVER DESTROY", null); + if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) logSurface(win, + "RECOVER DESTROY", null); surface.destroy(); win.mSurfaceShown = false; win.mSurface = null; diff --git a/services/java/com/android/server/wm/WindowState.java b/services/java/com/android/server/wm/WindowState.java index 144341ba391e..587685e624ff 100644 --- a/services/java/com/android/server/wm/WindowState.java +++ b/services/java/com/android/server/wm/WindowState.java @@ -54,6 +54,10 @@ import java.util.ArrayList; * A window in the window manager. */ final class WindowState implements WindowManagerPolicy.WindowState { + static final boolean DEBUG_VISIBILITY = WindowManagerService.DEBUG_VISIBILITY; + static final boolean SHOW_TRANSACTIONS = WindowManagerService.SHOW_TRANSACTIONS; + static final boolean SHOW_SURFACE_ALLOC = WindowManagerService.SHOW_SURFACE_ALLOC; + final WindowManagerService mService; final Session mSession; final IWindow mClient; @@ -71,7 +75,7 @@ final class WindowState implements WindowManagerPolicy.WindowState { final boolean mIsImWindow; final boolean mIsWallpaper; final boolean mIsFloatingLayer; - final boolean mEnforceSizeCompat; + boolean mEnforceSizeCompat; int mViewVisibility; boolean mPolicyVisibility = true; boolean mPolicyVisibilityAfterAnim = true; @@ -600,7 +604,7 @@ final class WindowState implements WindowManagerPolicy.WindowState { if ((mAttrs.flags&WindowManager.LayoutParams.FLAG_SECURE) != 0) { flags |= Surface.SECURE; } - if (WindowManagerService.DEBUG_VISIBILITY) Slog.v( + if (DEBUG_VISIBILITY) Slog.v( WindowManagerService.TAG, "Creating surface in session " + mSession.mSurfaceSession + " window " + this + " w=" + mCompatFrame.width() @@ -639,7 +643,8 @@ final class WindowState implements WindowManagerPolicy.WindowState { mSession.mSurfaceSession, mSession.mPid, mAttrs.getTitle().toString(), 0, w, h, format, flags); - if (WindowManagerService.SHOW_TRANSACTIONS) Slog.i(WindowManagerService.TAG, " CREATE SURFACE " + if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) Slog.i(WindowManagerService.TAG, + " CREATE SURFACE " + mSurface + " IN SESSION " + mSession.mSurfaceSession + ": pid=" + mSession.mPid + " format=" @@ -659,7 +664,7 @@ final class WindowState implements WindowManagerPolicy.WindowState { WindowManagerService.TAG, "Got surface: " + mSurface + ", set left=" + mFrame.left + " top=" + mFrame.top + ", animLayer=" + mAnimLayer); - if (WindowManagerService.SHOW_TRANSACTIONS) { + if (SHOW_TRANSACTIONS) { Slog.i(WindowManagerService.TAG, ">>> OPEN TRANSACTION createSurfaceLocked"); WindowManagerService.logSurface(this, "CREATE pos=(" + mFrame.left + "," + mFrame.top + ") (" + @@ -677,7 +682,7 @@ final class WindowState implements WindowManagerPolicy.WindowState { mSurfaceShown = false; mSurface.hide(); if ((mAttrs.flags&WindowManager.LayoutParams.FLAG_DITHER) != 0) { - if (WindowManagerService.SHOW_TRANSACTIONS) WindowManagerService.logSurface(this, "DITHER", null); + if (SHOW_TRANSACTIONS) WindowManagerService.logSurface(this, "DITHER", null); mSurface.setFlags(Surface.SURFACE_DITHER, Surface.SURFACE_DITHER); } @@ -688,7 +693,7 @@ final class WindowState implements WindowManagerPolicy.WindowState { mLastHidden = true; } finally { Surface.closeTransaction(); - if (WindowManagerService.SHOW_TRANSACTIONS) Slog.i(WindowManagerService.TAG, "<<< CLOSE TRANSACTION createSurfaceLocked"); + if (SHOW_TRANSACTIONS) Slog.i(WindowManagerService.TAG, "<<< CLOSE TRANSACTION createSurfaceLocked"); } if (WindowManagerService.localLOGV) Slog.v( WindowManagerService.TAG, "Created surface " + this); @@ -725,7 +730,7 @@ final class WindowState implements WindowManagerPolicy.WindowState { } try { - if (WindowManagerService.DEBUG_VISIBILITY) { + if (DEBUG_VISIBILITY) { RuntimeException e = null; if (!WindowManagerService.HIDE_STACK_CRAWLS) { e = new RuntimeException(); @@ -734,13 +739,13 @@ final class WindowState implements WindowManagerPolicy.WindowState { Slog.w(WindowManagerService.TAG, "Window " + this + " destroying surface " + mSurface + ", session " + mSession, e); } - if (WindowManagerService.SHOW_TRANSACTIONS) { + if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) { RuntimeException e = null; if (!WindowManagerService.HIDE_STACK_CRAWLS) { e = new RuntimeException(); e.fillInStackTrace(); } - if (WindowManagerService.SHOW_TRANSACTIONS) WindowManagerService.logSurface(this, "DESTROY", e); + WindowManagerService.logSurface(this, "DESTROY", e); } mSurface.destroy(); } catch (RuntimeException e) { @@ -756,7 +761,7 @@ final class WindowState implements WindowManagerPolicy.WindowState { boolean finishDrawingLocked() { if (mDrawPending) { - if (WindowManagerService.SHOW_TRANSACTIONS || WindowManagerService.DEBUG_ORIENTATION) Slog.v( + if (SHOW_TRANSACTIONS || WindowManagerService.DEBUG_ORIENTATION) Slog.v( WindowManagerService.TAG, "finishDrawingLocked: " + mSurface); mCommitDrawPending = true; mDrawPending = false; @@ -783,7 +788,7 @@ final class WindowState implements WindowManagerPolicy.WindowState { // This must be called while inside a transaction. boolean performShowLocked() { - if (WindowManagerService.DEBUG_VISIBILITY) { + if (DEBUG_VISIBILITY) { RuntimeException e = null; if (!WindowManagerService.HIDE_STACK_CRAWLS) { e = new RuntimeException(); @@ -794,9 +799,9 @@ final class WindowState implements WindowManagerPolicy.WindowState { + " starting=" + (mAttrs.type == TYPE_APPLICATION_STARTING), e); } if (mReadyToShow && isReadyForDisplay()) { - if (WindowManagerService.SHOW_TRANSACTIONS || WindowManagerService.DEBUG_ORIENTATION) WindowManagerService.logSurface(this, + if (SHOW_TRANSACTIONS || WindowManagerService.DEBUG_ORIENTATION) WindowManagerService.logSurface(this, "SHOW (performShowLocked)", null); - if (WindowManagerService.DEBUG_VISIBILITY) Slog.v(WindowManagerService.TAG, "Showing " + this + if (DEBUG_VISIBILITY) Slog.v(WindowManagerService.TAG, "Showing " + this + " during animation: policyVis=" + mPolicyVisibility + " attHidden=" + mAttachedHidden + " tok.hiddenRequested=" @@ -958,7 +963,7 @@ final class WindowState implements WindowManagerPolicy.WindowState { mHasTransformation = false; mHasLocalTransformation = false; if (mPolicyVisibility != mPolicyVisibilityAfterAnim) { - if (WindowManagerService.DEBUG_VISIBILITY) { + if (DEBUG_VISIBILITY) { Slog.v(WindowManagerService.TAG, "Policy visibility changing after anim in " + this + ": " + mPolicyVisibilityAfterAnim); } @@ -1020,7 +1025,7 @@ final class WindowState implements WindowManagerPolicy.WindowState { if (mSurface != null) { mService.mDestroySurface.add(this); mDestroying = true; - if (WindowManagerService.SHOW_TRANSACTIONS) WindowManagerService.logSurface(this, "HIDE (finishExit)", null); + if (SHOW_TRANSACTIONS) WindowManagerService.logSurface(this, "HIDE (finishExit)", null); mSurfaceShown = false; try { mSurface.hide(); @@ -1414,9 +1419,9 @@ final class WindowState implements WindowManagerPolicy.WindowState { if (mPolicyVisibility && mPolicyVisibilityAfterAnim) { return false; } - if (WindowManagerService.DEBUG_VISIBILITY) Slog.v(WindowManagerService.TAG, "Policy visibility true: " + this); + if (DEBUG_VISIBILITY) Slog.v(WindowManagerService.TAG, "Policy visibility true: " + this); if (doAnimation) { - if (WindowManagerService.DEBUG_VISIBILITY) Slog.v(WindowManagerService.TAG, "doAnimation: mPolicyVisibility=" + if (DEBUG_VISIBILITY) Slog.v(WindowManagerService.TAG, "doAnimation: mPolicyVisibility=" + mPolicyVisibility + " mAnimation=" + mAnimation); if (mService.mDisplayFrozen || !mService.mPolicy.isScreenOn()) { doAnimation = false; @@ -1462,7 +1467,7 @@ final class WindowState implements WindowManagerPolicy.WindowState { if (doAnimation) { mPolicyVisibilityAfterAnim = false; } else { - if (WindowManagerService.DEBUG_VISIBILITY) Slog.v(WindowManagerService.TAG, "Policy visibility false: " + this); + if (DEBUG_VISIBILITY) Slog.v(WindowManagerService.TAG, "Policy visibility false: " + this); mPolicyVisibilityAfterAnim = false; mPolicyVisibility = false; // Window is no longer visible -- make sure if we were waiting diff --git a/services/jni/com_android_server_UsbHostManager.cpp b/services/jni/com_android_server_UsbHostManager.cpp index 9506d75dbcab..f1abf5605143 100644 --- a/services/jni/com_android_server_UsbHostManager.cpp +++ b/services/jni/com_android_server_UsbHostManager.cpp @@ -125,7 +125,7 @@ static int usb_device_removed(const char *devname, void* client_data) { jobject thiz = (jobject)client_data; jstring deviceName = env->NewStringUTF(devname); - env->CallVoidMethod(thiz, method_usbDeviceRemoved, env->NewStringUTF(devname)); + env->CallVoidMethod(thiz, method_usbDeviceRemoved, deviceName); env->DeleteLocalRef(deviceName); checkAndClearExceptionFromCallback(env, __FUNCTION__); return 0; diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp index d1b10f799c1b..0ae79294f9a7 100644 --- a/services/sensorservice/SensorService.cpp +++ b/services/sensorservice/SensorService.cpp @@ -52,7 +52,6 @@ namespace android { * Notes: * * - what about a gyro-corrected magnetic-field sensor? - * - option to "hide" the HAL sensors * - run mag sensor from time to time to force calibration * - gravity sensor length is wrong (=> drift in linear-acc sensor) * @@ -71,6 +70,7 @@ void SensorService::onFirstRef() SensorDevice& dev(SensorDevice::getInstance()); if (dev.initCheck() == NO_ERROR) { + ssize_t orientationIndex = -1; bool hasGyro = false; uint32_t virtualSensorsNeeds = (1<<SENSOR_TYPE_GRAVITY) | @@ -82,6 +82,9 @@ void SensorService::onFirstRef() for (int i=0 ; i<count ; i++) { registerSensor( new HardwareSensor(list[i]) ); switch (list[i].type) { + case SENSOR_TYPE_ORIENTATION: + orientationIndex = i; + break; case SENSOR_TYPE_GYROSCOPE: hasGyro = true; break; @@ -120,6 +123,18 @@ void SensorService::onFirstRef() } } + // build the sensor list returned to users + mUserSensorList = mSensorList; + if (hasGyro && + (virtualSensorsNeeds & (1<<SENSOR_TYPE_ROTATION_VECTOR))) { + // if we have the fancy sensor fusion, and it's not provided by the + // HAL, use our own (fused) orientation sensor by removing the + // HAL supplied one form the user list. + if (orientationIndex >= 0) { + mUserSensorList.removeItemsAt(orientationIndex); + } + } + run("SensorService", PRIORITY_URGENT_DISPLAY); mInitCheck = NO_ERROR; } @@ -315,9 +330,9 @@ SensorService::getActiveVirtualSensors() const } String8 SensorService::getSensorName(int handle) const { - size_t count = mSensorList.size(); + size_t count = mUserSensorList.size(); for (size_t i=0 ; i<count ; i++) { - const Sensor& sensor(mSensorList[i]); + const Sensor& sensor(mUserSensorList[i]); if (sensor.getHandle() == handle) { return sensor.getName(); } @@ -328,7 +343,7 @@ String8 SensorService::getSensorName(int handle) const { Vector<Sensor> SensorService::getSensorList() { - return mSensorList; + return mUserSensorList; } sp<ISensorEventConnection> SensorService::createSensorEventConnection() diff --git a/services/sensorservice/SensorService.h b/services/sensorservice/SensorService.h index 77a7e34e8510..4d0f1d9d9c5d 100644 --- a/services/sensorservice/SensorService.h +++ b/services/sensorservice/SensorService.h @@ -114,6 +114,7 @@ class SensorService : // constants Vector<Sensor> mSensorList; + Vector<Sensor> mUserSensorList; DefaultKeyedVector<int, SensorInterface*> mSensorMap; Vector<SensorInterface *> mVirtualSensorList; Permission mDump; diff --git a/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java new file mode 100644 index 000000000000..98463721b501 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java @@ -0,0 +1,280 @@ +/* + * 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.server; + +import static android.net.ConnectivityManager.CONNECTIVITY_ACTION; +import static android.net.ConnectivityManager.TYPE_WIFI; +import static android.net.NetworkStats.UID_ALL; +import static android.net.TrafficStats.TEMPLATE_WIFI; +import static android.text.format.DateUtils.DAY_IN_MILLIS; +import static android.text.format.DateUtils.HOUR_IN_MILLIS; +import static com.android.server.net.NetworkStatsService.ACTION_NETWORK_STATS_POLL; +import static org.easymock.EasyMock.anyLong; +import static org.easymock.EasyMock.createMock; +import static org.easymock.EasyMock.eq; +import static org.easymock.EasyMock.expect; +import static org.easymock.EasyMock.expectLastCall; +import static org.easymock.EasyMock.isA; + +import android.app.AlarmManager; +import android.app.IAlarmManager; +import android.app.PendingIntent; +import android.content.Intent; +import android.net.IConnectivityManager; +import android.net.LinkProperties; +import android.net.NetworkInfo; +import android.net.NetworkInfo.DetailedState; +import android.net.NetworkState; +import android.net.NetworkStats; +import android.net.NetworkStatsHistory; +import android.os.INetworkManagementService; +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.LargeTest; +import android.util.TrustedTime; + +import com.android.server.net.NetworkStatsService; + +import org.easymock.EasyMock; + +import java.io.File; + +/** + * Tests for {@link NetworkStatsService}. + */ +@LargeTest +public class NetworkStatsServiceTest extends AndroidTestCase { + private static final String TAG = "NetworkStatsServiceTest"; + + private static final String TEST_IFACE = "test0"; + private static final long TEST_START = 1194220800000L; + + private BroadcastInterceptingContext mServiceContext; + private File mStatsDir; + + private INetworkManagementService mNetManager; + private IAlarmManager mAlarmManager; + private TrustedTime mTime; + private IConnectivityManager mConnManager; + + private NetworkStatsService mService; + + @Override + public void setUp() throws Exception { + super.setUp(); + + mServiceContext = new BroadcastInterceptingContext(getContext()); + mStatsDir = getContext().getFilesDir(); + + mNetManager = createMock(INetworkManagementService.class); + mAlarmManager = createMock(IAlarmManager.class); + mTime = createMock(TrustedTime.class); + mConnManager = createMock(IConnectivityManager.class); + + mService = new NetworkStatsService( + mServiceContext, mNetManager, mAlarmManager, mTime, mStatsDir); + mService.bindConnectivityManager(mConnManager); + + expectSystemReady(); + + replay(); + mService.systemReady(); + verifyAndReset(); + + } + + @Override + public void tearDown() throws Exception { + for (File file : mStatsDir.listFiles()) { + file.delete(); + } + + mServiceContext = null; + mStatsDir = null; + + mNetManager = null; + mAlarmManager = null; + mTime = null; + + mService = null; + + super.tearDown(); + } + + private static NetworkState buildWifi() { + final NetworkInfo info = new NetworkInfo(TYPE_WIFI, 0, null, null); + info.setDetailedState(DetailedState.CONNECTED, null, null); + final LinkProperties prop = new LinkProperties(); + prop.setInterfaceName(TEST_IFACE); + return new NetworkState(info, prop, null); + } + + public void testHistoryForWifi() throws Exception { + long elapsedRealtime = 0; + NetworkState[] state = null; + NetworkStats stats = null; + NetworkStats detail = null; + + // pretend that wifi network comes online; service should ask about full + // network state, and poll any existing interfaces before updating. + state = new NetworkState[] { buildWifi() }; + stats = new NetworkStats.Builder(elapsedRealtime, 0).build(); + detail = new NetworkStats.Builder(elapsedRealtime, 0).build(); + + expect(mConnManager.getAllNetworkState()).andReturn(state).atLeastOnce(); + expect(mNetManager.getNetworkStatsSummary()).andReturn(stats).atLeastOnce(); + expect(mNetManager.getNetworkStatsDetail()).andReturn(detail).atLeastOnce(); + expectTime(TEST_START + elapsedRealtime); + + replay(); + mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION)); + verifyAndReset(); + + // verify service has empty history for wifi + assertNetworkTotal(TEMPLATE_WIFI, 0L, 0L); + + // modify some number on wifi, and trigger poll event + elapsedRealtime += HOUR_IN_MILLIS; + stats = new NetworkStats.Builder(elapsedRealtime, 1).addEntry( + TEST_IFACE, UID_ALL, 1024L, 2048L).build(); + + expect(mNetManager.getNetworkStatsSummary()).andReturn(stats).atLeastOnce(); + expect(mNetManager.getNetworkStatsDetail()).andReturn(detail).atLeastOnce(); + expectTime(TEST_START + elapsedRealtime); + + replay(); + mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL)); + verifyAndReset(); + + // verify service recorded history + assertNetworkTotal(TEMPLATE_WIFI, 1024L, 2048L); + + // and bump forward again, with counters going higher. this is + // important, since polling should correctly subtract last snapshot. + elapsedRealtime += DAY_IN_MILLIS; + stats = new NetworkStats.Builder(elapsedRealtime, 1).addEntry( + TEST_IFACE, UID_ALL, 4096L, 8192L).build(); + + expect(mNetManager.getNetworkStatsSummary()).andReturn(stats).atLeastOnce(); + expect(mNetManager.getNetworkStatsDetail()).andReturn(detail).atLeastOnce(); + expectTime(TEST_START + elapsedRealtime); + + replay(); + mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL)); + verifyAndReset(); + + // verify service recorded history + assertNetworkTotal(TEMPLATE_WIFI, 4096L, 8192L); + } + + public void testHistoryForRebootPersist() throws Exception { + long elapsedRealtime = 0; + NetworkState[] state = null; + NetworkStats stats = null; + NetworkStats detail = null; + + // assert that no stats file exists + final File statsFile = new File(mStatsDir, "netstats.bin"); + assertFalse(statsFile.exists()); + + // pretend that wifi network comes online; service should ask about full + // network state, and poll any existing interfaces before updating. + state = new NetworkState[] { buildWifi() }; + stats = new NetworkStats.Builder(elapsedRealtime, 0).build(); + detail = new NetworkStats.Builder(elapsedRealtime, 0).build(); + + expect(mConnManager.getAllNetworkState()).andReturn(state).atLeastOnce(); + expect(mNetManager.getNetworkStatsSummary()).andReturn(stats).atLeastOnce(); + expect(mNetManager.getNetworkStatsDetail()).andReturn(detail).atLeastOnce(); + expectTime(TEST_START + elapsedRealtime); + + replay(); + mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION)); + verifyAndReset(); + + // verify service has empty history for wifi + assertNetworkTotal(TEMPLATE_WIFI, 0L, 0L); + + // modify some number on wifi, and trigger poll event + elapsedRealtime += HOUR_IN_MILLIS; + stats = new NetworkStats.Builder(elapsedRealtime, 1).addEntry( + TEST_IFACE, UID_ALL, 1024L, 2048L).build(); + + expect(mNetManager.getNetworkStatsSummary()).andReturn(stats).atLeastOnce(); + expect(mNetManager.getNetworkStatsDetail()).andReturn(detail).atLeastOnce(); + expectTime(TEST_START + elapsedRealtime); + + replay(); + mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL)); + verifyAndReset(); + + // verify service recorded history + assertNetworkTotal(TEMPLATE_WIFI, 1024L, 2048L); + + // graceful shutdown system, which should trigger persist of stats, and + // clear any values in memory. + mServiceContext.sendBroadcast(new Intent(Intent.ACTION_SHUTDOWN)); + + // talk with zombie service to assert stats have gone; and assert that + // we persisted them to file. + assertNetworkTotal(TEMPLATE_WIFI, 0L, 0L); + assertTrue(statsFile.exists()); + + // boot through serviceReady() again + expectSystemReady(); + + replay(); + mService.systemReady(); + verifyAndReset(); + + // after systemReady(), we should have historical stats loaded again + assertNetworkTotal(TEMPLATE_WIFI, 1024L, 2048L); + + } + + private void assertNetworkTotal(int template, long rx, long tx) { + final NetworkStatsHistory history = mService.getHistoryForNetwork(template); + final long[] total = history.getTotalData(Long.MIN_VALUE, Long.MAX_VALUE, null); + assertEquals(rx, total[0]); + assertEquals(tx, total[1]); + } + + private void expectSystemReady() throws Exception { + mAlarmManager.remove(isA(PendingIntent.class)); + expectLastCall().anyTimes(); + + mAlarmManager.setInexactRepeating( + eq(AlarmManager.ELAPSED_REALTIME), anyLong(), anyLong(), isA(PendingIntent.class)); + expectLastCall().atLeastOnce(); + } + + public void expectTime(long currentTime) throws Exception { + expect(mTime.forceRefresh()).andReturn(false).anyTimes(); + expect(mTime.hasCache()).andReturn(true).anyTimes(); + expect(mTime.currentTimeMillis()).andReturn(currentTime).anyTimes(); + expect(mTime.getCacheAge()).andReturn(0L).anyTimes(); + expect(mTime.getCacheCertainty()).andReturn(0L).anyTimes(); + } + + private void replay() { + EasyMock.replay(mNetManager, mAlarmManager, mTime, mConnManager); + } + + private void verifyAndReset() { + EasyMock.verify(mNetManager, mAlarmManager, mTime, mConnManager); + EasyMock.reset(mNetManager, mAlarmManager, mTime, mConnManager); + } +} diff --git a/telephony/java/android/telephony/SmsCbConstants.java b/telephony/java/android/telephony/SmsCbConstants.java new file mode 100644 index 000000000000..a1b4adf19baf --- /dev/null +++ b/telephony/java/android/telephony/SmsCbConstants.java @@ -0,0 +1,117 @@ +/* + * 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 android.telephony; + +/** + * Constants used in SMS Cell Broadcast messages. + * + * {@hide} + */ +public interface SmsCbConstants { + /** Start of PWS Message Identifier range (includes ETWS and CMAS). */ + public static final int MESSAGE_ID_PWS_FIRST_IDENTIFIER = 0x1100; + + /** Bitmask for messages of ETWS type (including future extensions). */ + public static final int MESSAGE_ID_ETWS_TYPE_MASK = 0xFFF8; + + /** Value for messages of ETWS type after applying {@link #MESSAGE_ID_ETWS_TYPE_MASK}. */ + public static final int MESSAGE_ID_ETWS_TYPE = 0x1100; + + /** ETWS Message Identifier for earthquake warning message. */ + public static final int MESSAGE_ID_ETWS_EARTHQUAKE_WARNING = 0x1100; + + /** ETWS Message Identifier for tsunami warning message. */ + public static final int MESSAGE_ID_ETWS_TSUNAMI_WARNING = 0x1101; + + /** ETWS Message Identifier for earthquake and tsunami combined warning message. */ + public static final int MESSAGE_ID_ETWS_EARTHQUAKE_AND_TSUNAMI_WARNING = 0x1102; + + /** ETWS Message Identifier for test message. */ + public static final int MESSAGE_ID_ETWS_TEST_MESSAGE = 0x1103; + + /** ETWS Message Identifier for messages related to other emergency types. */ + public static final int MESSAGE_ID_ETWS_OTHER_EMERGENCY_TYPE = 0x1104; + + /** Start of CMAS Message Identifier range. */ + public static final int MESSAGE_ID_CMAS_FIRST_IDENTIFIER = 0x1112; + + /** CMAS Message Identifier for Presidential Level alerts. */ + public static final int MESSAGE_ID_CMAS_ALERT_PRESIDENTIAL_LEVEL = 0x1112; + + /** CMAS Message Identifier for Extreme alerts, Urgency=Immediate, Certainty=Observed. */ + public static final int MESSAGE_ID_CMAS_ALERT_EXTREME_IMMEDIATE_OBSERVED = 0x1113; + + /** CMAS Message Identifier for Extreme alerts, Urgency=Immediate, Certainty=Likely. */ + public static final int MESSAGE_ID_CMAS_ALERT_EXTREME_IMMEDIATE_LIKELY = 0x1114; + + /** CMAS Message Identifier for Extreme alerts, Urgency=Expected, Certainty=Observed. */ + public static final int MESSAGE_ID_CMAS_ALERT_EXTREME_EXPECTED_OBSERVED = 0x1115; + + /** CMAS Message Identifier for Extreme alerts, Urgency=Expected, Certainty=Likely. */ + public static final int MESSAGE_ID_CMAS_ALERT_EXTREME_EXPECTED_LIKELY = 0x1116; + + /** CMAS Message Identifier for Severe alerts, Urgency=Immediate, Certainty=Observed. */ + public static final int MESSAGE_ID_CMAS_ALERT_SEVERE_IMMEDIATE_OBSERVED = 0x1117; + + /** CMAS Message Identifier for Severe alerts, Urgency=Immediate, Certainty=Likely. */ + public static final int MESSAGE_ID_CMAS_ALERT_SEVERE_IMMEDIATE_LIKELY = 0x1118; + + /** CMAS Message Identifier for Severe alerts, Urgency=Expected, Certainty=Observed. */ + public static final int MESSAGE_ID_CMAS_ALERT_SEVERE_EXPECTED_OBSERVED = 0x1119; + + /** CMAS Message Identifier for Severe alerts, Urgency=Expected, Certainty=Likely. */ + public static final int MESSAGE_ID_CMAS_ALERT_SEVERE_EXPECTED_LIKELY = 0x111A; + + /** CMAS Message Identifier for Child Abduction Emergency (Amber Alert). */ + public static final int MESSAGE_ID_CMAS_ALERT_CHILD_ABDUCTION_EMERGENCY = 0x111B; + + /** CMAS Message Identifier for the Required Monthly Test. */ + public static final int MESSAGE_ID_CMAS_ALERT_REQUIRED_MONTHLY_TEST = 0x111C; + + /** CMAS Message Identifier for CMAS Exercise. */ + public static final int MESSAGE_ID_CMAS_ALERT_EXERCISE = 0x111D; + + /** CMAS Message Identifier for operator defined use. */ + public static final int MESSAGE_ID_CMAS_ALERT_OPERATOR_DEFINED_USE = 0x111E; + + /** End of CMAS Message Identifier range (including future extensions). */ + public static final int MESSAGE_ID_CMAS_LAST_IDENTIFIER = 0x112F; + + /** End of PWS Message Identifier range (includes ETWS, CMAS, and future extensions). */ + public static final int MESSAGE_ID_PWS_LAST_IDENTIFIER = 0x18FF; + + /** ETWS message code flag to activate the popup display. */ + public static final int MESSAGE_CODE_ETWS_ACTIVATE_POPUP = 0x100; + + /** ETWS message code flag to activate the emergency user alert. */ + public static final int MESSAGE_CODE_ETWS_EMERGENCY_USER_ALERT = 0x200; + + /** ETWS warning type value for earthquake. */ + public static final int ETWS_WARNING_TYPE_EARTHQUAKE = 0x00; + + /** ETWS warning type value for tsunami. */ + public static final int ETWS_WARNING_TYPE_TSUNAMI = 0x01; + + /** ETWS warning type value for earthquake and tsunami. */ + public static final int ETWS_WARNING_TYPE_EARTHQUAKE_AND_TSUNAMI = 0x02; + + /** ETWS warning type value for test broadcast. */ + public static final int ETWS_WARNING_TYPE_TEST = 0x03; + + /** ETWS warning type value for other notifications. */ + public static final int ETWS_WARNING_TYPE_OTHER = 0x04; +} diff --git a/telephony/java/android/telephony/SmsCbMessage.java b/telephony/java/android/telephony/SmsCbMessage.java index 5608402b5f3e..383e0f9c90c4 100644 --- a/telephony/java/android/telephony/SmsCbMessage.java +++ b/telephony/java/android/telephony/SmsCbMessage.java @@ -16,9 +16,11 @@ package android.telephony; +import android.text.format.Time; import android.util.Log; import com.android.internal.telephony.GsmAlphabet; +import com.android.internal.telephony.IccUtils; import com.android.internal.telephony.gsm.SmsCbHeader; import java.io.UnsupportedEncodingException; @@ -93,9 +95,26 @@ public class SmsCbMessage { private String mBody; + /** Timestamp of ETWS primary notification with security. */ + private long mPrimaryNotificationTimestamp; + + /** 43 byte digital signature of ETWS primary notification with security. */ + private byte[] mPrimaryNotificationDigitalSignature; + private SmsCbMessage(byte[] pdu) throws IllegalArgumentException { mHeader = new SmsCbHeader(pdu); - parseBody(pdu); + if (mHeader.format == SmsCbHeader.FORMAT_ETWS_PRIMARY) { + mBody = "ETWS"; + // ETWS primary notification with security is 56 octets in length + if (pdu.length >= SmsCbHeader.PDU_LENGTH_ETWS) { + mPrimaryNotificationTimestamp = getTimestampMillis(pdu); + mPrimaryNotificationDigitalSignature = new byte[43]; + // digital signature starts after 6 byte header and 7 byte timestamp + System.arraycopy(pdu, 13, mPrimaryNotificationDigitalSignature, 0, 43); + } + } else { + parseBody(pdu); + } } /** @@ -157,6 +176,55 @@ public class SmsCbMessage { } /** + * Get the format of this message. + * @return {@link SmsCbHeader#FORMAT_GSM}, {@link SmsCbHeader#FORMAT_UMTS}, or + * {@link SmsCbHeader#FORMAT_ETWS_PRIMARY} + */ + public int getMessageFormat() { + return mHeader.format; + } + + /** + * For ETWS primary notifications, return the emergency user alert flag. + * @return true to notify terminal to activate emergency user alert; false otherwise + */ + public boolean getEtwsEmergencyUserAlert() { + return mHeader.etwsEmergencyUserAlert; + } + + /** + * For ETWS primary notifications, return the popup flag. + * @return true to notify terminal to activate display popup; false otherwise + */ + public boolean getEtwsPopup() { + return mHeader.etwsPopup; + } + + /** + * For ETWS primary notifications, return the warning type. + * @return a value such as {@link SmsCbConstants#ETWS_WARNING_TYPE_EARTHQUAKE} + */ + public int getEtwsWarningType() { + return mHeader.etwsWarningType; + } + + /** + * For ETWS primary notifications, return the Warning-Security-Information timestamp. + * @return a timestamp in System.currentTimeMillis() format. + */ + public long getEtwsSecurityTimestamp() { + return mPrimaryNotificationTimestamp; + } + + /** + * For ETWS primary notifications, return the 43 byte digital signature. + * @return a byte array containing a copy of the digital signature + */ + public byte[] getEtwsSecuritySignature() { + return mPrimaryNotificationDigitalSignature.clone(); + } + + /** * Parse and unpack the body text according to the encoding in the DCS. * After completing successfully this method will have assigned the body * text into mBody, and optionally the language code into mLanguage @@ -333,4 +401,59 @@ public class SmsCbMessage { return body; } + + /** + * Parses an ETWS primary notification timestamp and returns a currentTimeMillis()-style + * timestamp. Copied from com.android.internal.telephony.gsm.SmsMessage. + * @param pdu the ETWS primary notification PDU to decode + * @return the UTC timestamp from the Warning-Security-Information parameter + */ + private long getTimestampMillis(byte[] pdu) { + // Timestamp starts after CB header, in pdu[6] + int year = IccUtils.gsmBcdByteToInt(pdu[6]); + int month = IccUtils.gsmBcdByteToInt(pdu[7]); + int day = IccUtils.gsmBcdByteToInt(pdu[8]); + int hour = IccUtils.gsmBcdByteToInt(pdu[9]); + int minute = IccUtils.gsmBcdByteToInt(pdu[10]); + int second = IccUtils.gsmBcdByteToInt(pdu[11]); + + // For the timezone, the most significant bit of the + // least significant nibble is the sign byte + // (meaning the max range of this field is 79 quarter-hours, + // which is more than enough) + + byte tzByte = pdu[12]; + + // Mask out sign bit. + int timezoneOffset = IccUtils.gsmBcdByteToInt((byte) (tzByte & (~0x08))); + + timezoneOffset = ((tzByte & 0x08) == 0) ? timezoneOffset : -timezoneOffset; + + Time time = new Time(Time.TIMEZONE_UTC); + + // It's 2006. Should I really support years < 2000? + time.year = year >= 90 ? year + 1900 : year + 2000; + time.month = month - 1; + time.monthDay = day; + time.hour = hour; + time.minute = minute; + time.second = second; + + // Timezone offset is in quarter hours. + return time.toMillis(true) - (timezoneOffset * 15 * 60 * 1000); + } + + /** + * Append text to the message body. This is used to concatenate multi-page GSM broadcasts. + * @param body the text to append to this message + */ + public void appendToBody(String body) { + mBody = mBody + body; + } + + @Override + public String toString() { + return "SmsCbMessage{" + mHeader.toString() + ", language=" + mLanguage + + ", body=\"" + mBody + "\"}"; + } } diff --git a/telephony/java/android/telephony/SmsManager.java b/telephony/java/android/telephony/SmsManager.java index 6a346af37bd5..5bdc146792f3 100644 --- a/telephony/java/android/telephony/SmsManager.java +++ b/telephony/java/android/telephony/SmsManager.java @@ -345,7 +345,7 @@ public final class SmsManager { * message identifier. Note that if two different clients enable the same * message identifier, they must both disable it for the device to stop * receiving those messages. All received messages will be broadcast in an - * intent with the action "android.provider.telephony.SMS_CB_RECEIVED". + * intent with the action "android.provider.Telephony.SMS_CB_RECEIVED". * Note: This call is blocking, callers may want to avoid calling it from * the main thread of an application. * @@ -401,6 +401,68 @@ public final class SmsManager { } /** + * Enable reception of cell broadcast (SMS-CB) messages with the given + * message identifier range. Note that if two different clients enable the same + * message identifier, they must both disable it for the device to stop + * receiving those messages. All received messages will be broadcast in an + * intent with the action "android.provider.Telephony.SMS_CB_RECEIVED". + * Note: This call is blocking, callers may want to avoid calling it from + * the main thread of an application. + * + * @param startMessageId first message identifier as specified in TS 23.041 + * @param endMessageId last message identifier as specified in TS 23.041 + * @return true if successful, false otherwise + * @see #disableCellBroadcastRange(int, int) + * + * {@hide} + */ + public boolean enableCellBroadcastRange(int startMessageId, int endMessageId) { + boolean success = false; + + try { + ISms iccISms = ISms.Stub.asInterface(ServiceManager.getService("isms")); + if (iccISms != null) { + success = iccISms.enableCellBroadcastRange(startMessageId, endMessageId); + } + } catch (RemoteException ex) { + // ignore it + } + + return success; + } + + /** + * Disable reception of cell broadcast (SMS-CB) messages with the given + * message identifier range. Note that if two different clients enable the same + * message identifier, they must both disable it for the device to stop + * receiving those messages. + * Note: This call is blocking, callers may want to avoid calling it from + * the main thread of an application. + * + * @param startMessageId first message identifier as specified in TS 23.041 + * @param endMessageId last message identifier as specified in TS 23.041 + * @return true if successful, false otherwise + * + * @see #enableCellBroadcastRange(int, int) + * + * {@hide} + */ + public boolean disableCellBroadcastRange(int startMessageId, int endMessageId) { + boolean success = false; + + try { + ISms iccISms = ISms.Stub.asInterface(ServiceManager.getService("isms")); + if (iccISms != null) { + success = iccISms.disableCellBroadcastRange(startMessageId, endMessageId); + } + } catch (RemoteException ex) { + // ignore it + } + + return success; + } + + /** * Create a list of <code>SmsMessage</code>s from a list of RawSmsData * records returned by <code>getAllMessagesFromIcc()</code> * diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index 66120a171dd9..184d665d0579 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -191,6 +191,10 @@ public class TelephonyManager { * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} */ public String getDeviceId() { + if (!isVoiceCapable()) { + return null; + } + try { return getSubscriberInfo().getDeviceId(); } catch (RemoteException ex) { diff --git a/telephony/java/com/android/internal/telephony/GsmAlphabet.java b/telephony/java/com/android/internal/telephony/GsmAlphabet.java index c7c91e4d9e99..a3f4f1fe2f22 100644 --- a/telephony/java/com/android/internal/telephony/GsmAlphabet.java +++ b/telephony/java/com/android/internal/telephony/GsmAlphabet.java @@ -86,6 +86,8 @@ public class GsmAlphabet { * GSM_EXTENDED_ESCAPE if this character is in the extended table. * In this case, you must call charToGsmExtended() for the value * that should follow GSM_EXTENDED_ESCAPE in the GSM alphabet string. + * @param c the character to convert + * @return the GSM 7 bit table index for the specified character */ public static int charToGsm(char c) { @@ -99,12 +101,15 @@ public class GsmAlphabet { /** * Converts a char to a GSM 7 bit table index. + * Returns GSM_EXTENDED_ESCAPE if this character is in the extended table. + * In this case, you must call charToGsmExtended() for the value that + * should follow GSM_EXTENDED_ESCAPE in the GSM alphabet string. + * + * @param c the character to convert * @param throwException If true, throws EncodeException on invalid char. * If false, returns GSM alphabet ' ' char. - * - * Returns GSM_EXTENDED_ESCAPE if this character is in the extended table - * In this case, you must call charToGsmExtended() for the value that - * should follow GSM_EXTENDED_ESCAPE in the GSM alphabet string + * @throws EncodeException encode error when throwException is true + * @return the GSM 7 bit table index for the specified character */ public static int charToGsm(char c, boolean throwException) throws EncodeException { @@ -133,6 +138,8 @@ public class GsmAlphabet { * Converts a char to an extended GSM 7 bit table index. * Extended chars should be escaped with GSM_EXTENDED_ESCAPE. * Returns ' ' in GSM alphabet if there's no possible match. + * @param c the character to convert + * @return the GSM 7 bit extended table index for the specified character */ public static int charToGsmExtended(char c) { @@ -155,6 +162,9 @@ public class GsmAlphabet { * gsmExtendedToChar(). * * If an unmappable value is passed (one greater than 127), ' ' is returned. + * + * @param gsmChar the GSM 7 bit table index to convert + * @return the decoded character */ public static char gsmToChar(int gsmChar) { @@ -174,6 +184,9 @@ public class GsmAlphabet { * * If an unmappable value is passed, the character from the GSM 7 bit * default table will be used (table 6.2.1.1 of TS 23.038). + * + * @param gsmChar the GSM 7 bit extended table index to convert + * @return the decoded character */ public static char gsmExtendedToChar(int gsmChar) { @@ -244,6 +257,26 @@ public class GsmAlphabet { * septets. * * @param data the data string to encode + * @return the encoded string + * @throws EncodeException if String is too large to encode + */ + public static byte[] stringToGsm7BitPacked(String data) + throws EncodeException { + return stringToGsm7BitPacked(data, 0, true, 0, 0); + } + + /** + * Converts a String into a byte array containing + * the 7-bit packed GSM Alphabet representation of the string. + * + * Unencodable chars are encoded as spaces + * + * Byte 0 in the returned byte array is the count of septets used + * The returned byte array is the minimum size required to store + * the packed septets. The returned array cannot contain more than 255 + * septets. + * + * @param data the data string to encode * @param languageTable the 7 bit language table, or 0 for the default GSM alphabet * @param languageShiftTable the 7 bit single shift language table, or 0 for the default * GSM extension table @@ -449,6 +482,11 @@ public class GsmAlphabet { * * Field may be padded with trailing 0xff's. The decode stops * at the first 0xff encountered. + * + * @param data the byte array to decode + * @param offset array offset for the first character to decode + * @param length the number of bytes to decode + * @return the decoded string */ public static String gsm8BitUnpackedToString(byte[] data, int offset, int length) { @@ -532,6 +570,8 @@ public class GsmAlphabet { /** * Convert a string into an 8-bit unpacked GSM alphabet byte array. * Always uses GSM default 7-bit alphabet and extension table. + * @param s the string to encode + * @return the 8-bit GSM encoded byte array for the string */ public static byte[] stringToGsm8BitPacked(String s) { @@ -550,11 +590,13 @@ public class GsmAlphabet { /** * Write a String into a GSM 8-bit unpacked field of - * @param length size at @param offset in @param dest - * * Field is padded with 0xff's, string is truncated if necessary + * + * @param s the string to encode + * @param dest the destination byte array + * @param offset the starting offset for the encoded string + * @param length the maximum number of bytes to write */ - public static void stringToGsm8BitUnpackedField(String s, byte dest[], int offset, int length) { int outByteIndex = offset; @@ -596,6 +638,8 @@ public class GsmAlphabet { /** * Returns the count of 7-bit GSM alphabet characters * needed to represent this character. Counts unencodable char as 1 septet. + * @param c the character to examine + * @return the number of septets for this character */ public static int countGsmSeptets(char c) { @@ -610,8 +654,11 @@ public class GsmAlphabet { /** * Returns the count of 7-bit GSM alphabet characters * needed to represent this character using the default 7 bit GSM alphabet. + * @param c the character to examine * @param throwsException If true, throws EncodeException if unencodable - * char. Otherwise, counts invalid char as 1 septet + * char. Otherwise, counts invalid char as 1 septet. + * @return the number of septets for this character + * @throws EncodeException the character can't be encoded and throwsException is true */ public static int countGsmSeptets(char c, boolean throwsException) throws EncodeException { diff --git a/telephony/java/com/android/internal/telephony/ISms.aidl b/telephony/java/com/android/internal/telephony/ISms.aidl index 90de5e1c9a7d..735f986917bc 100644 --- a/telephony/java/com/android/internal/telephony/ISms.aidl +++ b/telephony/java/com/android/internal/telephony/ISms.aidl @@ -170,4 +170,32 @@ interface ISms { */ boolean disableCellBroadcast(int messageIdentifier); + /** + * Enable reception of cell broadcast (SMS-CB) messages with the given + * message identifier range. Note that if two different clients enable + * a message identifier range, they must both disable it for the device + * to stop receiving those messages. + * + * @param startMessageId first message identifier as specified in TS 23.041 + * @param endMessageId last message identifier as specified in TS 23.041 + * @return true if successful, false otherwise + * + * @see #disableCellBroadcastRange(int, int) + */ + boolean enableCellBroadcastRange(int startMessageId, int endMessageId); + + /** + * Disable reception of cell broadcast (SMS-CB) messages with the given + * message identifier range. Note that if two different clients enable + * a message identifier range, they must both disable it for the device + * to stop receiving those messages. + * + * @param startMessageId first message identifier as specified in TS 23.041 + * @param endMessageId last message identifier as specified in TS 23.041 + * @return true if successful, false otherwise + * + * @see #enableCellBroadcastRange(int, int) + */ + boolean disableCellBroadcastRange(int startMessageId, int endMessageId); + } diff --git a/telephony/java/com/android/internal/telephony/IccCardApplication.java b/telephony/java/com/android/internal/telephony/IccCardApplication.java index 4cf21eeaf8e3..434c484ebbdd 100644 --- a/telephony/java/com/android/internal/telephony/IccCardApplication.java +++ b/telephony/java/com/android/internal/telephony/IccCardApplication.java @@ -177,4 +177,15 @@ public class IccCardApplication { return newSubState; } + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + + sb.append("{").append(app_type).append(",").append(app_state); + if (app_state == AppState.APPSTATE_SUBSCRIPTION_PERSO) { + sb.append(",").append(perso_substate); + } + sb.append("}"); + return sb.toString(); + } } diff --git a/telephony/java/com/android/internal/telephony/IccCardStatus.java b/telephony/java/com/android/internal/telephony/IccCardStatus.java index 7199616acbd9..e9de922a5cd9 100644 --- a/telephony/java/com/android/internal/telephony/IccCardStatus.java +++ b/telephony/java/com/android/internal/telephony/IccCardStatus.java @@ -144,4 +144,33 @@ public class IccCardStatus { return mApplications.get(index); } + @Override + public String toString() { + IccCardApplication app; + + StringBuilder sb = new StringBuilder(); + sb.append("IccCardState {").append(mCardState).append(",") + .append(mUniversalPinState) + .append(",num_apps=").append(mNumApplications) + .append(",gsm_id=").append(mGsmUmtsSubscriptionAppIndex); + if (mGsmUmtsSubscriptionAppIndex >=0 + && mGsmUmtsSubscriptionAppIndex <CARD_MAX_APPS) { + app = getApplication(mGsmUmtsSubscriptionAppIndex); + sb.append(app == null ? "null" : app); + } + + sb.append(",cmda_id=").append(mCdmaSubscriptionAppIndex); + if (mCdmaSubscriptionAppIndex >=0 + && mCdmaSubscriptionAppIndex <CARD_MAX_APPS) { + app = getApplication(mCdmaSubscriptionAppIndex); + sb.append(app == null ? "null" : app); + } + + sb.append(",ism_id=").append(mImsSubscriptionAppIndex); + + sb.append("}"); + + return sb.toString(); + } + } diff --git a/telephony/java/com/android/internal/telephony/IccConstants.java b/telephony/java/com/android/internal/telephony/IccConstants.java index cafc79bf5fd9..1ba6dfe19366 100644 --- a/telephony/java/com/android/internal/telephony/IccConstants.java +++ b/telephony/java/com/android/internal/telephony/IccConstants.java @@ -63,6 +63,10 @@ public interface IccConstants { // 3GPP2 C.S0065 static final int EF_CSIM_LI = 0x6F3A; static final int EF_CSIM_SPN =0x6F41; + static final int EF_CSIM_MDN = 0x6F44; + static final int EF_CSIM_IMSIM = 0x6F22; + static final int EF_CSIM_CDMAHOME = 0x6F28; + static final int EF_CSIM_EPRL = 0x6F5A; //ISIM access static final int EF_IMPU = 0x6f04; diff --git a/telephony/java/com/android/internal/telephony/IccRecords.java b/telephony/java/com/android/internal/telephony/IccRecords.java index 10a3b6996440..3a2790123fb1 100644 --- a/telephony/java/com/android/internal/telephony/IccRecords.java +++ b/telephony/java/com/android/internal/telephony/IccRecords.java @@ -288,6 +288,16 @@ public abstract class IccRecords extends Handler implements IccConstants { } /** + * Indicates wether SIM is in provisioned state or not. + * Overridden only if SIM can be dynamically provisioned via OTA. + * + * @return true if provisioned + */ + public boolean isProvisioned () { + return true; + } + + /** * Write string to log file * * @param s is the string to write diff --git a/telephony/java/com/android/internal/telephony/IccSmsInterfaceManagerProxy.java b/telephony/java/com/android/internal/telephony/IccSmsInterfaceManagerProxy.java index 5049249053ba..54de508c04de 100644 --- a/telephony/java/com/android/internal/telephony/IccSmsInterfaceManagerProxy.java +++ b/telephony/java/com/android/internal/telephony/IccSmsInterfaceManagerProxy.java @@ -76,4 +76,13 @@ public class IccSmsInterfaceManagerProxy extends ISms.Stub { return mIccSmsInterfaceManager.disableCellBroadcast(messageIdentifier); } + public boolean enableCellBroadcastRange(int startMessageId, int endMessageId) + throws android.os.RemoteException { + return mIccSmsInterfaceManager.enableCellBroadcastRange(startMessageId, endMessageId); + } + + public boolean disableCellBroadcastRange(int startMessageId, int endMessageId) + throws android.os.RemoteException { + return mIccSmsInterfaceManager.disableCellBroadcastRange(startMessageId, endMessageId); + } } diff --git a/telephony/java/com/android/internal/telephony/IccUtils.java b/telephony/java/com/android/internal/telephony/IccUtils.java index c3b0ffc15976..a966f7694f09 100644 --- a/telephony/java/com/android/internal/telephony/IccUtils.java +++ b/telephony/java/com/android/internal/telephony/IccUtils.java @@ -63,6 +63,29 @@ public class IccUtils { return ret.toString(); } + /** + * Decode cdma byte into String. + */ + public static String + cdmaBcdToString(byte[] data, int offset, int length) { + StringBuilder ret = new StringBuilder(length); + + int count = 0; + for (int i = offset; count < length; i++) { + int v; + v = data[i] & 0xf; + if (v > 9) v = 0; + ret.append((char)('0' + v)); + + if (++count == length) break; + + v = (data[i] >> 4) & 0xf; + if (v > 9) v = 0; + ret.append((char)('0' + v)); + ++count; + } + return ret.toString(); + } /** * Decodes a GSM-style BCD byte, returning an int ranging from 0-99. diff --git a/telephony/java/com/android/internal/telephony/IntRangeManager.java b/telephony/java/com/android/internal/telephony/IntRangeManager.java new file mode 100644 index 000000000000..970bc4424fba --- /dev/null +++ b/telephony/java/com/android/internal/telephony/IntRangeManager.java @@ -0,0 +1,568 @@ +/* + * 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.telephony; + +import java.util.ArrayList; +import java.util.Iterator; + +/** + * Clients can enable reception of SMS-CB messages for specific ranges of + * message identifiers (channels). This class keeps track of the currently + * enabled message identifiers and calls abstract methods to update the + * radio when the range of enabled message identifiers changes. + * + * An update is a call to {@link #startUpdate} followed by zero or more + * calls to {@link #addRange} followed by a call to {@link #finishUpdate}. + * Calls to {@link #enableRange} and {@link #disableRange} will perform + * an incremental update operation if the enabled ranges have changed. + * A full update operation (i.e. after a radio reset) can be performed + * by a call to {@link #updateRanges}. + * + * Clients are identified by String (the name associated with the User ID + * of the caller) so that a call to remove a range can be mapped to the + * client that enabled that range (or else rejected). + */ +public abstract class IntRangeManager { + + /** + * Initial capacity for IntRange clients array list. There will be + * few cell broadcast listeners on a typical device, so this can be small. + */ + private static final int INITIAL_CLIENTS_ARRAY_SIZE = 4; + + /** + * One or more clients forming the continuous range [startId, endId]. + * <p>When a client is added, the IntRange may merge with one or more + * adjacent IntRanges to form a single combined IntRange. + * <p>When a client is removed, the IntRange may divide into several + * non-contiguous IntRanges. + */ + private class IntRange { + int startId; + int endId; + // sorted by earliest start id + final ArrayList<ClientRange> clients; + + /** + * Create a new IntRange with a single client. + * @param startId the first id included in the range + * @param endId the last id included in the range + * @param client the client requesting the enabled range + */ + IntRange(int startId, int endId, String client) { + this.startId = startId; + this.endId = endId; + clients = new ArrayList<ClientRange>(INITIAL_CLIENTS_ARRAY_SIZE); + clients.add(new ClientRange(startId, endId, client)); + } + + /** + * Create a new IntRange for an existing ClientRange. + * @param clientRange the initial ClientRange to add + */ + IntRange(ClientRange clientRange) { + startId = clientRange.startId; + endId = clientRange.endId; + clients = new ArrayList<ClientRange>(INITIAL_CLIENTS_ARRAY_SIZE); + clients.add(clientRange); + } + + /** + * Create a new IntRange from an existing IntRange. This is used for + * removing a ClientRange, because new IntRanges may need to be created + * for any gaps that open up after the ClientRange is removed. A copy + * is made of the elements of the original IntRange preceding the element + * that is being removed. The following elements will be added to this + * IntRange or to a new IntRange when a gap is found. + * @param intRange the original IntRange to copy elements from + * @param numElements the number of elements to copy from the original + */ + IntRange(IntRange intRange, int numElements) { + this.startId = intRange.startId; + this.endId = intRange.endId; + this.clients = new ArrayList<ClientRange>(intRange.clients.size()); + for (int i=0; i < numElements; i++) { + this.clients.add(intRange.clients.get(i)); + } + } + + /** + * Insert new ClientRange in order by start id. + * <p>If the new ClientRange is known to be sorted before or after the + * existing ClientRanges, or at a particular index, it can be added + * to the clients array list directly, instead of via this method. + * <p>Note that this can be changed from linear to binary search if the + * number of clients grows large enough that it would make a difference. + * @param range the new ClientRange to insert + */ + void insert(ClientRange range) { + int len = clients.size(); + for (int i=0; i < len; i++) { + ClientRange nextRange = clients.get(i); + if (range.startId <= nextRange.startId) { + // ignore duplicate ranges from the same client + if (!range.equals(nextRange)) { + clients.add(i, range); + } + return; + } + } + clients.add(range); // append to end of list + } + } + + /** + * The message id range for a single client. + */ + private class ClientRange { + final int startId; + final int endId; + final String client; + + ClientRange(int startId, int endId, String client) { + this.startId = startId; + this.endId = endId; + this.client = client; + } + + @Override + public boolean equals(Object o) { + if (o != null && o instanceof ClientRange) { + ClientRange other = (ClientRange) o; + return startId == other.startId && + endId == other.endId && + client.equals(other.client); + } else { + return false; + } + } + + @Override + public int hashCode() { + return (startId * 31 + endId) * 31 + client.hashCode(); + } + } + + /** + * List of integer ranges, one per client, sorted by start id. + */ + private ArrayList<IntRange> mRanges = new ArrayList<IntRange>(); + + protected IntRangeManager() {} + + /** + * Enable a range for the specified client and update ranges + * if necessary. If {@link #finishUpdate} returns failure, + * false is returned and the range is not added. + * + * @param startId the first id included in the range + * @param endId the last id included in the range + * @param client the client requesting the enabled range + * @return true if successful, false otherwise + */ + public synchronized boolean enableRange(int startId, int endId, String client) { + int len = mRanges.size(); + + // empty range list: add the initial IntRange + if (len == 0) { + if (tryAddSingleRange(startId, endId, true)) { + mRanges.add(new IntRange(startId, endId, client)); + return true; + } else { + return false; // failed to update radio + } + } + + for (int startIndex = 0; startIndex < len; startIndex++) { + IntRange range = mRanges.get(startIndex); + if (startId < range.startId) { + // test if new range completely precedes this range + // note that [1, 4] and [5, 6] coalesce to [1, 6] + if ((endId + 1) < range.startId) { + // insert new int range before previous first range + if (tryAddSingleRange(startId, endId, true)) { + mRanges.add(startIndex, new IntRange(startId, endId, client)); + return true; + } else { + return false; // failed to update radio + } + } else if (endId <= range.endId) { + // extend the start of this range + if (tryAddSingleRange(startId, range.startId - 1, true)) { + range.startId = startId; + range.clients.add(0, new ClientRange(startId, endId, client)); + return true; + } else { + return false; // failed to update radio + } + } else { + // find last range that can coalesce into the new combined range + for (int endIndex = startIndex+1; endIndex < len; endIndex++) { + IntRange endRange = mRanges.get(endIndex); + if ((endId + 1) < endRange.startId) { + // try to add entire new range + if (tryAddSingleRange(startId, endId, true)) { + range.startId = startId; + range.endId = endId; + // insert new ClientRange before existing ranges + range.clients.add(0, new ClientRange(startId, endId, client)); + // coalesce range with following ranges up to endIndex-1 + // remove each range after adding its elements, so the index + // of the next range to join is always startIndex+1. + // i is the index if no elements were removed: we only care + // about the number of loop iterations, not the value of i. + int joinIndex = startIndex + 1; + for (int i = joinIndex; i < endIndex; i++) { + IntRange joinRange = mRanges.get(joinIndex); + range.clients.addAll(joinRange.clients); + mRanges.remove(joinRange); + } + return true; + } else { + return false; // failed to update radio + } + } else if (endId <= endRange.endId) { + // add range from start id to start of last overlapping range, + // values from endRange.startId to endId are already enabled + if (tryAddSingleRange(startId, endRange.startId - 1, true)) { + range.startId = startId; + range.endId = endRange.endId; + // insert new ClientRange before existing ranges + range.clients.add(0, new ClientRange(startId, endId, client)); + // coalesce range with following ranges up to endIndex + // remove each range after adding its elements, so the index + // of the next range to join is always startIndex+1. + // i is the index if no elements were removed: we only care + // about the number of loop iterations, not the value of i. + int joinIndex = startIndex + 1; + for (int i = joinIndex; i <= endIndex; i++) { + IntRange joinRange = mRanges.get(joinIndex); + range.clients.addAll(joinRange.clients); + mRanges.remove(joinRange); + } + return true; + } else { + return false; // failed to update radio + } + } + } + + // endId extends past all existing IntRanges: combine them all together + if (tryAddSingleRange(startId, endId, true)) { + range.startId = startId; + range.endId = endId; + // insert new ClientRange before existing ranges + range.clients.add(0, new ClientRange(startId, endId, client)); + // coalesce range with following ranges up to len-1 + // remove each range after adding its elements, so the index + // of the next range to join is always startIndex+1. + // i is the index if no elements were removed: we only care + // about the number of loop iterations, not the value of i. + int joinIndex = startIndex + 1; + for (int i = joinIndex; i < len; i++) { + IntRange joinRange = mRanges.get(joinIndex); + range.clients.addAll(joinRange.clients); + mRanges.remove(joinRange); + } + return true; + } else { + return false; // failed to update radio + } + } + } else if ((startId + 1) <= range.endId) { + if (endId <= range.endId) { + // completely contained in existing range; no radio changes + range.insert(new ClientRange(startId, endId, client)); + return true; + } else { + // find last range that can coalesce into the new combined range + int endIndex = startIndex; + for (int testIndex = startIndex+1; testIndex < len; testIndex++) { + IntRange testRange = mRanges.get(testIndex); + if ((endId + 1) < testRange.startId) { + break; + } else { + endIndex = testIndex; + } + } + // no adjacent IntRanges to combine + if (endIndex == startIndex) { + // add range from range.endId+1 to endId, + // values from startId to range.endId are already enabled + if (tryAddSingleRange(range.endId + 1, endId, true)) { + range.endId = endId; + range.insert(new ClientRange(startId, endId, client)); + return true; + } else { + return false; // failed to update radio + } + } + // get last range to coalesce into start range + IntRange endRange = mRanges.get(endIndex); + // Values from startId to range.endId have already been enabled. + // if endId > endRange.endId, then enable range from range.endId+1 to endId, + // else enable range from range.endId+1 to endRange.startId-1, because + // values from endRange.startId to endId have already been added. + int newRangeEndId = (endId <= endRange.endId) ? endRange.startId - 1 : endId; + if (tryAddSingleRange(range.endId + 1, newRangeEndId, true)) { + range.endId = endId; + // insert new ClientRange in place + range.insert(new ClientRange(startId, endId, client)); + // coalesce range with following ranges up to endIndex-1 + // remove each range after adding its elements, so the index + // of the next range to join is always startIndex+1 (joinIndex). + // i is the index if no elements had been removed: we only care + // about the number of loop iterations, not the value of i. + int joinIndex = startIndex + 1; + for (int i = joinIndex; i < endIndex; i++) { + IntRange joinRange = mRanges.get(joinIndex); + range.clients.addAll(joinRange.clients); + mRanges.remove(joinRange); + } + return true; + } else { + return false; // failed to update radio + } + } + } + } + + // append new range after existing IntRanges + if (tryAddSingleRange(startId, endId, true)) { + mRanges.add(new IntRange(startId, endId, client)); + return true; + } else { + return false; // failed to update radio + } + } + + /** + * Disable a range for the specified client and update ranges + * if necessary. If {@link #finishUpdate} returns failure, + * false is returned and the range is not removed. + * + * @param startId the first id included in the range + * @param endId the last id included in the range + * @param client the client requesting to disable the range + * @return true if successful, false otherwise + */ + public synchronized boolean disableRange(int startId, int endId, String client) { + int len = mRanges.size(); + + for (int i=0; i < len; i++) { + IntRange range = mRanges.get(i); + if (startId < range.startId) { + return false; // not found + } else if (endId <= range.endId) { + // found the IntRange that encloses the client range, if any + // search for it in the clients list + ArrayList<ClientRange> clients = range.clients; + + // handle common case of IntRange containing one ClientRange + int crLength = clients.size(); + if (crLength == 1) { + ClientRange cr = clients.get(0); + if (cr.startId == startId && cr.endId == endId && cr.client.equals(client)) { + // disable range in radio then remove the entire IntRange + if (tryAddSingleRange(startId, endId, false)) { + mRanges.remove(i); + return true; + } else { + return false; // failed to update radio + } + } else { + return false; // not found + } + } + + // several ClientRanges: remove one, potentially splitting into many IntRanges. + // Save the original start and end id for the original IntRange + // in case the radio update fails and we have to revert it. If the + // update succeeds, we remove the client range and insert the new IntRanges. + int largestEndId = Integer.MIN_VALUE; // largest end identifier found + boolean updateStarted = false; + + for (int crIndex=0; crIndex < crLength; crIndex++) { + ClientRange cr = clients.get(crIndex); + if (cr.startId == startId && cr.endId == endId && cr.client.equals(client)) { + // found the ClientRange to remove, check if it's the last in the list + if (crIndex == crLength - 1) { + if (range.endId == largestEndId) { + // no channels to remove from radio; return success + clients.remove(crIndex); + return true; + } else { + // disable the channels at the end and lower the end id + if (tryAddSingleRange(largestEndId + 1, range.endId, false)) { + clients.remove(crIndex); + range.endId = largestEndId; + return true; + } else { + return false; + } + } + } + + // copy the IntRange so that we can remove elements and modify the + // start and end id's in the copy, leaving the original unmodified + // until after the radio update succeeds + IntRange rangeCopy = new IntRange(range, crIndex); + + if (crIndex == 0) { + // removing the first ClientRange, so we may need to increase + // the start id of the IntRange. + // We know there are at least two ClientRanges in the list, + // so clients.get(1) should always succeed. + int nextStartId = clients.get(1).startId; + if (nextStartId != range.startId) { + startUpdate(); + updateStarted = true; + addRange(range.startId, nextStartId - 1, false); + rangeCopy.startId = nextStartId; + } + // init largestEndId + largestEndId = clients.get(1).endId; + } + + // go through remaining ClientRanges, creating new IntRanges when + // there is a gap in the sequence. After radio update succeeds, + // remove the original IntRange and append newRanges to mRanges. + // Otherwise, leave the original IntRange in mRanges and return false. + ArrayList<IntRange> newRanges = new ArrayList<IntRange>(); + + IntRange currentRange = rangeCopy; + for (int nextIndex = crIndex + 1; nextIndex < crLength; nextIndex++) { + ClientRange nextCr = clients.get(nextIndex); + if (nextCr.startId > largestEndId + 1) { + if (!updateStarted) { + startUpdate(); + updateStarted = true; + } + addRange(largestEndId + 1, nextCr.startId - 1, false); + currentRange.endId = largestEndId; + newRanges.add(currentRange); + currentRange = new IntRange(nextCr); + } else { + currentRange.clients.add(nextCr); + } + if (nextCr.endId > largestEndId) { + largestEndId = nextCr.endId; + } + } + + // remove any channels between largestEndId and endId + if (largestEndId < endId) { + if (!updateStarted) { + startUpdate(); + updateStarted = true; + } + addRange(largestEndId + 1, endId, false); + currentRange.endId = largestEndId; + } + newRanges.add(currentRange); + + if (updateStarted && !finishUpdate()) { + return false; // failed to update radio + } + + // replace the original IntRange with newRanges + mRanges.remove(i); + mRanges.addAll(i, newRanges); + return true; + } else { + // not the ClientRange to remove; save highest end ID seen so far + if (cr.endId > largestEndId) { + largestEndId = cr.endId; + } + } + } + } + } + + return false; // not found + } + + /** + * Perform a complete update operation (enable all ranges). Useful + * after a radio reset. Calls {@link #startUpdate}, followed by zero or + * more calls to {@link #addRange}, followed by {@link #finishUpdate}. + * @return true if successful, false otherwise + */ + public boolean updateRanges() { + startUpdate(); + Iterator<IntRange> iterator = mRanges.iterator(); + if (iterator.hasNext()) { + IntRange range = iterator.next(); + int start = range.startId; + int end = range.endId; + // accumulate ranges of [startId, endId] + while (iterator.hasNext()) { + IntRange nextNode = iterator.next(); + // [startIdA, endIdA], [endIdA + 1, endIdB] -> [startIdA, endIdB] + if (nextNode.startId <= (end + 1)) { + if (nextNode.endId > end) { + end = nextNode.endId; + } + } else { + addRange(start, end, true); + start = nextNode.startId; + end = nextNode.endId; + } + } + // add final range + addRange(start, end, true); + } + return finishUpdate(); + } + + /** + * Enable or disable a single range of message identifiers. + * @param startId the first id included in the range + * @param endId the last id included in the range + * @param selected true to enable range, false to disable range + * @return true if successful, false otherwise + */ + private boolean tryAddSingleRange(int startId, int endId, boolean selected) { + startUpdate(); + addRange(startId, endId, selected); + return finishUpdate(); + } + + /** + * Called when the list of enabled ranges has changed. This will be + * followed by zero or more calls to {@link #addRange} followed by + * a call to {@link #finishUpdate}. + */ + protected abstract void startUpdate(); + + /** + * Called after {@link #startUpdate} to indicate a range of enabled + * or disabled values. + * + * @param startId the first id included in the range + * @param endId the last id included in the range + * @param selected true to enable range, false to disable range + */ + protected abstract void addRange(int startId, int endId, boolean selected); + + /** + * Called to indicate the end of a range update started by the + * previous call to {@link #startUpdate}. + * @return true if successful, false otherwise + */ + protected abstract boolean finishUpdate(); +} diff --git a/telephony/java/com/android/internal/telephony/MccTable.java b/telephony/java/com/android/internal/telephony/MccTable.java index fde1b591e32a..cdce841cfbd6 100644 --- a/telephony/java/com/android/internal/telephony/MccTable.java +++ b/telephony/java/com/android/internal/telephony/MccTable.java @@ -234,7 +234,7 @@ public final class MccTable String country = MccTable.countryCodeForMcc(mcc); Log.d(LOG_TAG, "locale set to "+language+"_"+country); - phone.setSystemLocale(language, country); + phone.setSystemLocale(language, country, true); } /** diff --git a/telephony/java/com/android/internal/telephony/PhoneBase.java b/telephony/java/com/android/internal/telephony/PhoneBase.java index f70d680fb604..40a70a806ce1 100644 --- a/telephony/java/com/android/internal/telephony/PhoneBase.java +++ b/telephony/java/com/android/internal/telephony/PhoneBase.java @@ -580,7 +580,7 @@ public abstract class PhoneBase extends Handler implements Phone { if (l.length() >=5) { country = l.substring(3, 5); } - setSystemLocale(language, country); + setSystemLocale(language, country, false); if (!country.isEmpty()) { try { @@ -602,10 +602,14 @@ public abstract class PhoneBase extends Handler implements Phone { * Utility code to set the system locale if it's not set already * @param language Two character language code desired * @param country Two character country code desired + * @param fromMcc Indicating whether the locale is set according to MCC table. + * This flag wil be ignored by default implementation. + * TODO: Use a source enumeration so that source of the locale + * can be prioritized. * * {@hide} */ - public void setSystemLocale(String language, String country) { + public void setSystemLocale(String language, String country, boolean fromMcc) { String l = SystemProperties.get("persist.sys.language"); String c = SystemProperties.get("persist.sys.country"); diff --git a/telephony/java/com/android/internal/telephony/PhoneFactory.java b/telephony/java/com/android/internal/telephony/PhoneFactory.java index 6a2d7c9e5cbc..74bae447bbbd 100644 --- a/telephony/java/com/android/internal/telephony/PhoneFactory.java +++ b/telephony/java/com/android/internal/telephony/PhoneFactory.java @@ -47,8 +47,6 @@ public class PhoneFactory { static private Looper sLooper; static private Context sContext; - static final int preferredNetworkMode = RILConstants.PREFERRED_NETWORK_MODE; - static final int preferredCdmaSubscription = RILConstants.PREFERRED_CDMA_SUBSCRIPTION; //***** Class Methods @@ -99,7 +97,11 @@ public class PhoneFactory { sPhoneNotifier = new DefaultPhoneNotifier(); - //Get preferredNetworkMode from Settings.System + // Get preferred network mode + int preferredNetworkMode = RILConstants.PREFERRED_NETWORK_MODE; + if (BaseCommands.getLteOnCdmaModeStatic() == Phone.LTE_ON_CDMA_TRUE) { + preferredNetworkMode = Phone.NT_MODE_GLOBAL; + } int networkMode = Settings.Secure.getInt(context.getContentResolver(), Settings.Secure.PREFERRED_NETWORK_MODE, preferredNetworkMode); Log.i(LOG_TAG, "Network Mode set to " + Integer.toString(networkMode)); diff --git a/telephony/java/com/android/internal/telephony/SMSDispatcher.java b/telephony/java/com/android/internal/telephony/SMSDispatcher.java index 8efc9aa4bd25..76e719c3c895 100755..100644 --- a/telephony/java/com/android/internal/telephony/SMSDispatcher.java +++ b/telephony/java/com/android/internal/telephony/SMSDispatcher.java @@ -32,11 +32,9 @@ import android.database.Cursor; import android.database.SQLException; import android.net.Uri; import android.os.AsyncResult; -import android.os.Environment; import android.os.Handler; import android.os.Message; import android.os.PowerManager; -import android.os.StatFs; import android.os.SystemProperties; import android.provider.Telephony; import android.provider.Telephony.Sms.Intents; @@ -908,37 +906,6 @@ public abstract class SMSDispatcher extends Handler { protected abstract void sendMultipartSms (SmsTracker tracker); /** - * Activate or deactivate cell broadcast SMS. - * - * @param activate - * 0 = activate, 1 = deactivate - * @param response - * Callback message is empty on completion - */ - public abstract void activateCellBroadcastSms(int activate, Message response); - - /** - * Query the current configuration of cell broadcast SMS. - * - * @param response - * Callback message contains the configuration from the modem on completion - * @see #setCellBroadcastConfig - */ - public abstract void getCellBroadcastSmsConfig(Message response); - - /** - * Configure cell broadcast SMS. - * - * @param configValuesArray - * The first element defines the number of triples that follow. - * A triple is made up of the service category, the language identifier - * and a boolean that specifies whether the category is set active. - * @param response - * Callback message is empty on completion - */ - public abstract void setCellBroadcastConfig(int[] configValuesArray, Message response); - - /** * Send an acknowledge message. * @param success indicates that last message was successfully received. * @param result result code indicating any error @@ -1065,14 +1032,17 @@ public abstract class SMSDispatcher extends Handler { protected abstract void handleBroadcastSms(AsyncResult ar); - protected void dispatchBroadcastPdus(byte[][] pdus) { - Intent intent = new Intent("android.provider.telephony.SMS_CB_RECEIVED"); - intent.putExtra("pdus", pdus); - - if (false) + protected void dispatchBroadcastPdus(byte[][] pdus, boolean isEmergencyMessage) { + if (isEmergencyMessage) { + Intent intent = new Intent(Intents.SMS_EMERGENCY_CB_RECEIVED_ACTION); + intent.putExtra("pdus", pdus); + Log.d(TAG, "Dispatching " + pdus.length + " emergency SMS CB pdus"); + dispatch(intent, "android.permission.RECEIVE_EMERGENCY_BROADCAST"); + } else { + Intent intent = new Intent(Intents.SMS_CB_RECEIVED_ACTION); + intent.putExtra("pdus", pdus); Log.d(TAG, "Dispatching " + pdus.length + " SMS CB pdus"); - - dispatch(intent, "android.permission.RECEIVE_SMS"); + dispatch(intent, "android.permission.RECEIVE_SMS"); + } } - } diff --git a/telephony/java/com/android/internal/telephony/cdma/CDMALTEPhone.java b/telephony/java/com/android/internal/telephony/cdma/CDMALTEPhone.java index fe2fcb22db24..6a95b674167a 100644 --- a/telephony/java/com/android/internal/telephony/cdma/CDMALTEPhone.java +++ b/telephony/java/com/android/internal/telephony/cdma/CDMALTEPhone.java @@ -65,33 +65,13 @@ public class CDMALTEPhone extends CDMAPhone { @Override public DataState getDataConnectionState(String apnType) { - // TODO: Remove instanceof if possible. - boolean isCdmaDataConnectionTracker = false; - if (mDataConnectionTracker instanceof CdmaDataConnectionTracker) { - log("getDataConnectionState isCdmaDataConnectionTracker"); - isCdmaDataConnectionTracker = true; - } else { - log("getDataConnectionState NOT CdmaDataConnectionTracker"); - } DataState ret = DataState.DISCONNECTED; - if (!isCdmaDataConnectionTracker && (SystemProperties.get("adb.connected", "").length() - > 0)) { - // We're connected to an ADB host and we have USB networking - // turned on. No matter what the radio state is, - // we report data connected - - ret = DataState.CONNECTED; - } else if (mSST == null) { + if (mSST == null) { // Radio Technology Change is ongoning, dispose() and - // removeReferences() have - // already been called + // removeReferences() have already been called ret = DataState.DISCONNECTED; - } else if (mSST.getCurrentDataConnectionState() != ServiceState.STATE_IN_SERVICE) { - // If we're out of service, open TCP sockets may still work - // but no data will flow - ret = DataState.DISCONNECTED; } else if (mDataConnectionTracker.isApnTypeEnabled(apnType) == false) { ret = DataState.DISCONNECTED; } else { @@ -141,6 +121,15 @@ public class CDMALTEPhone extends CDMAPhone { } @Override + public void setSystemLocale(String language, String country, boolean fromMcc) { + // Avoid system locale is set from MCC table if CDMALTEPhone is used. + // The locale will be picked up based on EFpl/EFli once CSIM records are loaded. + if (fromMcc) return; + + super.setSystemLocale(language, country, false); + } + + @Override protected void log(String s) { if (DBG) Log.d(LOG_TAG, "[CDMALTEPhone] " + s); diff --git a/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java b/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java index a283062cc674..bac15a6901d3 100755 --- a/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java +++ b/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java @@ -1121,7 +1121,8 @@ public class CDMAPhone extends PhoneBase { * @param response Callback message is empty on completion */ public void activateCellBroadcastSms(int activate, Message response) { - mSMS.activateCellBroadcastSms(activate, response); + Log.e(LOG_TAG, "[CDMAPhone] activateCellBroadcastSms() is obsolete; use SmsManager"); + response.sendToTarget(); } /** @@ -1130,7 +1131,8 @@ public class CDMAPhone extends PhoneBase { * @param response Callback message is empty on completion */ public void getCellBroadcastSmsConfig(Message response) { - mSMS.getCellBroadcastSmsConfig(response); + Log.e(LOG_TAG, "[CDMAPhone] getCellBroadcastSmsConfig() is obsolete; use SmsManager"); + response.sendToTarget(); } /** @@ -1139,7 +1141,8 @@ public class CDMAPhone extends PhoneBase { * @param response Callback message is empty on completion */ public void setCellBroadcastSmsConfig(int[] configValuesArray, Message response) { - mSMS.setCellBroadcastConfig(configValuesArray, response); + Log.e(LOG_TAG, "[CDMAPhone] setCellBroadcastSmsConfig() is obsolete; use SmsManager"); + response.sendToTarget(); } /** diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaLteServiceStateTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaLteServiceStateTracker.java index 7bc7ca217e4b..abd87b89b5ec 100644 --- a/telephony/java/com/android/internal/telephony/cdma/CdmaLteServiceStateTracker.java +++ b/telephony/java/com/android/internal/telephony/cdma/CdmaLteServiceStateTracker.java @@ -16,7 +16,6 @@ package com.android.internal.telephony.cdma; -import com.android.internal.telephony.DataConnectionTracker; import com.android.internal.telephony.TelephonyProperties; import com.android.internal.telephony.MccTable; import com.android.internal.telephony.EventLogTags; @@ -26,23 +25,15 @@ import android.telephony.SignalStrength; import android.telephony.ServiceState; import android.telephony.cdma.CdmaCellLocation; import android.os.AsyncResult; -import android.os.Handler; import android.os.Message; -import android.os.Registrant; -import android.os.RegistrantList; -import android.os.AsyncResult; -import android.os.Message; -import android.os.SystemProperties; + import android.util.Log; import android.util.EventLog; -import com.android.internal.telephony.RestrictedState; import com.android.internal.telephony.gsm.GsmDataConnectionTracker; public class CdmaLteServiceStateTracker extends CdmaServiceStateTracker { - static final String LOG_TAG = "CDMA"; - CDMALTEPhone mCdmaLtePhone; private ServiceState mLteSS; // The last LTE state from Voice Registration @@ -56,6 +47,7 @@ public class CdmaLteServiceStateTracker extends CdmaServiceStateTracker { if (DBG) log("CdmaLteServiceStateTracker Constructors"); } + @Override public void dispose() { cm.unregisterForSIMReady(this); super.dispose(); @@ -75,11 +67,24 @@ public class CdmaLteServiceStateTracker extends CdmaServiceStateTracker { case EVENT_SIM_READY: if (DBG) log("handleMessage EVENT_SIM_READY"); isSubscriptionFromRuim = false; - cm.getCDMASubscription( obtainMessage(EVENT_POLL_STATE_CDMA_SUBSCRIPTION)); + // Register SIM_RECORDS_LOADED dynamically. + // This is to avoid confilct with RUIM_READY scenario) + phone.mIccRecords.registerForRecordsLoaded(this, EVENT_SIM_RECORDS_LOADED, null); pollState(); // Signal strength polling stops when radio is off. queueNextSignalStrengthPoll(); break; + case EVENT_SIM_RECORDS_LOADED: + CdmaLteUiccRecords sim = (CdmaLteUiccRecords)phone.mIccRecords; + if ((sim != null) && sim.isProvisioned()) { + mMdn = sim.getMdn(); + mMin = sim.getMin(); + parseSidNid(sim.getSid(), sim.getNid()); + mPrlVersion = sim.getPrlVersion();; + mIsMinInfoReady = true; + updateOtaspState(); + } + break; default: super.handleMessage(msg); } @@ -120,8 +125,6 @@ public class CdmaLteServiceStateTracker extends CdmaServiceStateTracker { } } - // Not sure if this is needed in CDMALTE phone. - // mDataRoaming = regCodeIsRoaming(regState); mLteSS.setRadioTechnology(type); mLteSS.setState(regCodeToServiceState(regState)); } else { @@ -207,6 +210,12 @@ public class CdmaLteServiceStateTracker extends CdmaServiceStateTracker { if (DBG) log("pollStateDone: oldSS=[" + ss + "] newSS=[" + newSS + "]"); + if (cm.getSimState().isSIMReady()) { + // If CSIM is used, check roaming status according to SID/NID + // on EFcdmahome record. + newSS.setRoaming(!isInHomeSidNid(newSS.getSystemId(), newSS.getNetworkId())); + } + boolean hasRegistered = ss.getState() != ServiceState.STATE_IN_SERVICE && newSS.getState() == ServiceState.STATE_IN_SERVICE; @@ -398,6 +407,7 @@ public class CdmaLteServiceStateTracker extends CdmaServiceStateTracker { } } + @Override protected void onSignalStrengthResult(AsyncResult ar) { SignalStrength oldSignalStrength = mSignalStrength; @@ -439,6 +449,7 @@ public class CdmaLteServiceStateTracker extends CdmaServiceStateTracker { } } + @Override public boolean isConcurrentVoiceAndDataAllowed() { // Note: it needs to be confirmed which CDMA network types // can support voice and data calls concurrently. @@ -447,6 +458,43 @@ public class CdmaLteServiceStateTracker extends CdmaServiceStateTracker { return false; } + /** + * Returns OTASP_NOT_NEEDED as its not needed for LTE + */ + @Override + int getOtasp() { + int provisioningState = OTASP_NOT_NEEDED; + if (DBG) log("getOtasp: state=" + provisioningState); + return provisioningState; + } + + /** + * Check whether the specified SID and NID pair appears in the HOME SID/NID list + * read from NV or SIM. + * + * @return true if provided sid/nid pair belongs to operator's home network. + */ + private boolean isInHomeSidNid(int sid, int nid) { + // if SID/NID is not available, do not declare roaming. + if (isSidsAllZeros()) return true; + + // length of SID/NID shold be same + if (mHomeSystemId.length != mHomeNetworkId.length) return true; + + if (sid == 0) return true; + + for (int i = 0; i < mHomeSystemId.length; i++) { + // Use SID only if NID is a reserved value. + // SID 0 and NID 0 and 65535 are reserved. (C.0005 2.6.5.2) + if ((mHomeSystemId[i] == sid) && + ((mHomeNetworkId[i] == 0) || (mHomeNetworkId[i] == 65535) || + (nid == 0) || (nid == 65535) || (mHomeNetworkId[i] == nid))) { + return true; + } + } + return false; + } + @Override protected void log(String s) { Log.d(LOG_TAG, "[CdmaLteSST] " + s); @@ -456,8 +504,4 @@ public class CdmaLteServiceStateTracker extends CdmaServiceStateTracker { protected void loge(String s) { Log.e(LOG_TAG, "[CdmaLteSST] " + s); } - - protected static void sloge(String s) { - Log.e(LOG_TAG, "[CdmaLteSST] " + s); - } } diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaLteUiccFileHandler.java b/telephony/java/com/android/internal/telephony/cdma/CdmaLteUiccFileHandler.java index 2aede29e01e0..b9d7c467fa97 100644 --- a/telephony/java/com/android/internal/telephony/cdma/CdmaLteUiccFileHandler.java +++ b/telephony/java/com/android/internal/telephony/cdma/CdmaLteUiccFileHandler.java @@ -19,6 +19,7 @@ package com.android.internal.telephony.cdma; import android.util.Log; import com.android.internal.telephony.IccConstants; import com.android.internal.telephony.IccFileHandler; +import android.os.Message; /** * {@hide} @@ -34,6 +35,10 @@ public final class CdmaLteUiccFileHandler extends IccFileHandler { switch(efid) { case EF_CSIM_SPN: case EF_CSIM_LI: + case EF_CSIM_MDN: + case EF_CSIM_IMSIM: + case EF_CSIM_CDMAHOME: + case EF_CSIM_EPRL: return MF_SIM + DF_CDMA; case EF_AD: return MF_SIM + DF_GSM; @@ -41,6 +46,21 @@ public final class CdmaLteUiccFileHandler extends IccFileHandler { return getCommonIccEFPath(efid); } + @Override + public void loadEFTransparent(int fileid, Message onLoaded) { + if (fileid == EF_CSIM_EPRL) { + // Entire PRL could be huge. We are only interested in + // the first 4 bytes of the record. + phone.mCM.iccIO(COMMAND_READ_BINARY, fileid, getEFPath(fileid), + 0, 0, 4, null, null, + obtainMessage(EVENT_READ_BINARY_DONE, + fileid, 0, onLoaded)); + } else { + super.loadEFTransparent(fileid, onLoaded); + } + } + + protected void logd(String msg) { Log.d(LOG_TAG, "[CdmaLteUiccFileHandler] " + msg); } diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaLteUiccRecords.java b/telephony/java/com/android/internal/telephony/cdma/CdmaLteUiccRecords.java index 78879d690cd1..58ef747b42d0 100755 --- a/telephony/java/com/android/internal/telephony/cdma/CdmaLteUiccRecords.java +++ b/telephony/java/com/android/internal/telephony/cdma/CdmaLteUiccRecords.java @@ -19,6 +19,7 @@ import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OP import com.android.internal.telephony.GsmAlphabet; import com.android.internal.telephony.IccFileHandler; import com.android.internal.telephony.IccUtils; +import com.android.internal.telephony.MccTable; import com.android.internal.telephony.PhoneBase; import com.android.internal.telephony.cdma.sms.UserData; import com.android.internal.telephony.gsm.SIMRecords; @@ -26,7 +27,8 @@ import android.os.AsyncResult; import android.os.Message; import android.os.SystemProperties; import android.util.Log; - +import java.util.Locale; +import java.util.ArrayList; /** * {@hide} @@ -36,10 +38,19 @@ public final class CdmaLteUiccRecords extends SIMRecords { private byte[] mEFpl = null; private byte[] mEFli = null; boolean csimSpnDisplayCondition = false; + private String mMdn; + private String mMin; + private String mPrlVersion; + private String mHomeSystemId; + private String mHomeNetworkId; private static final int EVENT_GET_PL_DONE = CSIM_EVENT_BASE; private static final int EVENT_GET_CSIM_LI_DONE = CSIM_EVENT_BASE + 1; private static final int EVENT_GET_CSIM_SPN_DONE = CSIM_EVENT_BASE + 2; + private static final int EVENT_GET_CSIM_MDN_DONE = CSIM_EVENT_BASE + 3; + private static final int EVENT_GET_CSIM_IMSIM_DONE = CSIM_EVENT_BASE + 4; + private static final int EVENT_GET_CSIM_CDMAHOME_DONE = CSIM_EVENT_BASE + 5; + private static final int EVENT_GET_CSIM_EPRL_DONE = CSIM_EVENT_BASE + 6; public CdmaLteUiccRecords(PhoneBase p) { super(p); @@ -109,6 +120,46 @@ public final class CdmaLteUiccRecords extends SIMRecords { } onGetCSimSpnDone(ar); break; + case EVENT_GET_CSIM_MDN_DONE: + if (DBG) log("EVENT_GET_CSIM_MDN_DONE"); + isCsimRecordLoadResponse = true; + ar = (AsyncResult) msg.obj; + if (ar.exception != null) { + Log.e(LOG_TAG, "ar.exception=" + ar.exception); + break; + } + onGetCSimMdnDone(ar); + break; + case EVENT_GET_CSIM_IMSIM_DONE: + if (DBG) log("EVENT_GET_CSIM_IMSIM_DONE"); + isCsimRecordLoadResponse = true; + ar = (AsyncResult) msg.obj; + if (ar.exception != null) { + Log.e(LOG_TAG, "ar.exception=" + ar.exception); + break; + } + onGetCSimImsimDone(ar); + break; + case EVENT_GET_CSIM_CDMAHOME_DONE: + if (DBG) log("EVENT_GET_CSIM_CDMAHOME_DONE"); + isCsimRecordLoadResponse = true; + ar = (AsyncResult) msg.obj; + if (ar.exception != null) { + Log.e(LOG_TAG, "ar.exception=" + ar.exception); + break; + } + onGetCSimCdmaHomeDone(ar); + break; + case EVENT_GET_CSIM_EPRL_DONE: + if (DBG) log("EVENT_GET_CSIM_EPRL_DONE"); + isCsimRecordLoadResponse = true; + ar = (AsyncResult) msg.obj; + if (ar.exception != null) { + Log.e(LOG_TAG, "ar.exception=" + ar.exception); + break; + } + onGetCSimEprlDone(ar); + break; default: super.handleMessage(msg); }}catch (RuntimeException exc) { @@ -135,6 +186,12 @@ public final class CdmaLteUiccRecords extends SIMRecords { } @Override + protected void onAllRecordsLoaded() { + super.onAllRecordsLoaded(); + setLocaleFromCsim(); + } + + @Override protected void fetchSimRecords() { IccFileHandler iccFh = phone.getIccFileHandler(); recordsRequested = true; @@ -156,6 +213,19 @@ public final class CdmaLteUiccRecords extends SIMRecords { iccFh.loadEFTransparent(EF_CSIM_SPN, obtainMessage(EVENT_GET_CSIM_SPN_DONE)); recordsToLoad++; + + iccFh.loadEFLinearFixed(EF_CSIM_MDN, 1, obtainMessage(EVENT_GET_CSIM_MDN_DONE)); + recordsToLoad++; + + iccFh.loadEFTransparent(EF_CSIM_IMSIM, obtainMessage(EVENT_GET_CSIM_IMSIM_DONE)); + recordsToLoad++; + + iccFh.loadEFLinearFixedAll(EF_CSIM_CDMAHOME, + obtainMessage(EVENT_GET_CSIM_CDMAHOME_DONE)); + recordsToLoad++; + + iccFh.loadEFTransparent(EF_CSIM_EPRL, obtainMessage(EVENT_GET_CSIM_EPRL_DONE)); + recordsToLoad++; } private void onGetCSimSpnDone(AsyncResult ar) { @@ -205,11 +275,172 @@ public final class CdmaLteUiccRecords extends SIMRecords { phone.setSystemProperty(PROPERTY_ICC_OPERATOR_ALPHA, spn); } - public byte[] getPreferredLanguage() { - return mEFpl; + private void onGetCSimMdnDone(AsyncResult ar) { + byte[] data = (byte[]) ar.result; + if (DBG) log("CSIM_MDN=" + IccUtils.bytesToHexString(data)); + int mdnDigitsNum = 0x0F & data[0]; + mMdn = IccUtils.cdmaBcdToString(data, 1, mdnDigitsNum); + if (DBG) log("CSIM MDN=" + mMdn); + } + + private void onGetCSimImsimDone(AsyncResult ar) { + byte[] data = (byte[]) ar.result; + if (DBG) log("CSIM_IMSIM=" + IccUtils.bytesToHexString(data)); + // C.S0065 section 5.2.2 for IMSI_M encoding + // C.S0005 section 2.3.1 for MIN encoding in IMSI_M. + boolean provisioned = ((data[7] & 0x80) == 0x80); + + if (provisioned) { + int first3digits = ((0x03 & data[2]) << 8) + (0xFF & data[1]); + int second3digits = (((0xFF & data[5]) << 8) | (0xFF & data[4])) >> 6; + int digit7 = 0x0F & (data[4] >> 2); + if (digit7 > 0x09) digit7 = 0; + int last3digits = ((0x03 & data[4]) << 8) | (0xFF & data[3]); + first3digits = adjstMinDigits(first3digits); + second3digits = adjstMinDigits(second3digits); + last3digits = adjstMinDigits(last3digits); + + StringBuilder builder = new StringBuilder(); + builder.append(String.format(Locale.US, "%03d", first3digits)); + builder.append(String.format(Locale.US, "%03d", second3digits)); + builder.append(String.format(Locale.US, "%d", digit7)); + builder.append(String.format(Locale.US, "%03d", last3digits)); + if (DBG) log("min present=" + builder.toString()); + + mMin = builder.toString(); + } else { + if (DBG) log("min not present"); + } } - public byte[] getLanguageIndication() { - return mEFli; + private int adjstMinDigits (int digits) { + // Per C.S0005 section 2.3.1. + digits += 111; + digits = (digits % 10 == 0)?(digits - 10):digits; + digits = ((digits / 10) % 10 == 0)?(digits - 100):digits; + digits = ((digits / 100) % 10 == 0)?(digits - 1000):digits; + return digits; + } + + private void onGetCSimCdmaHomeDone(AsyncResult ar) { + // Per C.S0065 section 5.2.8 + ArrayList<byte[]> dataList = (ArrayList<byte[]>) ar.result; + if (DBG) log("CSIM_CDMAHOME data size=" + dataList.size()); + if (dataList.isEmpty()) { + return; + } + StringBuilder sidBuf = new StringBuilder(); + StringBuilder nidBuf = new StringBuilder(); + + for (byte[] data : dataList) { + if (data.length == 5) { + int sid = ((data[1] & 0xFF) << 8) | (data[0] & 0xFF); + int nid = ((data[3] & 0xFF) << 8) | (data[2] & 0xFF); + sidBuf.append(sid).append(","); + nidBuf.append(nid).append(","); + } + } + // remove trailing "," + sidBuf.setLength(sidBuf.length()-1); + nidBuf.setLength(nidBuf.length()-1); + + mHomeSystemId = sidBuf.toString(); + mHomeNetworkId = nidBuf.toString(); + } + + private void onGetCSimEprlDone(AsyncResult ar) { + // C.S0065 section 5.2.57 for EFeprl encoding + // C.S0016 section 3.5.5 for PRL format. + byte[] data = (byte[]) ar.result; + if (DBG) log("CSIM_EPRL=" + IccUtils.bytesToHexString(data)); + + // Only need the first 4 bytes of record + if (data.length > 3) { + int prlId = ((data[2] & 0xFF) << 8) | (data[3] & 0xFF); + mPrlVersion = Integer.toString(prlId); + } + if (DBG) log("CSIM PRL version=" + mPrlVersion); + } + + private void setLocaleFromCsim() { + String prefLang = null; + // check EFli then EFpl + prefLang = findBestLanguage(mEFli); + + if (prefLang == null) { + prefLang = findBestLanguage(mEFpl); + } + + if (prefLang != null) { + // check country code from SIM + String imsi = getIMSI(); + String country = null; + if (imsi != null) { + country = MccTable.countryCodeForMcc( + Integer.parseInt(imsi.substring(0,3))); + } + log("Setting locale to " + prefLang + "_" + country); + phone.setSystemLocale(prefLang, country, false); + } else { + log ("No suitable CSIM selected locale"); + } + } + + private String findBestLanguage(byte[] languages) { + String bestMatch = null; + String[] locales = phone.getContext().getAssets().getLocales(); + + if ((languages == null) || (locales == null)) return null; + + // Each 2-bytes consists of one language + for (int i = 0; (i + 1) < languages.length; i += 2) { + try { + String lang = new String(languages, i, 2, "ISO-8859-1"); + for (int j = 0; j < locales.length; j++) { + if (locales[j] != null && locales[j].length() >= 2 && + locales[j].substring(0, 2).equals(lang)) { + return lang; + } + } + if (bestMatch != null) break; + } catch(java.io.UnsupportedEncodingException e) { + log ("Failed to parse SIM language records"); + } + } + // no match found. return null + return null; + } + + @Override + protected void log(String s) { + if (DBG) Log.d(LOG_TAG, "[CSIM] " + s); + } + + public String getMdn() { + return mMdn; + } + + public String getMin() { + return mMin; + } + + public String getSid() { + return mHomeSystemId; + } + + public String getNid() { + return mHomeNetworkId; + } + + public String getPrlVersion() { + return mPrlVersion; + } + + @Override + public boolean isProvisioned() { + // Look for MDN and MIN field to determine if the SIM is provisioned. + if ((mMdn != null) && (mMin != null)) return true; + + return false; } } diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java b/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java index cf6b78ab020d..29349db646d8 100644 --- a/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java +++ b/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java @@ -273,7 +273,7 @@ final class CdmaSMSDispatcher extends SMSDispatcher { if (cursorCount != totalSegments - 1) { // We don't have all the parts yet, store this one away ContentValues values = new ContentValues(); - values.put("date", new Long(0)); + values.put("date", (long) 0); values.put("pdu", HexDump.toHexString(pdu, index, pdu.length - index)); values.put("address", address); values.put("reference_number", referenceNumber); @@ -482,24 +482,6 @@ final class CdmaSMSDispatcher extends SMSDispatcher { } } - /** {@inheritDoc} */ - @Override - public void activateCellBroadcastSms(int activate, Message response) { - mCm.setCdmaBroadcastActivation((activate == 0), response); - } - - /** {@inheritDoc} */ - @Override - public void getCellBroadcastSmsConfig(Message response) { - mCm.getCdmaBroadcastConfig(response); - } - - /** {@inheritDoc} */ - @Override - public void setCellBroadcastConfig(int[] configValuesArray, Message response) { - mCm.setCdmaBroadcastConfig(configValuesArray, response); - } - protected void handleBroadcastSms(AsyncResult ar) { // Not supported Log.e(TAG, "Error! Not implemented for CDMA."); diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java index ead6bcad370f..e41985ea3978 100755 --- a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java +++ b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java @@ -129,12 +129,12 @@ public class CdmaServiceStateTracker extends ServiceStateTracker { /** Contains the name of the registered network in CDMA (either ONS or ERI text). */ private String curPlmn = null; - private String mMdn; - private int mHomeSystemId[] = null; - private int mHomeNetworkId[] = null; - private String mMin; - private String mPrlVersion; - private boolean mIsMinInfoReady = false; + protected String mMdn; + protected int mHomeSystemId[] = null; + protected int mHomeNetworkId[] = null; + protected String mMin; + protected String mPrlVersion; + protected boolean mIsMinInfoReady = false; private boolean isEriTextLoaded = false; protected boolean isSubscriptionFromRuim = false; @@ -373,53 +373,15 @@ public class CdmaServiceStateTracker extends ServiceStateTracker { String cdmaSubscription[] = (String[])ar.result; if (cdmaSubscription != null && cdmaSubscription.length >= 5) { mMdn = cdmaSubscription[0]; - if (cdmaSubscription[1] != null) { - String[] sid = cdmaSubscription[1].split(","); - mHomeSystemId = new int[sid.length]; - for (int i = 0; i < sid.length; i++) { - try { - mHomeSystemId[i] = Integer.parseInt(sid[i]); - } catch (NumberFormatException ex) { - loge("error parsing system id: " + ex); - } - } - } - if (DBG) log("GET_CDMA_SUBSCRIPTION: SID=" + cdmaSubscription[1] ); - - if (cdmaSubscription[2] != null) { - String[] nid = cdmaSubscription[2].split(","); - mHomeNetworkId = new int[nid.length]; - for (int i = 0; i < nid.length; i++) { - try { - mHomeNetworkId[i] = Integer.parseInt(nid[i]); - } catch (NumberFormatException ex) { - loge("GET_CDMA_SUBSCRIPTION: error parsing network id: " + ex); - } - } - } - if (DBG) log("GET_CDMA_SUBSCRIPTION: NID=" + cdmaSubscription[2]); + parseSidNid(cdmaSubscription[1], cdmaSubscription[2]); + mMin = cdmaSubscription[3]; mPrlVersion = cdmaSubscription[4]; if (DBG) log("GET_CDMA_SUBSCRIPTION: MDN=" + mMdn); mIsMinInfoReady = true; - int otaspMode = getOtasp(); - int oldOtaspMode = mCurrentOtaspMode; - mCurrentOtaspMode = otaspMode; - - // Notify apps subscription info is ready - if (cdmaForSubscriptionInfoReadyRegistrants != null) { - if (DBG) log("GET_CDMA_SUBSCRIPTION: call notifyRegistrants()"); - cdmaForSubscriptionInfoReadyRegistrants.notifyRegistrants(); - } - if (oldOtaspMode != mCurrentOtaspMode) { - if (DBG) { - log("GET_CDMA_SUBSCRIPTION: call notifyOtaspChanged old otaspMode=" + - oldOtaspMode + " new otaspMode=" + mCurrentOtaspMode); - } - phone.notifyOtaspChanged(mCurrentOtaspMode); - } + updateOtaspState(); phone.getIccCard().broadcastIccStateChangedIntent(IccCard.INTENT_VALUE_ICC_IMSI, null); } else { @@ -1519,7 +1481,7 @@ public class CdmaServiceStateTracker extends ServiceStateTracker { } } - private boolean isSidsAllZeros() { + protected boolean isSidsAllZeros() { if (mHomeSystemId != null) { for (int i=0; i < mHomeSystemId.length; i++) { if (mHomeSystemId[i] != 0) { @@ -1622,6 +1584,53 @@ public class CdmaServiceStateTracker extends ServiceStateTracker { cm.setRadioPower(false, null); } + protected void parseSidNid (String sidStr, String nidStr) { + if (sidStr != null) { + String[] sid = sidStr.split(","); + mHomeSystemId = new int[sid.length]; + for (int i = 0; i < sid.length; i++) { + try { + mHomeSystemId[i] = Integer.parseInt(sid[i]); + } catch (NumberFormatException ex) { + loge("error parsing system id: " + ex); + } + } + } + if (DBG) log("CDMA_SUBSCRIPTION: SID=" + sidStr); + + if (nidStr != null) { + String[] nid = nidStr.split(","); + mHomeNetworkId = new int[nid.length]; + for (int i = 0; i < nid.length; i++) { + try { + mHomeNetworkId[i] = Integer.parseInt(nid[i]); + } catch (NumberFormatException ex) { + loge("CDMA_SUBSCRIPTION: error parsing network id: " + ex); + } + } + } + if (DBG) log("CDMA_SUBSCRIPTION: NID=" + nidStr); + } + + protected void updateOtaspState() { + int otaspMode = getOtasp(); + int oldOtaspMode = mCurrentOtaspMode; + mCurrentOtaspMode = otaspMode; + + // Notify apps subscription info is ready + if (cdmaForSubscriptionInfoReadyRegistrants != null) { + if (DBG) log("CDMA_SUBSCRIPTION: call notifyRegistrants()"); + cdmaForSubscriptionInfoReadyRegistrants.notifyRegistrants(); + } + if (oldOtaspMode != mCurrentOtaspMode) { + if (DBG) { + log("CDMA_SUBSCRIPTION: call notifyOtaspChanged old otaspMode=" + + oldOtaspMode + " new otaspMode=" + mCurrentOtaspMode); + } + phone.notifyOtaspChanged(mCurrentOtaspMode); + } + } + @Override protected void log(String s) { Log.d(LOG_TAG, "[CdmaSST] " + s); @@ -1631,8 +1640,4 @@ public class CdmaServiceStateTracker extends ServiceStateTracker { protected void loge(String s) { Log.e(LOG_TAG, "[CdmaSST] " + s); } - - private static void slog(String s) { - Log.d(LOG_TAG, "[CdmaSST] " + s); - } } diff --git a/telephony/java/com/android/internal/telephony/cdma/RuimSmsInterfaceManager.java b/telephony/java/com/android/internal/telephony/cdma/RuimSmsInterfaceManager.java index 29f3bc1942a8..9cd059d3e397 100644 --- a/telephony/java/com/android/internal/telephony/cdma/RuimSmsInterfaceManager.java +++ b/telephony/java/com/android/internal/telephony/cdma/RuimSmsInterfaceManager.java @@ -203,6 +203,18 @@ public class RuimSmsInterfaceManager extends IccSmsInterfaceManager { return false; } + public boolean enableCellBroadcastRange(int startMessageId, int endMessageId) { + // Not implemented + Log.e(LOG_TAG, "Error! Not implemented for CDMA."); + return false; + } + + public boolean disableCellBroadcastRange(int startMessageId, int endMessageId) { + // Not implemented + Log.e(LOG_TAG, "Error! Not implemented for CDMA."); + return false; + } + protected void log(String msg) { Log.d(LOG_TAG, "[RuimSmsInterfaceManager] " + msg); } diff --git a/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java b/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java index 3ccc03d680b8..d357eacf5d1b 100644 --- a/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java +++ b/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java @@ -301,6 +301,9 @@ public class GSMPhone extends PhoneBase { ret = DataState.DISCONNECTED; } else if (mDataConnectionTracker.isApnTypeEnabled(apnType) == false || mDataConnectionTracker.isApnTypeActive(apnType) == false) { + //TODO: isApnTypeActive() is just checking whether ApnContext holds + // Dataconnection or not. Checking each ApnState below should + // provide the same state. Calling isApnTypeActive() can be removed. ret = DataState.DISCONNECTED; } else { /* mSST.gprsState == ServiceState.STATE_IN_SERVICE */ switch (mDataConnectionTracker.getState(apnType)) { @@ -1427,16 +1430,35 @@ public class GSMPhone extends PhoneBase { return this.mIccFileHandler; } + /** + * Activate or deactivate cell broadcast SMS. + * + * @param activate 0 = activate, 1 = deactivate + * @param response Callback message is empty on completion + */ public void activateCellBroadcastSms(int activate, Message response) { - Log.e(LOG_TAG, "Error! This functionality is not implemented for GSM."); + Log.e(LOG_TAG, "[GSMPhone] activateCellBroadcastSms() is obsolete; use SmsManager"); + response.sendToTarget(); } + /** + * Query the current configuration of cdma cell broadcast SMS. + * + * @param response Callback message is empty on completion + */ public void getCellBroadcastSmsConfig(Message response) { - Log.e(LOG_TAG, "Error! This functionality is not implemented for GSM."); + Log.e(LOG_TAG, "[GSMPhone] getCellBroadcastSmsConfig() is obsolete; use SmsManager"); + response.sendToTarget(); } - public void setCellBroadcastSmsConfig(int[] configValuesArray, Message response){ - Log.e(LOG_TAG, "Error! This functionality is not implemented for GSM."); + /** + * Configure cdma cell broadcast SMS. + * + * @param response Callback message is empty on completion + */ + public void setCellBroadcastSmsConfig(int[] configValuesArray, Message response) { + Log.e(LOG_TAG, "[GSMPhone] setCellBroadcastSmsConfig() is obsolete; use SmsManager"); + response.sendToTarget(); } public boolean isCspPlmnEnabled() { diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java index db2b4903073b..dcde71a50925 100644 --- a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java +++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java @@ -561,6 +561,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { boolean allowed = (gprsState == ServiceState.STATE_IN_SERVICE || mAutoAttachOnCreation) && mPhone.mIccRecords.getRecordsLoaded() && + mPhone.mIccRecords.isProvisioned() && mPhone.getState() == Phone.State.IDLE && mInternalDataEnabled && (!mPhone.getServiceState().getRoaming() || getDataOnRoamingEnabled()) && @@ -572,6 +573,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { reason += " - gprs= " + gprsState; } if (!mPhone.mIccRecords.getRecordsLoaded()) reason += " - SIM not loaded"; + if (!mPhone.mIccRecords.isProvisioned()) reason += " - SIM not provisioned"; if (mPhone.getState() != Phone.State.IDLE) { reason += " - PhoneState= " + mPhone.getState(); } diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java b/telephony/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java index b021967c6112..52ca45304714 100755..100644 --- a/telephony/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java +++ b/telephony/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java @@ -391,30 +391,6 @@ final class GsmSMSDispatcher extends SMSDispatcher { } } - /** {@inheritDoc} */ - @Override - public void activateCellBroadcastSms(int activate, Message response) { - // Unless CBS is implemented for GSM, this point should be unreachable. - Log.e(TAG, "Error! The functionality cell broadcast sms is not implemented for GSM."); - response.recycle(); - } - - /** {@inheritDoc} */ - @Override - public void getCellBroadcastSmsConfig(Message response){ - // Unless CBS is implemented for GSM, this point should be unreachable. - Log.e(TAG, "Error! The functionality cell broadcast sms is not implemented for GSM."); - response.recycle(); - } - - /** {@inheritDoc} */ - @Override - public void setCellBroadcastConfig(int[] configValuesArray, Message response) { - // Unless CBS is implemented for GSM, this point should be unreachable. - Log.e(TAG, "Error! The functionality cell broadcast sms is not implemented for GSM."); - response.recycle(); - } - private int resultToCause(int rc) { switch (rc) { case Activity.RESULT_OK: @@ -506,9 +482,10 @@ final class GsmSMSDispatcher extends SMSDispatcher { } // This map holds incomplete concatenated messages waiting for assembly - private HashMap<SmsCbConcatInfo, byte[][]> mSmsCbPageMap = + private final HashMap<SmsCbConcatInfo, byte[][]> mSmsCbPageMap = new HashMap<SmsCbConcatInfo, byte[][]>(); + @Override protected void handleBroadcastSms(AsyncResult ar) { try { byte[][] pdus = null; @@ -520,9 +497,9 @@ final class GsmSMSDispatcher extends SMSDispatcher { for (int j = i; j < i + 8 && j < receivedPdu.length; j++) { int b = receivedPdu[j] & 0xff; if (b < 0x10) { - sb.append("0"); + sb.append('0'); } - sb.append(Integer.toHexString(b)).append(" "); + sb.append(Integer.toHexString(b)).append(' '); } Log.d(TAG, sb.toString()); } @@ -567,7 +544,8 @@ final class GsmSMSDispatcher extends SMSDispatcher { pdus[0] = receivedPdu; } - dispatchBroadcastPdus(pdus); + boolean isEmergencyMessage = SmsCbHeader.isEmergencyMessage(header.messageIdentifier); + dispatchBroadcastPdus(pdus, isEmergencyMessage); // Remove messages that are out of scope to prevent the map from // growing indefinitely, containing incomplete messages that were diff --git a/telephony/java/com/android/internal/telephony/gsm/SimSmsInterfaceManager.java b/telephony/java/com/android/internal/telephony/gsm/SimSmsInterfaceManager.java index 5abba6e9fe8c..8d0e5d3eefda 100644 --- a/telephony/java/com/android/internal/telephony/gsm/SimSmsInterfaceManager.java +++ b/telephony/java/com/android/internal/telephony/gsm/SimSmsInterfaceManager.java @@ -27,6 +27,7 @@ import android.util.Log; import com.android.internal.telephony.IccConstants; import com.android.internal.telephony.IccSmsInterfaceManager; import com.android.internal.telephony.IccUtils; +import com.android.internal.telephony.IntRangeManager; import com.android.internal.telephony.SMSDispatcher; import com.android.internal.telephony.SmsRawData; @@ -53,6 +54,9 @@ public class SimSmsInterfaceManager extends IccSmsInterfaceManager { private HashMap<Integer, HashSet<String>> mCellBroadcastSubscriptions = new HashMap<Integer, HashSet<String>>(); + private CellBroadcastRangeManager mCellBroadcastRangeManager = + new CellBroadcastRangeManager(); + private static final int EVENT_LOAD_DONE = 1; private static final int EVENT_UPDATE_DONE = 2; private static final int EVENT_SET_BROADCAST_ACTIVATION_DONE = 3; @@ -213,7 +217,15 @@ public class SimSmsInterfaceManager extends IccSmsInterfaceManager { } public boolean enableCellBroadcast(int messageIdentifier) { - if (DBG) log("enableCellBroadcast"); + return enableCellBroadcastRange(messageIdentifier, messageIdentifier); + } + + public boolean disableCellBroadcast(int messageIdentifier) { + return disableCellBroadcastRange(messageIdentifier, messageIdentifier); + } + + public boolean enableCellBroadcastRange(int startMessageId, int endMessageId) { + if (DBG) log("enableCellBroadcastRange"); Context context = mPhone.getContext(); @@ -223,30 +235,22 @@ public class SimSmsInterfaceManager extends IccSmsInterfaceManager { String client = context.getPackageManager().getNameForUid( Binder.getCallingUid()); - HashSet<String> clients = mCellBroadcastSubscriptions.get(messageIdentifier); - - if (clients == null) { - // This is a new message identifier - clients = new HashSet<String>(); - mCellBroadcastSubscriptions.put(messageIdentifier, clients); - if (!updateCellBroadcastConfig()) { - mCellBroadcastSubscriptions.remove(messageIdentifier); - return false; - } + if (!mCellBroadcastRangeManager.enableRange(startMessageId, endMessageId, client)) { + log("Failed to add cell broadcast subscription for MID range " + startMessageId + + " to " + endMessageId + " from client " + client); + return false; } - clients.add(client); - if (DBG) - log("Added cell broadcast subscription for MID " + messageIdentifier - + " from client " + client); + log("Added cell broadcast subscription for MID range " + startMessageId + + " to " + endMessageId + " from client " + client); return true; } - public boolean disableCellBroadcast(int messageIdentifier) { - if (DBG) log("disableCellBroadcast"); + public boolean disableCellBroadcastRange(int startMessageId, int endMessageId) { + if (DBG) log("disableCellBroadcastRange"); Context context = mPhone.getContext(); @@ -256,39 +260,56 @@ public class SimSmsInterfaceManager extends IccSmsInterfaceManager { String client = context.getPackageManager().getNameForUid( Binder.getCallingUid()); - HashSet<String> clients = mCellBroadcastSubscriptions.get(messageIdentifier); - if (clients != null && clients.remove(client)) { - if (DBG) - log("Removed cell broadcast subscription for MID " + messageIdentifier - + " from client " + client); - - if (clients.isEmpty()) { - mCellBroadcastSubscriptions.remove(messageIdentifier); - updateCellBroadcastConfig(); - } - return true; + if (!mCellBroadcastRangeManager.disableRange(startMessageId, endMessageId, client)) { + log("Failed to remove cell broadcast subscription for MID range " + startMessageId + + " to " + endMessageId + " from client " + client); + return false; } - return false; + if (DBG) + log("Removed cell broadcast subscription for MID range " + startMessageId + + " to " + endMessageId + " from client " + client); + + return true; } - private boolean updateCellBroadcastConfig() { - Set<Integer> messageIdentifiers = mCellBroadcastSubscriptions.keySet(); + class CellBroadcastRangeManager extends IntRangeManager { + private ArrayList<SmsBroadcastConfigInfo> mConfigList = + new ArrayList<SmsBroadcastConfigInfo>(); + + /** + * Called when the list of enabled ranges has changed. This will be + * followed by zero or more calls to {@link #addRange} followed by + * a call to {@link #finishUpdate}. + */ + protected void startUpdate() { + mConfigList.clear(); + } - if (messageIdentifiers.size() > 0) { - SmsBroadcastConfigInfo[] configs = - new SmsBroadcastConfigInfo[messageIdentifiers.size()]; - int i = 0; + /** + * Called after {@link #startUpdate} to indicate a range of enabled + * values. + * @param startId the first id included in the range + * @param endId the last id included in the range + */ + protected void addRange(int startId, int endId, boolean selected) { + mConfigList.add(new SmsBroadcastConfigInfo(startId, endId, + SMS_CB_CODE_SCHEME_MIN, SMS_CB_CODE_SCHEME_MAX, selected)); + } - for (int messageIdentifier : messageIdentifiers) { - configs[i++] = new SmsBroadcastConfigInfo(messageIdentifier, messageIdentifier, - SMS_CB_CODE_SCHEME_MIN, SMS_CB_CODE_SCHEME_MAX, true); + /** + * Called to indicate the end of a range update started by the + * previous call to {@link #startUpdate}. + */ + protected boolean finishUpdate() { + if (mConfigList.isEmpty()) { + return setCellBroadcastActivation(false); + } else { + SmsBroadcastConfigInfo[] configs = + mConfigList.toArray(new SmsBroadcastConfigInfo[mConfigList.size()]); + return setCellBroadcastConfig(configs) && setCellBroadcastActivation(true); } - - return setCellBroadcastConfig(configs) && setCellBroadcastActivation(true); - } else { - return setCellBroadcastActivation(false); } } @@ -314,7 +335,7 @@ public class SimSmsInterfaceManager extends IccSmsInterfaceManager { private boolean setCellBroadcastActivation(boolean activate) { if (DBG) - log("Calling setCellBroadcastActivation(" + activate + ")"); + log("Calling setCellBroadcastActivation(" + activate + ')'); synchronized (mLock) { Message response = mHandler.obtainMessage(EVENT_SET_BROADCAST_ACTIVATION_DONE); diff --git a/telephony/java/com/android/internal/telephony/gsm/SmsBroadcastConfigInfo.java b/telephony/java/com/android/internal/telephony/gsm/SmsBroadcastConfigInfo.java index 45f50bc49fb1..66e7ce0783cf 100644 --- a/telephony/java/com/android/internal/telephony/gsm/SmsBroadcastConfigInfo.java +++ b/telephony/java/com/android/internal/telephony/gsm/SmsBroadcastConfigInfo.java @@ -30,11 +30,11 @@ package com.android.internal.telephony.gsm; * and 9.4.4.2.3 for UMTS. * All other values can be treated as empty CBM data coding scheme. * - * selected false means message types specified in <fromServiceId, toServiceId> - * and <fromCodeScheme, toCodeScheme>are not accepted, while true means accepted. + * selected false means message types specified in {@code <fromServiceId, toServiceId>} + * and {@code <fromCodeScheme, toCodeScheme>} are not accepted, while true means accepted. * */ -public class SmsBroadcastConfigInfo { +public final class SmsBroadcastConfigInfo { private int fromServiceId; private int toServiceId; private int fromCodeScheme; @@ -46,11 +46,11 @@ public class SmsBroadcastConfigInfo { */ public SmsBroadcastConfigInfo(int fromId, int toId, int fromScheme, int toScheme, boolean selected) { - setFromServiceId(fromId); - setToServiceId(toId); - setFromCodeScheme(fromScheme); - setToCodeScheme(toScheme); - this.setSelected(selected); + fromServiceId = fromId; + toServiceId = toId; + fromCodeScheme = fromScheme; + toCodeScheme = toScheme; + this.selected = selected; } /** @@ -126,8 +126,8 @@ public class SmsBroadcastConfigInfo { @Override public String toString() { return "SmsBroadcastConfigInfo: Id [" + - getFromServiceId() + "," + getToServiceId() + "] Code [" + - getFromCodeScheme() + "," + getToCodeScheme() + "] " + - (isSelected() ? "ENABLED" : "DISABLED"); + fromServiceId + ',' + toServiceId + "] Code [" + + fromCodeScheme + ',' + toCodeScheme + "] " + + (selected ? "ENABLED" : "DISABLED"); } -}
\ No newline at end of file +} diff --git a/telephony/java/com/android/internal/telephony/gsm/SmsCbHeader.java b/telephony/java/com/android/internal/telephony/gsm/SmsCbHeader.java index 0945a3812530..8e6b79b322da 100644 --- a/telephony/java/com/android/internal/telephony/gsm/SmsCbHeader.java +++ b/telephony/java/com/android/internal/telephony/gsm/SmsCbHeader.java @@ -16,7 +16,9 @@ package com.android.internal.telephony.gsm; -public class SmsCbHeader { +import android.telephony.SmsCbConstants; + +public class SmsCbHeader implements SmsCbConstants { /** * Length of SMS-CB header */ @@ -33,6 +35,11 @@ public class SmsCbHeader { public static final int FORMAT_UMTS = 2; /** + * GSM pdu format, as defined in 3gpp TS 23.041, section 9.4.1.3 + */ + public static final int FORMAT_ETWS_PRIMARY = 3; + + /** * Message type value as defined in 3gpp TS 25.324, section 11.1. */ private static final int MESSAGE_TYPE_CBS_MESSAGE = 1; @@ -40,7 +47,12 @@ public class SmsCbHeader { /** * Length of GSM pdus */ - private static final int PDU_LENGTH_GSM = 88; + public static final int PDU_LENGTH_GSM = 88; + + /** + * Maximum length of ETWS primary message GSM pdus + */ + public static final int PDU_LENGTH_ETWS = 56; public final int geographicalScope; @@ -58,12 +70,30 @@ public class SmsCbHeader { public final int format; + public final boolean etwsEmergencyUserAlert; + + public final boolean etwsPopup; + + public final int etwsWarningType; + public SmsCbHeader(byte[] pdu) throws IllegalArgumentException { if (pdu == null || pdu.length < PDU_HEADER_LENGTH) { throw new IllegalArgumentException("Illegal PDU"); } - if (pdu.length <= PDU_LENGTH_GSM) { + if (pdu.length <= PDU_LENGTH_ETWS) { + format = FORMAT_ETWS_PRIMARY; + geographicalScope = -1; //not applicable + messageCode = -1; + updateNumber = -1; + messageIdentifier = ((pdu[2] & 0xff) << 8) | (pdu[3] & 0xff); + dataCodingScheme = -1; + pageIndex = -1; + nrOfPages = -1; + etwsEmergencyUserAlert = (pdu[4] & 0x1) != 0; + etwsPopup = (pdu[5] & 0x80) != 0; + etwsWarningType = (pdu[4] & 0xfe) >> 1; + } else if (pdu.length <= PDU_LENGTH_GSM) { // GSM pdus are no more than 88 bytes format = FORMAT_GSM; geographicalScope = (pdu[0] & 0xc0) >> 6; @@ -83,6 +113,9 @@ public class SmsCbHeader { this.pageIndex = pageIndex; this.nrOfPages = nrOfPages; + etwsEmergencyUserAlert = false; + etwsPopup = false; + etwsWarningType = -1; } else { // UMTS pdus are always at least 90 bytes since the payload includes // a number-of-pages octet and also one length octet per page @@ -105,6 +138,77 @@ public class SmsCbHeader { // actual payload may contain several pages. pageIndex = 1; nrOfPages = 1; + etwsEmergencyUserAlert = false; + etwsPopup = false; + etwsWarningType = -1; } } + + /** + * Return whether the specified message ID is an emergency (PWS) message type. + * This method is static and takes an argument so that it can be used by + * CellBroadcastReceiver, which stores message ID's in SQLite rather than PDU. + * @param id the message identifier to check + * @return true if the message is emergency type; false otherwise + */ + public static boolean isEmergencyMessage(int id) { + return id >= MESSAGE_ID_PWS_FIRST_IDENTIFIER && id <= MESSAGE_ID_PWS_LAST_IDENTIFIER; + } + + /** + * Return whether the specified message ID is an ETWS emergency message type. + * This method is static and takes an argument so that it can be used by + * CellBroadcastReceiver, which stores message ID's in SQLite rather than PDU. + * @param id the message identifier to check + * @return true if the message is ETWS emergency type; false otherwise + */ + public static boolean isEtwsMessage(int id) { + return (id & MESSAGE_ID_ETWS_TYPE_MASK) == MESSAGE_ID_ETWS_TYPE; + } + + /** + * Return whether the specified message ID is a CMAS emergency message type. + * This method is static and takes an argument so that it can be used by + * CellBroadcastReceiver, which stores message ID's in SQLite rather than PDU. + * @param id the message identifier to check + * @return true if the message is CMAS emergency type; false otherwise + */ + public static boolean isCmasMessage(int id) { + return id >= MESSAGE_ID_CMAS_FIRST_IDENTIFIER && id <= MESSAGE_ID_CMAS_LAST_IDENTIFIER; + } + + /** + * Return whether the specified message code indicates an ETWS popup alert. + * This method is static and takes an argument so that it can be used by + * CellBroadcastReceiver, which stores message codes in SQLite rather than PDU. + * This method assumes that the message ID has already been checked for ETWS type. + * + * @param messageCode the message code to check + * @return true if the message code indicates a popup alert should be displayed + */ + public static boolean isEtwsPopupAlert(int messageCode) { + return (messageCode & MESSAGE_CODE_ETWS_ACTIVATE_POPUP) != 0; + } + + /** + * Return whether the specified message code indicates an ETWS emergency user alert. + * This method is static and takes an argument so that it can be used by + * CellBroadcastReceiver, which stores message codes in SQLite rather than PDU. + * This method assumes that the message ID has already been checked for ETWS type. + * + * @param messageCode the message code to check + * @return true if the message code indicates an emergency user alert + */ + public static boolean isEtwsEmergencyUserAlert(int messageCode) { + return (messageCode & MESSAGE_CODE_ETWS_EMERGENCY_USER_ALERT) != 0; + } + + @Override + public String toString() { + return "SmsCbHeader{GS=" + geographicalScope + ", messageCode=0x" + + Integer.toHexString(messageCode) + ", updateNumber=" + updateNumber + + ", messageIdentifier=0x" + Integer.toHexString(messageIdentifier) + + ", DCS=0x" + Integer.toHexString(dataCodingScheme) + + ", page " + pageIndex + " of " + nrOfPages + '}'; + } } diff --git a/telephony/tests/telephonytests/src/com/android/internal/telephony/GsmSmsCbTest.java b/telephony/tests/telephonytests/src/com/android/internal/telephony/GsmSmsCbTest.java index b131a0145cb1..417aac4cca92 100644 --- a/telephony/tests/telephonytests/src/com/android/internal/telephony/GsmSmsCbTest.java +++ b/telephony/tests/telephonytests/src/com/android/internal/telephony/GsmSmsCbTest.java @@ -18,6 +18,7 @@ package com.android.internal.telephony; import android.telephony.SmsCbMessage; import android.test.AndroidTestCase; +import android.util.Log; /** * Test cases for basic SmsCbMessage operations @@ -663,4 +664,49 @@ public class GsmSmsCbTest extends AndroidTestCase { assertEquals("Unexpected update number decoded", 5, msg.getUpdateNumber()); } + + /* ETWS Test message including header */ + private static final byte[] etwsMessageNormal = IccUtils.hexStringToBytes("000011001101" + + "0D0A5BAE57CE770C531790E85C716CBF3044573065B930675730" + + "9707767A751F30025F37304463FA308C306B5099304830664E0B30553044FF086C178C615E81FF09" + + "0000000000000000000000000000"); + + private static final byte[] etwsMessageCancel = IccUtils.hexStringToBytes("000011001101" + + "0D0A5148307B3069002800310030003A0035" + + "00320029306E7DCA602557309707901F5831309253D66D883057307E3059FF086C178C615E81FF09" + + "00000000000000000000000000000000000000000000"); + + private static final byte[] etwsMessageTest = IccUtils.hexStringToBytes("000011031101" + + "0D0A5BAE57CE770C531790E85C716CBF3044" + + "573065B9306757309707300263FA308C306B5099304830664E0B30553044FF086C178C615E81FF09" + + "00000000000000000000000000000000000000000000"); + + // FIXME: add example of ETWS primary notification PDU + + public void testEtwsMessageNormal() { + SmsCbMessage msg = SmsCbMessage.createFromPdu(etwsMessageNormal); + Log.d("GsmSmsCbTest", msg.toString()); + assertEquals("GS mismatch", 0, msg.getGeographicalScope()); + assertEquals("message code mismatch", 0, msg.getMessageCode()); + assertEquals("update number mismatch", 0, msg.getUpdateNumber()); + assertEquals("message ID mismatch", 0x1100, msg.getMessageIdentifier()); + } + + public void testEtwsMessageCancel() { + SmsCbMessage msg = SmsCbMessage.createFromPdu(etwsMessageCancel); + Log.d("GsmSmsCbTest", msg.toString()); + assertEquals("GS mismatch", 0, msg.getGeographicalScope()); + assertEquals("message code mismatch", 0, msg.getMessageCode()); + assertEquals("update number mismatch", 0, msg.getUpdateNumber()); + assertEquals("message ID mismatch", 0x1100, msg.getMessageIdentifier()); + } + + public void testEtwsMessageTest() { + SmsCbMessage msg = SmsCbMessage.createFromPdu(etwsMessageTest); + Log.d("GsmSmsCbTest", msg.toString()); + assertEquals("GS mismatch", 0, msg.getGeographicalScope()); + assertEquals("message code mismatch", 0, msg.getMessageCode()); + assertEquals("update number mismatch", 0, msg.getUpdateNumber()); + assertEquals("message ID mismatch", 0x1103, msg.getMessageIdentifier()); + } } diff --git a/telephony/tests/telephonytests/src/com/android/internal/telephony/IntRangeManagerTest.java b/telephony/tests/telephonytests/src/com/android/internal/telephony/IntRangeManagerTest.java new file mode 100644 index 000000000000..79dca39f156b --- /dev/null +++ b/telephony/tests/telephonytests/src/com/android/internal/telephony/IntRangeManagerTest.java @@ -0,0 +1,374 @@ +/* + * 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.telephony; + +import android.test.AndroidTestCase; + +import com.android.internal.telephony.gsm.SmsBroadcastConfigInfo; + +import java.util.ArrayList; + +/** + * Test cases for the IntRangeManager class. + */ +public class IntRangeManagerTest extends AndroidTestCase { + + private static final int SMS_CB_CODE_SCHEME_MIN = 0; + private static final int SMS_CB_CODE_SCHEME_MAX = 255; + + private static final int FLAG_START_UPDATE_CALLED = 0x01; + private static final int FLAG_ADD_RANGE_CALLED = 0x02; + private static final int FLAG_FINISH_UPDATE_CALLED = 0x04; + + private static final int ALL_FLAGS_SET = FLAG_START_UPDATE_CALLED | FLAG_ADD_RANGE_CALLED | + FLAG_FINISH_UPDATE_CALLED; + + /** Dummy IntRangeManager for testing. */ + class TestIntRangeManager extends IntRangeManager { + ArrayList<SmsBroadcastConfigInfo> mConfigList = + new ArrayList<SmsBroadcastConfigInfo>(); + + int flags; + boolean finishUpdateReturnValue = true; + + /** + * Called when the list of enabled ranges has changed. This will be + * followed by zero or more calls to {@link #addRange} followed by + * a call to {@link #finishUpdate}. + */ + protected void startUpdate() { + mConfigList.clear(); + flags |= FLAG_START_UPDATE_CALLED; + } + + /** + * Called after {@link #startUpdate} to indicate a range of enabled + * values. + * @param startId the first id included in the range + * @param endId the last id included in the range + */ + protected void addRange(int startId, int endId, boolean selected) { + mConfigList.add(new SmsBroadcastConfigInfo(startId, endId, + SMS_CB_CODE_SCHEME_MIN, SMS_CB_CODE_SCHEME_MAX, selected)); + flags |= FLAG_ADD_RANGE_CALLED; + } + + /** + * Called to indicate the end of a range update started by the + * previous call to {@link #startUpdate}. + */ + protected boolean finishUpdate() { + flags |= FLAG_FINISH_UPDATE_CALLED; + return finishUpdateReturnValue; + } + + /** Reset the object for the next test case. */ + void reset() { + flags = 0; + mConfigList.clear(); + } + } + + public void testEmptyRangeManager() { + TestIntRangeManager testManager = new TestIntRangeManager(); + assertEquals("expecting empty configlist", 0, testManager.mConfigList.size()); + } + + private void checkConfigInfo(SmsBroadcastConfigInfo info, int fromServiceId, + int toServiceId, int fromCodeScheme, int toCodeScheme, boolean selected) { + assertEquals("fromServiceId", fromServiceId, info.getFromServiceId()); + assertEquals("toServiceId", toServiceId, info.getToServiceId()); + assertEquals("fromCodeScheme", fromCodeScheme, info.getFromCodeScheme()); + assertEquals("toCodeScheme", toCodeScheme, info.getToCodeScheme()); + assertEquals("selected", selected, info.isSelected()); + } + + public void testAddSingleChannel() { + TestIntRangeManager testManager = new TestIntRangeManager(); + assertEquals("flags before test", 0, testManager.flags); + assertTrue("enabling range", testManager.enableRange(123, 123, "client1")); + assertEquals("flags after test", ALL_FLAGS_SET, testManager.flags); + assertEquals("configlist size", 1, testManager.mConfigList.size()); + checkConfigInfo(testManager.mConfigList.get(0), 123, 123, SMS_CB_CODE_SCHEME_MIN, + SMS_CB_CODE_SCHEME_MAX, true); + testManager.reset(); + assertTrue("updating ranges", testManager.updateRanges()); + assertEquals("flags after test", ALL_FLAGS_SET, testManager.flags); + assertEquals("configlist size", 1, testManager.mConfigList.size()); + checkConfigInfo(testManager.mConfigList.get(0), 123, 123, SMS_CB_CODE_SCHEME_MIN, + SMS_CB_CODE_SCHEME_MAX, true); + } + + public void testRemoveSingleChannel() { + TestIntRangeManager testManager = new TestIntRangeManager(); + assertTrue("enabling range", testManager.enableRange(123, 123, "client1")); + assertEquals("flags after enable", ALL_FLAGS_SET, testManager.flags); + assertEquals("configlist size", 1, testManager.mConfigList.size()); + testManager.reset(); + assertTrue("disabling range", testManager.disableRange(123, 123, "client1")); + assertEquals("flags after test", ALL_FLAGS_SET, testManager.flags); + assertEquals("configlist size", 1, testManager.mConfigList.size()); + checkConfigInfo(testManager.mConfigList.get(0), 123, 123, SMS_CB_CODE_SCHEME_MIN, + SMS_CB_CODE_SCHEME_MAX, false); + testManager.reset(); + assertTrue("updating ranges", testManager.updateRanges()); + assertEquals("flags after test", FLAG_START_UPDATE_CALLED | FLAG_FINISH_UPDATE_CALLED, + testManager.flags); + assertEquals("configlist size", 0, testManager.mConfigList.size()); + } + + public void testRemoveBadChannel() { + TestIntRangeManager testManager = new TestIntRangeManager(); + assertFalse("disabling missing range", testManager.disableRange(123, 123, "client1")); + assertEquals("flags after test", 0, testManager.flags); + assertEquals("configlist size", 0, testManager.mConfigList.size()); + } + + public void testAddTwoChannels() { + TestIntRangeManager testManager = new TestIntRangeManager(); + assertEquals("flags before test", 0, testManager.flags); + assertTrue("enabling range 1", testManager.enableRange(100, 120, "client1")); + assertEquals("flags after test", ALL_FLAGS_SET, testManager.flags); + assertEquals("configlist size", 1, testManager.mConfigList.size()); + checkConfigInfo(testManager.mConfigList.get(0), 100, 120, SMS_CB_CODE_SCHEME_MIN, + SMS_CB_CODE_SCHEME_MAX, true); + testManager.reset(); + assertTrue("enabling range 2", testManager.enableRange(200, 250, "client2")); + assertEquals("flags after test", ALL_FLAGS_SET, testManager.flags); + assertEquals("configlist size", 1, testManager.mConfigList.size()); + checkConfigInfo(testManager.mConfigList.get(0), 200, 250, SMS_CB_CODE_SCHEME_MIN, + SMS_CB_CODE_SCHEME_MAX, true); + testManager.reset(); + assertTrue("updating ranges", testManager.updateRanges()); + assertEquals("flags after test", ALL_FLAGS_SET, testManager.flags); + assertEquals("configlist size", 2, testManager.mConfigList.size()); + checkConfigInfo(testManager.mConfigList.get(0), 100, 120, SMS_CB_CODE_SCHEME_MIN, + SMS_CB_CODE_SCHEME_MAX, true); + checkConfigInfo(testManager.mConfigList.get(1), 200, 250, SMS_CB_CODE_SCHEME_MIN, + SMS_CB_CODE_SCHEME_MAX, true); + } + + public void testOverlappingChannels() { + TestIntRangeManager testManager = new TestIntRangeManager(); + assertEquals("flags before test", 0, testManager.flags); + assertTrue("enabling range 1", testManager.enableRange(100, 200, "client1")); + assertEquals("flags after test", ALL_FLAGS_SET, testManager.flags); + assertEquals("configlist size", 1, testManager.mConfigList.size()); + checkConfigInfo(testManager.mConfigList.get(0), 100, 200, SMS_CB_CODE_SCHEME_MIN, + SMS_CB_CODE_SCHEME_MAX, true); + testManager.reset(); + assertTrue("enabling range 2", testManager.enableRange(150, 250, "client2")); + assertEquals("flags after test", ALL_FLAGS_SET, testManager.flags); + assertEquals("configlist size", 1, testManager.mConfigList.size()); + checkConfigInfo(testManager.mConfigList.get(0), 201, 250, SMS_CB_CODE_SCHEME_MIN, + SMS_CB_CODE_SCHEME_MAX, true); + testManager.reset(); + assertTrue("updating ranges", testManager.updateRanges()); + assertEquals("flags after test", ALL_FLAGS_SET, testManager.flags); + assertEquals("configlist size", 1, testManager.mConfigList.size()); + checkConfigInfo(testManager.mConfigList.get(0), 100, 250, SMS_CB_CODE_SCHEME_MIN, + SMS_CB_CODE_SCHEME_MAX, true); + testManager.reset(); + assertTrue("disabling range 1", testManager.disableRange(100, 200, "client1")); + assertEquals("flags after test", ALL_FLAGS_SET, testManager.flags); + assertEquals("configlist size", 1, testManager.mConfigList.size()); + checkConfigInfo(testManager.mConfigList.get(0), 100, 149, SMS_CB_CODE_SCHEME_MIN, + SMS_CB_CODE_SCHEME_MAX, false); + testManager.reset(); + assertTrue("disabling range 2", testManager.disableRange(150, 250, "client2")); + assertEquals("flags after test", ALL_FLAGS_SET, testManager.flags); + assertEquals("configlist size", 1, testManager.mConfigList.size()); + checkConfigInfo(testManager.mConfigList.get(0), 150, 250, SMS_CB_CODE_SCHEME_MIN, + SMS_CB_CODE_SCHEME_MAX, false); + testManager.reset(); + assertTrue("updating ranges", testManager.updateRanges()); + assertEquals("flags after test", FLAG_START_UPDATE_CALLED | FLAG_FINISH_UPDATE_CALLED, + testManager.flags); + assertEquals("configlist size", 0, testManager.mConfigList.size()); + } + + public void testOverlappingChannels2() { + TestIntRangeManager testManager = new TestIntRangeManager(); + assertEquals("flags before test", 0, testManager.flags); + assertTrue("enabling range 1", testManager.enableRange(100, 200, "client1")); + assertEquals("flags after test", ALL_FLAGS_SET, testManager.flags); + assertEquals("configlist size", 1, testManager.mConfigList.size()); + checkConfigInfo(testManager.mConfigList.get(0), 100, 200, SMS_CB_CODE_SCHEME_MIN, + SMS_CB_CODE_SCHEME_MAX, true); + testManager.reset(); + assertTrue("enabling range 2", testManager.enableRange(150, 250, "client2")); + assertEquals("flags after test", ALL_FLAGS_SET, testManager.flags); + assertEquals("configlist size", 1, testManager.mConfigList.size()); + checkConfigInfo(testManager.mConfigList.get(0), 201, 250, SMS_CB_CODE_SCHEME_MIN, + SMS_CB_CODE_SCHEME_MAX, true); + testManager.reset(); + assertTrue("disabling range 2", testManager.disableRange(150, 250, "client2")); + assertEquals("flags after test", ALL_FLAGS_SET, testManager.flags); + assertEquals("configlist size", 1, testManager.mConfigList.size()); + checkConfigInfo(testManager.mConfigList.get(0), 201, 250, SMS_CB_CODE_SCHEME_MIN, + SMS_CB_CODE_SCHEME_MAX, false); + testManager.reset(); + assertTrue("updating ranges", testManager.updateRanges()); + assertEquals("flags after test", ALL_FLAGS_SET, testManager.flags); + assertEquals("configlist size", 1, testManager.mConfigList.size()); + checkConfigInfo(testManager.mConfigList.get(0), 100, 200, SMS_CB_CODE_SCHEME_MIN, + SMS_CB_CODE_SCHEME_MAX, true); + testManager.reset(); + assertTrue("disabling range 1", testManager.disableRange(100, 200, "client1")); + assertEquals("flags after test", ALL_FLAGS_SET, testManager.flags); + assertEquals("configlist size", 1, testManager.mConfigList.size()); + checkConfigInfo(testManager.mConfigList.get(0), 100, 200, SMS_CB_CODE_SCHEME_MIN, + SMS_CB_CODE_SCHEME_MAX, false); + } + + public void testMultipleOverlappingChannels() { + TestIntRangeManager testManager = new TestIntRangeManager(); + assertEquals("flags before test", 0, testManager.flags); + assertTrue("enabling range 1", testManager.enableRange(67, 9999, "client1")); + assertEquals("flags after test", ALL_FLAGS_SET, testManager.flags); + assertEquals("configlist size", 1, testManager.mConfigList.size()); + checkConfigInfo(testManager.mConfigList.get(0), 67, 9999, SMS_CB_CODE_SCHEME_MIN, + SMS_CB_CODE_SCHEME_MAX, true); + testManager.reset(); + assertTrue("enabling range 2", testManager.enableRange(150, 250, "client2")); + assertEquals("flags after test", 0, testManager.flags); + assertEquals("configlist size", 0, testManager.mConfigList.size()); + testManager.reset(); + assertTrue("enabling range 3", testManager.enableRange(25, 75, "client3")); + assertEquals("flags after test", ALL_FLAGS_SET, testManager.flags); + assertEquals("configlist size", 1, testManager.mConfigList.size()); + checkConfigInfo(testManager.mConfigList.get(0), 25, 66, SMS_CB_CODE_SCHEME_MIN, + SMS_CB_CODE_SCHEME_MAX, true); + testManager.reset(); + assertTrue("enabling range 4", testManager.enableRange(12, 500, "client4")); + assertEquals("flags after test", ALL_FLAGS_SET, testManager.flags); + assertEquals("configlist size", 1, testManager.mConfigList.size()); + checkConfigInfo(testManager.mConfigList.get(0), 12, 24, SMS_CB_CODE_SCHEME_MIN, + SMS_CB_CODE_SCHEME_MAX, true); + testManager.reset(); + assertTrue("enabling range 5", testManager.enableRange(8000, 9998, "client5")); + assertEquals("flags after test", 0, testManager.flags); + assertEquals("configlist size", 0, testManager.mConfigList.size()); + testManager.reset(); + assertTrue("enabling range 6", testManager.enableRange(50000, 65535, "client6")); + assertEquals("flags after test", ALL_FLAGS_SET, testManager.flags); + assertEquals("configlist size", 1, testManager.mConfigList.size()); + checkConfigInfo(testManager.mConfigList.get(0), 50000, 65535, SMS_CB_CODE_SCHEME_MIN, + SMS_CB_CODE_SCHEME_MAX, true); + testManager.reset(); + assertTrue("updating ranges", testManager.updateRanges()); + assertEquals("flags after test", ALL_FLAGS_SET, testManager.flags); + assertEquals("configlist size", 2, testManager.mConfigList.size()); + checkConfigInfo(testManager.mConfigList.get(0), 12, 9999, SMS_CB_CODE_SCHEME_MIN, + SMS_CB_CODE_SCHEME_MAX, true); + checkConfigInfo(testManager.mConfigList.get(1), 50000, 65535, SMS_CB_CODE_SCHEME_MIN, + SMS_CB_CODE_SCHEME_MAX, true); + testManager.reset(); + assertTrue("disabling range 1", testManager.disableRange(67, 9999, "client1")); + assertEquals("flags after test", ALL_FLAGS_SET, testManager.flags); + assertEquals("configlist size", 2, testManager.mConfigList.size()); + checkConfigInfo(testManager.mConfigList.get(0), 501, 7999, SMS_CB_CODE_SCHEME_MIN, + SMS_CB_CODE_SCHEME_MAX, false); + checkConfigInfo(testManager.mConfigList.get(1), 9999, 9999, SMS_CB_CODE_SCHEME_MIN, + SMS_CB_CODE_SCHEME_MAX, false); + testManager.reset(); + assertTrue("updating ranges", testManager.updateRanges()); + assertEquals("flags after test", ALL_FLAGS_SET, testManager.flags); + assertEquals("configlist size", 3, testManager.mConfigList.size()); + checkConfigInfo(testManager.mConfigList.get(0), 12, 500, SMS_CB_CODE_SCHEME_MIN, + SMS_CB_CODE_SCHEME_MAX, true); + checkConfigInfo(testManager.mConfigList.get(1), 8000, 9998, SMS_CB_CODE_SCHEME_MIN, + SMS_CB_CODE_SCHEME_MAX, true); + checkConfigInfo(testManager.mConfigList.get(2), 50000, 65535, SMS_CB_CODE_SCHEME_MIN, + SMS_CB_CODE_SCHEME_MAX, true); + testManager.reset(); + assertTrue("disabling range 4", testManager.disableRange(12, 500, "client4")); + assertEquals("flags after test", ALL_FLAGS_SET, testManager.flags); + assertEquals("configlist size", 3, testManager.mConfigList.size()); + checkConfigInfo(testManager.mConfigList.get(0), 12, 24, SMS_CB_CODE_SCHEME_MIN, + SMS_CB_CODE_SCHEME_MAX, false); + checkConfigInfo(testManager.mConfigList.get(1), 76, 149, SMS_CB_CODE_SCHEME_MIN, + SMS_CB_CODE_SCHEME_MAX, false); + checkConfigInfo(testManager.mConfigList.get(2), 251, 500, SMS_CB_CODE_SCHEME_MIN, + SMS_CB_CODE_SCHEME_MAX, false); + testManager.reset(); + assertTrue("updating ranges", testManager.updateRanges()); + assertEquals("flags after test", ALL_FLAGS_SET, testManager.flags); + assertEquals("configlist size", 4, testManager.mConfigList.size()); + checkConfigInfo(testManager.mConfigList.get(0), 25, 75, SMS_CB_CODE_SCHEME_MIN, + SMS_CB_CODE_SCHEME_MAX, true); + checkConfigInfo(testManager.mConfigList.get(1), 150, 250, SMS_CB_CODE_SCHEME_MIN, + SMS_CB_CODE_SCHEME_MAX, true); + checkConfigInfo(testManager.mConfigList.get(2), 8000, 9998, SMS_CB_CODE_SCHEME_MIN, + SMS_CB_CODE_SCHEME_MAX, true); + checkConfigInfo(testManager.mConfigList.get(3), 50000, 65535, SMS_CB_CODE_SCHEME_MIN, + SMS_CB_CODE_SCHEME_MAX, true); + testManager.reset(); + assertTrue("disabling range 5", testManager.disableRange(8000, 9998, "client5")); + assertEquals("flags after test", ALL_FLAGS_SET, testManager.flags); + assertEquals("configlist size", 1, testManager.mConfigList.size()); + checkConfigInfo(testManager.mConfigList.get(0), 8000, 9998, SMS_CB_CODE_SCHEME_MIN, + SMS_CB_CODE_SCHEME_MAX, false); + testManager.reset(); + assertTrue("updating ranges", testManager.updateRanges()); + assertEquals("flags after test", ALL_FLAGS_SET, testManager.flags); + assertEquals("configlist size", 3, testManager.mConfigList.size()); + checkConfigInfo(testManager.mConfigList.get(0), 25, 75, SMS_CB_CODE_SCHEME_MIN, + SMS_CB_CODE_SCHEME_MAX, true); + checkConfigInfo(testManager.mConfigList.get(1), 150, 250, SMS_CB_CODE_SCHEME_MIN, + SMS_CB_CODE_SCHEME_MAX, true); + checkConfigInfo(testManager.mConfigList.get(2), 50000, 65535, SMS_CB_CODE_SCHEME_MIN, + SMS_CB_CODE_SCHEME_MAX, true); + testManager.reset(); + assertTrue("disabling range 6", testManager.disableRange(50000, 65535, "client6")); + assertEquals("flags after test", ALL_FLAGS_SET, testManager.flags); + assertEquals("configlist size", 1, testManager.mConfigList.size()); + checkConfigInfo(testManager.mConfigList.get(0), 50000, 65535, SMS_CB_CODE_SCHEME_MIN, + SMS_CB_CODE_SCHEME_MAX, false); + testManager.reset(); + assertTrue("updating ranges", testManager.updateRanges()); + assertEquals("flags after test", ALL_FLAGS_SET, testManager.flags); + assertEquals("configlist size", 2, testManager.mConfigList.size()); + checkConfigInfo(testManager.mConfigList.get(0), 25, 75, SMS_CB_CODE_SCHEME_MIN, + SMS_CB_CODE_SCHEME_MAX, true); + checkConfigInfo(testManager.mConfigList.get(1), 150, 250, SMS_CB_CODE_SCHEME_MIN, + SMS_CB_CODE_SCHEME_MAX, true); + testManager.reset(); + assertTrue("disabling range 2", testManager.disableRange(150, 250, "client2")); + assertEquals("flags after test", ALL_FLAGS_SET, testManager.flags); + assertEquals("configlist size", 1, testManager.mConfigList.size()); + checkConfigInfo(testManager.mConfigList.get(0), 150, 250, SMS_CB_CODE_SCHEME_MIN, + SMS_CB_CODE_SCHEME_MAX, false); + testManager.reset(); + assertTrue("updating ranges", testManager.updateRanges()); + assertEquals("flags after test", ALL_FLAGS_SET, testManager.flags); + assertEquals("configlist size", 1, testManager.mConfigList.size()); + checkConfigInfo(testManager.mConfigList.get(0), 25, 75, SMS_CB_CODE_SCHEME_MIN, + SMS_CB_CODE_SCHEME_MAX, true); + testManager.reset(); + assertTrue("disabling range 3", testManager.disableRange(25, 75, "client3")); + assertEquals("flags after test", ALL_FLAGS_SET, testManager.flags); + assertEquals("configlist size", 1, testManager.mConfigList.size()); + checkConfigInfo(testManager.mConfigList.get(0), 25, 75, SMS_CB_CODE_SCHEME_MIN, + SMS_CB_CODE_SCHEME_MAX, false); + testManager.reset(); + assertTrue("updating ranges", testManager.updateRanges()); + assertEquals("flags after test", FLAG_START_UPDATE_CALLED | FLAG_FINISH_UPDATE_CALLED, + testManager.flags); + assertEquals("configlist size", 0, testManager.mConfigList.size()); + } +} diff --git a/services/java/com/android/server/WifiStateTracker.java b/tests/BiDiTests/Android index e69de29bb2d1..e69de29bb2d1 100644 --- a/services/java/com/android/server/WifiStateTracker.java +++ b/tests/BiDiTests/Android diff --git a/tests/BiDiTests/AndroidManifest.xml b/tests/BiDiTests/AndroidManifest.xml index ad27a62bc1f0..4a687f247fa8 100644 --- a/tests/BiDiTests/AndroidManifest.xml +++ b/tests/BiDiTests/AndroidManifest.xml @@ -29,90 +29,6 @@ </intent-filter> </activity> - <activity android:name=".BiDiTestBasicActivity" - android:windowSoftInputMode="stateAlwaysHidden"> - <intent-filter> - <action android:name="android.intent.action.MAIN" /> - </intent-filter> - </activity> - - <activity android:name=".BiDiTestCanvasActivity" - android:windowSoftInputMode="stateAlwaysHidden"> - <intent-filter> - <action android:name="android.intent.action.MAIN" /> - </intent-filter> - </activity> - - <activity android:name=".BiDiTestLinearLayoutLtrActivity" - android:windowSoftInputMode="stateAlwaysHidden"> - <intent-filter> - <action android:name="android.intent.action.MAIN" /> - </intent-filter> - </activity> - - <activity android:name=".BiDiTestLinearLayoutRtlActivity" - android:windowSoftInputMode="stateAlwaysHidden"> - <intent-filter> - <action android:name="android.intent.action.MAIN" /> - </intent-filter> - </activity> - - <activity android:name=".BiDiTestFrameLayoutLtrActivity" - android:windowSoftInputMode="stateAlwaysHidden"> - <intent-filter> - <action android:name="android.intent.action.MAIN" /> - </intent-filter> - </activity> - - <activity android:name=".BiDiTestFrameLayoutRtlActivity" - android:windowSoftInputMode="stateAlwaysHidden"> - <intent-filter> - <action android:name="android.intent.action.MAIN" /> - </intent-filter> - </activity> - - <activity android:name=".BiDiTestRelativeLayoutLtrActivity" - android:windowSoftInputMode="stateAlwaysHidden"> - <intent-filter> - <action android:name="android.intent.action.MAIN" /> - </intent-filter> - </activity> - - <activity android:name=".BiDiTestRelativeLayoutRtlActivity" - android:windowSoftInputMode="stateAlwaysHidden"> - <intent-filter> - <action android:name="android.intent.action.MAIN" /> - </intent-filter> - </activity> - - <activity android:name=".BiDiTestRelativeLayoutLtrActivity2" - android:windowSoftInputMode="stateAlwaysHidden"> - <intent-filter> - <action android:name="android.intent.action.MAIN" /> - </intent-filter> - </activity> - - <activity android:name=".BiDiTestRelativeLayoutRtlActivity2" - android:windowSoftInputMode="stateAlwaysHidden"> - <intent-filter> - <action android:name="android.intent.action.MAIN" /> - </intent-filter> - </activity> - - <activity android:name=".BiDiTestTableLayoutLtrActivity" - android:windowSoftInputMode="stateAlwaysHidden"> - <intent-filter> - <action android:name="android.intent.action.MAIN" /> - </intent-filter> - </activity> - - <activity android:name=".BiDiTestTableLayoutRtlActivity" - android:windowSoftInputMode="stateAlwaysHidden"> - <intent-filter> - <action android:name="android.intent.action.MAIN" /> - </intent-filter> - </activity> - </application> </manifest> diff --git a/tests/BiDiTests/res/layout/basic.xml b/tests/BiDiTests/res/layout/basic.xml index f254e3c4d40f..d438b2cee732 100644 --- a/tests/BiDiTests/res/layout/basic.xml +++ b/tests/BiDiTests/res/layout/basic.xml @@ -14,36 +14,41 @@ limitations under the License. --> -<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:orientation="vertical" - android:layout_width="match_parent" - android:layout_height="match_parent"> - - <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:orientation="vertical" - android:layout_width="match_parent" - android:layout_height="wrap_content"> - - <Button android:id="@+id/button" - android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:text="@string/button_text" - android:textSize="32dip" - /> - - <TextView android:id="@+id/textview" - android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:textSize="32dip" - android:text="@string/textview_text" - /> - - <EditText android:id="@+id/edittext" - android:layout_height="wrap_content" - android:layout_width="match_parent" - android:textSize="32dip" - /> +<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/basic" + android:layout_width="fill_parent" + android:layout_height="fill_parent"> + + <LinearLayout android:orientation="vertical" + android:layout_width="match_parent" + android:layout_height="match_parent"> + + <LinearLayout android:orientation="vertical" + android:layout_width="match_parent" + android:layout_height="wrap_content"> + + <Button android:id="@+id/button" + android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button_text" + android:textSize="32dip" + /> + + <TextView android:id="@+id/textview" + android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:textSize="32dip" + android:text="@string/textview_text" + /> + + <EditText android:id="@+id/edittext" + android:layout_height="wrap_content" + android:layout_width="match_parent" + android:textSize="32dip" + /> + + </LinearLayout> </LinearLayout> -</LinearLayout>
\ No newline at end of file +</FrameLayout>
\ No newline at end of file diff --git a/tests/BiDiTests/res/layout/canvas.xml b/tests/BiDiTests/res/layout/canvas.xml index 77007af3a6bd..0319a83b0382 100644 --- a/tests/BiDiTests/res/layout/canvas.xml +++ b/tests/BiDiTests/res/layout/canvas.xml @@ -14,21 +14,27 @@ limitations under the License. --> -<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:orientation="vertical" - android:layout_width="match_parent" - android:layout_height="match_parent"> - - <SeekBar android:id="@+id/seekbar" - android:layout_height="wrap_content" - android:layout_width="match_parent" - /> - - <view class="com.android.bidi.BiDiTestView" - android:id="@+id/testview" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:background="#FF0000" - /> - -</LinearLayout> +<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/canvas" + android:layout_width="fill_parent" + android:layout_height="fill_parent"> + + <LinearLayout android:orientation="vertical" + android:layout_width="match_parent" + android:layout_height="match_parent"> + + <SeekBar android:id="@+id/seekbar" + android:layout_height="wrap_content" + android:layout_width="match_parent" + /> + + <view class="com.android.bidi.BiDiTestView" + android:id="@+id/testview" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:background="#FF0000" + /> + + </LinearLayout> + +</FrameLayout>
\ No newline at end of file diff --git a/tests/BiDiTests/res/layout/custom_list_item.xml b/tests/BiDiTests/res/layout/custom_list_item.xml new file mode 100644 index 000000000000..069424e82df4 --- /dev/null +++ b/tests/BiDiTests/res/layout/custom_list_item.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2006 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. +--> + +<TextView xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@android:id/text1" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:textAppearance="?android:attr/textAppearanceLarge" + android:gravity="center_vertical" + android:paddingLeft="6dip" + android:minHeight="?android:attr/listPreferredItemHeight" + android:background="?android:attr/activatedBackgroundIndicator" +/> diff --git a/tests/BiDiTests/res/layout/frame_layout_locale.xml b/tests/BiDiTests/res/layout/frame_layout_locale.xml new file mode 100644 index 000000000000..33822343eb2d --- /dev/null +++ b/tests/BiDiTests/res/layout/frame_layout_locale.xml @@ -0,0 +1,92 @@ +<?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. +--> + +<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/frame_layout_locale" + android:layout_width="fill_parent" + android:layout_height="fill_parent"> + + <FrameLayout android:layout_width="match_parent" + android:layout_height="match_parent" + android:layoutDirection="locale" + android:background="#FF000000"> + + <FrameLayout + android:layout_width="100dp" + android:layout_height="100dp" + android:layout_gravity="right|center_vertical" + android:background="#FFFF0000"> + </FrameLayout> + + <FrameLayout + android:layout_width="100dp" + android:layout_height="100dp" + android:layout_gravity="left|center_vertical" + android:background="#FF00FF00"> + </FrameLayout> + + <FrameLayout + android:layout_width="100dp" + android:layout_height="100dp" + android:layout_gravity="top|center_horizontal" + android:background="#FF0000FF"> + </FrameLayout> + + <FrameLayout + android:layout_width="100dp" + android:layout_height="100dp" + android:layout_gravity="bottom|center_horizontal" + android:background="#FF00FFFF"> + </FrameLayout> + + <FrameLayout + android:layout_width="100dp" + android:layout_height="100dp" + android:layout_gravity="top|start" + android:background="#FFFFFFFF"> + </FrameLayout> + + <FrameLayout + android:layout_width="100dp" + android:layout_height="100dp" + android:layout_gravity="top|end" + android:background="#FFFFFF00"> + </FrameLayout> + + <FrameLayout + android:layout_width="100dp" + android:layout_height="100dp" + android:layout_gravity="bottom|start" + android:background="#FFFFFFFF"> + </FrameLayout> + + <FrameLayout + android:layout_width="100dp" + android:layout_height="100dp" + android:layout_gravity="bottom|end" + android:background="#FFFFFF00"> + </FrameLayout> + + <FrameLayout + android:layout_width="100dp" + android:layout_height="100dp" + android:layout_gravity="center_horizontal|center_vertical" + android:background="#FF888888"> + </FrameLayout> + + </FrameLayout> + +</FrameLayout> diff --git a/tests/BiDiTests/res/layout/frame_layout_ltr.xml b/tests/BiDiTests/res/layout/frame_layout_ltr.xml index 61fd06e08532..a8ae91442ec3 100644 --- a/tests/BiDiTests/res/layout/frame_layout_ltr.xml +++ b/tests/BiDiTests/res/layout/frame_layout_ltr.xml @@ -15,74 +15,78 @@ --> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:id="@+id/frame_layout_ltr" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:layoutDirection="ltr" - android:background="#FF000000"> + android:id="@+id/frame_layout_ltr" + android:layout_width="fill_parent" + android:layout_height="fill_parent"> + + <FrameLayout android:layout_width="match_parent" + android:layout_height="match_parent" + android:layoutDirection="ltr" + android:background="#FF000000"> <FrameLayout - android:layout_width="100dp" - android:layout_height="100dp" - android:layout_gravity="right|center_vertical" - android:background="#FFFF0000"> + android:layout_width="100dp" + android:layout_height="100dp" + android:layout_gravity="right|center_vertical" + android:background="#FFFF0000"> </FrameLayout> <FrameLayout - android:layout_width="100dp" - android:layout_height="100dp" - android:layout_gravity="left|center_vertical" - android:background="#FF00FF00"> + android:layout_width="100dp" + android:layout_height="100dp" + android:layout_gravity="left|center_vertical" + android:background="#FF00FF00"> </FrameLayout> <FrameLayout - android:layout_width="100dp" - android:layout_height="100dp" - android:layout_gravity="top|center_horizontal" - android:background="#FF0000FF"> + android:layout_width="100dp" + android:layout_height="100dp" + android:layout_gravity="top|center_horizontal" + android:background="#FF0000FF"> </FrameLayout> <FrameLayout - android:layout_width="100dp" - android:layout_height="100dp" - android:layout_gravity="bottom|center_horizontal" - android:background="#FF00FFFF"> + android:layout_width="100dp" + android:layout_height="100dp" + android:layout_gravity="bottom|center_horizontal" + android:background="#FF00FFFF"> </FrameLayout> <FrameLayout - android:layout_width="100dp" - android:layout_height="100dp" - android:layout_gravity="top|start" - android:background="#FFFFFFFF"> + android:layout_width="100dp" + android:layout_height="100dp" + android:layout_gravity="top|start" + android:background="#FFFFFFFF"> </FrameLayout> <FrameLayout - android:layout_width="100dp" - android:layout_height="100dp" - android:layout_gravity="top|end" - android:background="#FFFFFF00"> + android:layout_width="100dp" + android:layout_height="100dp" + android:layout_gravity="top|end" + android:background="#FFFFFF00"> </FrameLayout> <FrameLayout - android:layout_width="100dp" - android:layout_height="100dp" - android:layout_gravity="bottom|start" - android:background="#FFFFFFFF"> + android:layout_width="100dp" + android:layout_height="100dp" + android:layout_gravity="bottom|start" + android:background="#FFFFFFFF"> </FrameLayout> <FrameLayout - android:layout_width="100dp" - android:layout_height="100dp" - android:layout_gravity="bottom|end" - android:background="#FFFFFF00"> + android:layout_width="100dp" + android:layout_height="100dp" + android:layout_gravity="bottom|end" + android:background="#FFFFFF00"> </FrameLayout> <FrameLayout - android:layout_width="100dp" - android:layout_height="100dp" - android:layout_gravity="center_horizontal|center_vertical" - android:background="#FF888888"> + android:layout_width="100dp" + android:layout_height="100dp" + android:layout_gravity="center_horizontal|center_vertical" + android:background="#FF888888"> </FrameLayout> -</FrameLayout> + </FrameLayout> +</FrameLayout> diff --git a/tests/BiDiTests/res/layout/frame_layout_rtl.xml b/tests/BiDiTests/res/layout/frame_layout_rtl.xml index 598b41a233a2..258d44a1874b 100644 --- a/tests/BiDiTests/res/layout/frame_layout_rtl.xml +++ b/tests/BiDiTests/res/layout/frame_layout_rtl.xml @@ -15,74 +15,78 @@ --> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:id="@+id/frame_layout_ltr" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:layoutDirection="rtl" - android:background="#FF000000"> + android:id="@+id/frame_layout_rtl" + android:layout_width="fill_parent" + android:layout_height="fill_parent"> + + <FrameLayout android:layout_width="match_parent" + android:layout_height="match_parent" + android:layoutDirection="ltr" + android:background="#FF000000"> <FrameLayout - android:layout_width="100dp" - android:layout_height="100dp" - android:layout_gravity="right|center_vertical" - android:background="#FFFF0000"> + android:layout_width="100dp" + android:layout_height="100dp" + android:layout_gravity="right|center_vertical" + android:background="#FFFF0000"> </FrameLayout> <FrameLayout - android:layout_width="100dp" - android:layout_height="100dp" - android:layout_gravity="left|center_vertical" - android:background="#FF00FF00"> + android:layout_width="100dp" + android:layout_height="100dp" + android:layout_gravity="left|center_vertical" + android:background="#FF00FF00"> </FrameLayout> <FrameLayout - android:layout_width="100dp" - android:layout_height="100dp" - android:layout_gravity="top|center_horizontal" - android:background="#FF0000FF"> + android:layout_width="100dp" + android:layout_height="100dp" + android:layout_gravity="top|center_horizontal" + android:background="#FF0000FF"> </FrameLayout> <FrameLayout - android:layout_width="100dp" - android:layout_height="100dp" - android:layout_gravity="bottom|center_horizontal" - android:background="#FF00FFFF"> + android:layout_width="100dp" + android:layout_height="100dp" + android:layout_gravity="bottom|center_horizontal" + android:background="#FF00FFFF"> </FrameLayout> <FrameLayout - android:layout_width="100dp" - android:layout_height="100dp" - android:layout_gravity="top|start" - android:background="#FFFFFFFF"> + android:layout_width="100dp" + android:layout_height="100dp" + android:layout_gravity="top|start" + android:background="#FFFFFFFF"> </FrameLayout> <FrameLayout - android:layout_width="100dp" - android:layout_height="100dp" - android:layout_gravity="top|end" - android:background="#FFFFFF00"> + android:layout_width="100dp" + android:layout_height="100dp" + android:layout_gravity="top|end" + android:background="#FFFFFF00"> </FrameLayout> <FrameLayout - android:layout_width="100dp" - android:layout_height="100dp" - android:layout_gravity="bottom|start" - android:background="#FFFFFFFF"> + android:layout_width="100dp" + android:layout_height="100dp" + android:layout_gravity="bottom|start" + android:background="#FFFFFFFF"> </FrameLayout> <FrameLayout - android:layout_width="100dp" - android:layout_height="100dp" - android:layout_gravity="bottom|end" - android:background="#FFFFFF00"> + android:layout_width="100dp" + android:layout_height="100dp" + android:layout_gravity="bottom|end" + android:background="#FFFFFF00"> </FrameLayout> <FrameLayout - android:layout_width="100dp" - android:layout_height="100dp" - android:layout_gravity="center_horizontal|center_vertical" - android:background="#FF888888"> + android:layout_width="100dp" + android:layout_height="100dp" + android:layout_gravity="center_horizontal|center_vertical" + android:background="#FF888888"> </FrameLayout> -</FrameLayout> + </FrameLayout> +</FrameLayout> diff --git a/tests/BiDiTests/res/layout/linear_layout_locale.xml b/tests/BiDiTests/res/layout/linear_layout_locale.xml new file mode 100644 index 000000000000..bddb4583a0d2 --- /dev/null +++ b/tests/BiDiTests/res/layout/linear_layout_locale.xml @@ -0,0 +1,253 @@ +<?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. +--> + +<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/linear_layout_locale" + android:layout_width="fill_parent" + android:layout_height="fill_parent"> + + <LinearLayout android:orientation="vertical" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:layoutDirection="locale"> + + <LinearLayout android:orientation="horizontal" + android:layout_width="match_parent" + android:layout_height="wrap_content"> + + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button1_text" + android:textSize="24dip" + /> + + <TextView android:id="@+id/textview" + android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:textSize="24dip" + android:text="@string/textview_text" + /> + + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button2_text" + android:textSize="24dip" + /> + </LinearLayout> + + <LinearLayout android:orientation="horizontal" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layoutDirection="inherit"> + + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button1_text" + android:textSize="24dip" + /> + + <TextView android:id="@+id/textview" + android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:textSize="24dip" + android:text="@string/textview_text" + /> + + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button2_text" + android:textSize="24dip" + /> + </LinearLayout> + + <LinearLayout android:orientation="horizontal" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layoutDirection="ltr"> + + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button1_text" + android:textSize="24dip" + /> + + <TextView android:id="@+id/textview" + android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:textSize="24dip" + android:text="@string/textview_text" + /> + + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button2_text" + android:textSize="24dip" + /> + </LinearLayout> + + <LinearLayout android:orientation="horizontal" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layoutDirection="rtl"> + + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button1_text" + android:textSize="24dip" + /> + + <TextView android:id="@+id/textview" + android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:textSize="24dip" + android:text="@string/textview_text" + /> + + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button2_text" + android:textSize="24dip" + /> + </LinearLayout> + + <LinearLayout android:orientation="horizontal" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layoutDirection="locale"> + + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button1_text" + android:textSize="24dip" + /> + + <TextView android:id="@+id/textview" + android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:textSize="24dip" + android:text="@string/textview_text" + /> + + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button2_text" + android:textSize="24dip" + /> + </LinearLayout> + + <LinearLayout android:orientation="vertical" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layoutDirection="inherit"> + + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button1_text" + android:textSize="24dip" + /> + + <TextView android:id="@+id/textview" + android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:textSize="24dip" + android:text="@string/textview_text" + /> + + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button2_text" + android:textSize="24dip" + /> + </LinearLayout> + + <LinearLayout android:orientation="vertical" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layoutDirection="ltr"> + + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button1_text" + android:textSize="24dip" + /> + + <TextView android:id="@+id/textview" + android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:textSize="24dip" + android:text="@string/textview_text" + /> + + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button2_text" + android:textSize="24dip" + /> + </LinearLayout> + + <LinearLayout android:orientation="vertical" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layoutDirection="rtl"> + + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button1_text" + android:textSize="24dip" + /> + + <TextView android:id="@+id/textview" + android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:textSize="24dip" + android:text="@string/textview_text" + /> + + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button2_text" + android:textSize="24dip" + /> + </LinearLayout> + + <LinearLayout android:orientation="vertical" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layoutDirection="locale"> + + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button1_text" + android:textSize="24dip" + /> + + <TextView android:id="@+id/textview" + android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:textSize="24dip" + android:text="@string/textview_text" + /> + + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button2_text" + android:textSize="24dip" + /> + </LinearLayout> + + </LinearLayout> + +</FrameLayout>
\ No newline at end of file diff --git a/tests/BiDiTests/res/layout/linear_layout_ltr.xml b/tests/BiDiTests/res/layout/linear_layout_ltr.xml index d4386f2d0102..060112d454cd 100644 --- a/tests/BiDiTests/res/layout/linear_layout_ltr.xml +++ b/tests/BiDiTests/res/layout/linear_layout_ltr.xml @@ -14,199 +14,240 @@ limitations under the License. --> -<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:id="@+id/linear_layout_ltr" - android:orientation="vertical" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:layoutDirection="ltr"> - - <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:orientation="horizontal" - android:layout_width="match_parent" - android:layout_height="wrap_content"> - - <Button android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:text="@string/button1_text" - android:textSize="24dip" - /> - - <TextView android:id="@+id/textview" - android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:textSize="24dip" - android:text="@string/textview_text" - /> - - <Button android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:text="@string/button2_text" - android:textSize="24dip" - /> - - </LinearLayout> - - <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:orientation="horizontal" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layoutDirection="inherit"> - - <Button android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:text="@string/button1_text" - android:textSize="24dip" - /> - - <TextView android:id="@+id/textview" - android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:textSize="24dip" - android:text="@string/textview_text" - /> - - <Button android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:text="@string/button2_text" - android:textSize="24dip" - /> - - </LinearLayout> - - <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:orientation="horizontal" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layoutDirection="ltr"> - - <Button android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:text="@string/button1_text" - android:textSize="24dip" - /> - - <TextView android:id="@+id/textview" - android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:textSize="24dip" - android:text="@string/textview_text" - /> - - <Button android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:text="@string/button2_text" - android:textSize="24dip" - /> - - </LinearLayout> - - <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:orientation="horizontal" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layoutDirection="rtl"> - - <Button android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:text="@string/button1_text" - android:textSize="24dip" - /> - - <TextView android:id="@+id/textview" - android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:textSize="24dip" - android:text="@string/textview_text" - /> - - <Button android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:text="@string/button2_text" - android:textSize="24dip" - /> - - </LinearLayout> - - <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:orientation="vertical" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layoutDirection="inherit"> - - <Button android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:text="@string/button1_text" - android:textSize="24dip" - /> - - <TextView android:id="@+id/textview" - android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:textSize="24dip" - android:text="@string/textview_text" - /> - - <Button android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:text="@string/button2_text" - android:textSize="24dip" - /> - - </LinearLayout> - - <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:orientation="vertical" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layoutDirection="ltr"> - - <Button android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:text="@string/button1_text" - android:textSize="24dip" - /> - - <TextView android:id="@+id/textview" - android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:textSize="24dip" - android:text="@string/textview_text" - /> - - <Button android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:text="@string/button2_text" - android:textSize="24dip" - /> - - </LinearLayout> - - <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:orientation="vertical" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layoutDirection="rtl"> - - <Button android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:text="@string/button1_text" - android:textSize="24dip" - /> - - <TextView android:id="@+id/textview" - android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:textSize="24dip" - android:text="@string/textview_text" - /> - - <Button android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:text="@string/button2_text" - android:textSize="24dip" - /> - +<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/linear_layout_ltr" + android:layout_width="fill_parent" + android:layout_height="fill_parent"> + + <LinearLayout android:orientation="vertical" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:layoutDirection="ltr"> + + <LinearLayout android:orientation="horizontal" + android:layout_width="match_parent" + android:layout_height="wrap_content"> + + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button1_text" + android:textSize="24dip" + /> + + <TextView android:id="@+id/textview" + android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:textSize="24dip" + android:text="@string/textview_text" + /> + + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button2_text" + android:textSize="24dip" + /> + </LinearLayout> + + <LinearLayout android:orientation="horizontal" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layoutDirection="inherit"> + + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button1_text" + android:textSize="24dip" + /> + + <TextView android:id="@+id/textview" + android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:textSize="24dip" + android:text="@string/textview_text" + /> + + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button2_text" + android:textSize="24dip" + /> + </LinearLayout> + + <LinearLayout android:orientation="horizontal" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layoutDirection="ltr"> + + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button1_text" + android:textSize="24dip" + /> + + <TextView android:id="@+id/textview" + android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:textSize="24dip" + android:text="@string/textview_text" + /> + + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button2_text" + android:textSize="24dip" + /> + </LinearLayout> + + <LinearLayout android:orientation="horizontal" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layoutDirection="rtl"> + + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button1_text" + android:textSize="24dip" + /> + + <TextView android:id="@+id/textview" + android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:textSize="24dip" + android:text="@string/textview_text" + /> + + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button2_text" + android:textSize="24dip" + /> + </LinearLayout> + + <LinearLayout android:orientation="horizontal" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layoutDirection="locale"> + + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button1_text" + android:textSize="24dip" + /> + + <TextView android:id="@+id/textview" + android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:textSize="24dip" + android:text="@string/textview_text" + /> + + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button2_text" + android:textSize="24dip" + /> + </LinearLayout> + + <LinearLayout android:orientation="vertical" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layoutDirection="inherit"> + + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button1_text" + android:textSize="24dip" + /> + + <TextView android:id="@+id/textview" + android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:textSize="24dip" + android:text="@string/textview_text" + /> + + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button2_text" + android:textSize="24dip" + /> + </LinearLayout> + + <LinearLayout android:orientation="vertical" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layoutDirection="ltr"> + + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button1_text" + android:textSize="24dip" + /> + + <TextView android:id="@+id/textview" + android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:textSize="24dip" + android:text="@string/textview_text" + /> + + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button2_text" + android:textSize="24dip" + /> + </LinearLayout> + + <LinearLayout android:orientation="vertical" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layoutDirection="rtl"> + + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button1_text" + android:textSize="24dip" + /> + + <TextView android:id="@+id/textview" + android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:textSize="24dip" + android:text="@string/textview_text" + /> + + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button2_text" + android:textSize="24dip" + /> + </LinearLayout> + + <LinearLayout android:orientation="vertical" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layoutDirection="locale"> + + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button1_text" + android:textSize="24dip" + /> + + <TextView android:id="@+id/textview" + android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:textSize="24dip" + android:text="@string/textview_text" + /> + + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button2_text" + android:textSize="24dip" + /> + </LinearLayout> + </LinearLayout> -</LinearLayout>
\ No newline at end of file +</FrameLayout>
\ No newline at end of file diff --git a/tests/BiDiTests/res/layout/linear_layout_rtl.xml b/tests/BiDiTests/res/layout/linear_layout_rtl.xml index 9d0726386c3d..53ecbcca7812 100644 --- a/tests/BiDiTests/res/layout/linear_layout_rtl.xml +++ b/tests/BiDiTests/res/layout/linear_layout_rtl.xml @@ -14,199 +14,240 @@ limitations under the License. --> -<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:id="@+id/linear_layout_rtl" - android:orientation="vertical" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:layoutDirection="rtl"> - - <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:orientation="horizontal" - android:layout_width="match_parent" - android:layout_height="wrap_content"> - - <Button android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:text="@string/button1_text" - android:textSize="24dip" - /> - - <TextView android:id="@+id/textview" - android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:textSize="24dip" - android:text="@string/textview_text" - /> - - <Button android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:text="@string/button2_text" - android:textSize="24dip" - /> - - </LinearLayout> - - <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:orientation="horizontal" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layoutDirection="inherit"> - - <Button android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:text="@string/button1_text" - android:textSize="24dip" - /> - - <TextView android:id="@+id/textview" - android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:textSize="24dip" - android:text="@string/textview_text" - /> - - <Button android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:text="@string/button2_text" - android:textSize="24dip" - /> - - </LinearLayout> - - <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:orientation="horizontal" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layoutDirection="ltr"> - - <Button android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:text="@string/button1_text" - android:textSize="24dip" - /> - - <TextView android:id="@+id/textview" - android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:textSize="24dip" - android:text="@string/textview_text" - /> - - <Button android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:text="@string/button2_text" - android:textSize="24dip" - /> - - </LinearLayout> - - <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:orientation="horizontal" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layoutDirection="rtl"> - - <Button android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:text="@string/button1_text" - android:textSize="24dip" - /> - - <TextView android:id="@+id/textview" - android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:textSize="24dip" - android:text="@string/textview_text" - /> - - <Button android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:text="@string/button2_text" - android:textSize="24dip" - /> - - </LinearLayout> - - <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:orientation="vertical" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layoutDirection="inherit"> - - <Button android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:text="@string/button1_text" - android:textSize="24dip" - /> - - <TextView android:id="@+id/textview" - android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:textSize="24dip" - android:text="@string/textview_text" - /> - - <Button android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:text="@string/button2_text" - android:textSize="24dip" - /> - - </LinearLayout> - - <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:orientation="vertical" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layoutDirection="ltr"> - - <Button android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:text="@string/button1_text" - android:textSize="24dip" - /> - - <TextView android:id="@+id/textview" - android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:textSize="24dip" - android:text="@string/textview_text" - /> - - <Button android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:text="@string/button2_text" - android:textSize="24dip" - /> - - </LinearLayout> - - <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:orientation="vertical" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layoutDirection="rtl"> - - <Button android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:text="@string/button1_text" - android:textSize="24dip" - /> - - <TextView android:id="@+id/textview" - android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:textSize="24dip" - android:text="@string/textview_text" - /> - - <Button android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:text="@string/button2_text" - android:textSize="24dip" - /> - +<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/linear_layout_rtl" + android:layout_width="fill_parent" + android:layout_height="fill_parent"> + + <LinearLayout android:orientation="vertical" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:layoutDirection="rtl"> + + <LinearLayout android:orientation="horizontal" + android:layout_width="match_parent" + android:layout_height="wrap_content"> + + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button1_text" + android:textSize="24dip" + /> + + <TextView android:id="@+id/textview" + android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:textSize="24dip" + android:text="@string/textview_text" + /> + + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button2_text" + android:textSize="24dip" + /> + </LinearLayout> + + <LinearLayout android:orientation="horizontal" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layoutDirection="inherit"> + + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button1_text" + android:textSize="24dip" + /> + + <TextView android:id="@+id/textview" + android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:textSize="24dip" + android:text="@string/textview_text" + /> + + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button2_text" + android:textSize="24dip" + /> + </LinearLayout> + + <LinearLayout android:orientation="horizontal" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layoutDirection="ltr"> + + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button1_text" + android:textSize="24dip" + /> + + <TextView android:id="@+id/textview" + android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:textSize="24dip" + android:text="@string/textview_text" + /> + + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button2_text" + android:textSize="24dip" + /> + </LinearLayout> + + <LinearLayout android:orientation="horizontal" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layoutDirection="rtl"> + + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button1_text" + android:textSize="24dip" + /> + + <TextView android:id="@+id/textview" + android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:textSize="24dip" + android:text="@string/textview_text" + /> + + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button2_text" + android:textSize="24dip" + /> + </LinearLayout> + + <LinearLayout android:orientation="horizontal" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layoutDirection="locale"> + + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button1_text" + android:textSize="24dip" + /> + + <TextView android:id="@+id/textview" + android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:textSize="24dip" + android:text="@string/textview_text" + /> + + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button2_text" + android:textSize="24dip" + /> + </LinearLayout> + + <LinearLayout android:orientation="vertical" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layoutDirection="inherit"> + + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button1_text" + android:textSize="24dip" + /> + + <TextView android:id="@+id/textview" + android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:textSize="24dip" + android:text="@string/textview_text" + /> + + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button2_text" + android:textSize="24dip" + /> + </LinearLayout> + + <LinearLayout android:orientation="vertical" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layoutDirection="ltr"> + + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button1_text" + android:textSize="24dip" + /> + + <TextView android:id="@+id/textview" + android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:textSize="24dip" + android:text="@string/textview_text" + /> + + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button2_text" + android:textSize="24dip" + /> + </LinearLayout> + + <LinearLayout android:orientation="vertical" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layoutDirection="rtl"> + + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button1_text" + android:textSize="24dip" + /> + + <TextView android:id="@+id/textview" + android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:textSize="24dip" + android:text="@string/textview_text" + /> + + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button2_text" + android:textSize="24dip" + /> + </LinearLayout> + + <LinearLayout android:orientation="vertical" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layoutDirection="locale"> + + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button1_text" + android:textSize="24dip" + /> + + <TextView android:id="@+id/textview" + android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:textSize="24dip" + android:text="@string/textview_text" + /> + + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button2_text" + android:textSize="24dip" + /> + </LinearLayout> + </LinearLayout> -</LinearLayout>
\ No newline at end of file +</FrameLayout>
\ No newline at end of file diff --git a/tests/BiDiTests/res/layout/main.xml b/tests/BiDiTests/res/layout/main.xml index e39d1d6ee002..3543eb7c8fc2 100644 --- a/tests/BiDiTests/res/layout/main.xml +++ b/tests/BiDiTests/res/layout/main.xml @@ -14,28 +14,20 @@ limitations under the License. --> -<TabHost xmlns:android="http://schemas.android.com/apk/res/android" - android:id="@android:id/tabhost" +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:orientation="horizontal" android:layout_width="fill_parent" android:layout_height="fill_parent"> - <LinearLayout - android:orientation="vertical" - android:layout_width="fill_parent" + <ListView android:id="@+id/testlist" + android:layout_width="0px" android:layout_height="fill_parent" - android:padding="5dp"> + android:layout_weight="1"/> - <TabWidget - android:id="@android:id/tabs" - android:layout_width="fill_parent" - android:layout_height="wrap_content" /> - - <FrameLayout - android:id="@android:id/tabcontent" - android:layout_width="fill_parent" - android:layout_height="fill_parent" - android:padding="5dp" /> - - </LinearLayout> + <FrameLayout android:id="@+id/testframe" + android:layout_width="0px" + android:layout_height="fill_parent" + android:layout_weight="6"> + </FrameLayout> -</TabHost> +</LinearLayout> diff --git a/tests/BiDiTests/res/layout/relative_layout_2_locale.xml b/tests/BiDiTests/res/layout/relative_layout_2_locale.xml new file mode 100644 index 000000000000..ff5bf7b8d64f --- /dev/null +++ b/tests/BiDiTests/res/layout/relative_layout_2_locale.xml @@ -0,0 +1,183 @@ +<?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. +--> + +<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/relative_layout_2_locale" + android:layout_width="fill_parent" + android:layout_height="fill_parent"> + + <LinearLayout android:orientation="vertical" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:layoutDirection="locale"> + + <RelativeLayout android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:background="#FF000000" + android:padding="10px"> + + <TextView android:id="@+id/label_1" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:text="Type here:"/> + + <EditText android:id="@+id/entry_1" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:layout_below="@id/label_1"/> + + <Button android:id="@+id/ok_1" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_below="@id/entry_1" + android:layout_alignParentRight="true" + android:layout_marginLeft="10px" + android:text="OK"/> + + <Button android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_toLeftOf="@id/ok_1" + android:layout_alignTop="@id/ok_1" + android:text="Cancel"/> + </RelativeLayout> + + <RelativeLayout android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:background="#FF000000" + android:padding="10px" + android:layoutDirection="ltr"> + + <TextView android:id="@+id/label_2" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:text="Type here:"/> + + <EditText android:id="@+id/entry_2" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:layout_below="@id/label_2"/> + + <Button android:id="@+id/ok_2" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_below="@id/entry_2" + android:layout_alignParentRight="true" + android:layout_marginLeft="10px" + android:text="OK"/> + + <Button android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_toLeftOf="@id/ok_2" + android:layout_alignTop="@id/ok_2" + android:text="Cancel"/> + </RelativeLayout> + + <RelativeLayout android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:background="#FF000000" + android:padding="10px" + android:layoutDirection="inherit"> + + <TextView android:id="@+id/label_3" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:text="Type here:"/> + + <EditText android:id="@+id/entry_3" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:layout_below="@id/label_3"/> + + <Button android:id="@+id/ok_3" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_below="@id/entry_3" + android:layout_alignParentRight="true" + android:layout_marginLeft="10px" + android:text="OK"/> + + <Button android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_toLeftOf="@id/ok_3" + android:layout_alignTop="@id/ok_3" + android:text="Cancel"/> + </RelativeLayout> + + <RelativeLayout android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:background="#FF000000" + android:padding="10px" + android:layoutDirection="rtl"> + + <TextView android:id="@+id/label_4" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:text="Type here:"/> + + <EditText android:id="@+id/entry_4" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:layout_below="@id/label_4"/> + + <Button android:id="@+id/ok_4" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_below="@id/entry_4" + android:layout_alignParentRight="true" + android:layout_marginLeft="10px" + android:text="OK"/> + + <Button android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_toLeftOf="@id/ok_4" + android:layout_alignTop="@id/ok_4" + android:text="Cancel"/> + </RelativeLayout> + + <RelativeLayout android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:background="#FF000000" + android:padding="10px" + android:layoutDirection="locale"> + + <TextView android:id="@+id/label_4" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:text="Type here:"/> + + <EditText android:id="@+id/entry_4" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:layout_below="@id/label_4"/> + + <Button android:id="@+id/ok_4" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_below="@id/entry_4" + android:layout_alignParentRight="true" + android:layout_marginLeft="10px" + android:text="OK"/> + + <Button android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_toLeftOf="@id/ok_4" + android:layout_alignTop="@id/ok_4" + android:text="Cancel"/> + </RelativeLayout> + + </LinearLayout> + +</FrameLayout>
\ No newline at end of file diff --git a/tests/BiDiTests/res/layout/relative_layout_2_ltr.xml b/tests/BiDiTests/res/layout/relative_layout_2_ltr.xml new file mode 100644 index 000000000000..cf585b5aa1b8 --- /dev/null +++ b/tests/BiDiTests/res/layout/relative_layout_2_ltr.xml @@ -0,0 +1,183 @@ +<?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. +--> + +<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/relative_layout_2_ltr" + android:layout_width="fill_parent" + android:layout_height="fill_parent"> + + <LinearLayout android:orientation="vertical" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:layoutDirection="ltr"> + + <RelativeLayout android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:background="#FF000000" + android:padding="10px"> + + <TextView android:id="@+id/label_1" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:text="Type here:"/> + + <EditText android:id="@+id/entry_1" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:layout_below="@id/label_1"/> + + <Button android:id="@+id/ok_1" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_below="@id/entry_1" + android:layout_alignParentRight="true" + android:layout_marginLeft="10px" + android:text="OK"/> + + <Button android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_toLeftOf="@id/ok_1" + android:layout_alignTop="@id/ok_1" + android:text="Cancel"/> + </RelativeLayout> + + <RelativeLayout android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:background="#FF000000" + android:padding="10px" + android:layoutDirection="ltr"> + + <TextView android:id="@+id/label_2" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:text="Type here:"/> + + <EditText android:id="@+id/entry_2" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:layout_below="@id/label_2"/> + + <Button android:id="@+id/ok_2" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_below="@id/entry_2" + android:layout_alignParentRight="true" + android:layout_marginLeft="10px" + android:text="OK"/> + + <Button android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_toLeftOf="@id/ok_2" + android:layout_alignTop="@id/ok_2" + android:text="Cancel"/> + </RelativeLayout> + + <RelativeLayout android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:background="#FF000000" + android:padding="10px" + android:layoutDirection="inherit"> + + <TextView android:id="@+id/label_3" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:text="Type here:"/> + + <EditText android:id="@+id/entry_3" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:layout_below="@id/label_3"/> + + <Button android:id="@+id/ok_3" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_below="@id/entry_3" + android:layout_alignParentRight="true" + android:layout_marginLeft="10px" + android:text="OK"/> + + <Button android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_toLeftOf="@id/ok_3" + android:layout_alignTop="@id/ok_3" + android:text="Cancel"/> + </RelativeLayout> + + <RelativeLayout android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:background="#FF000000" + android:padding="10px" + android:layoutDirection="rtl"> + + <TextView android:id="@+id/label_4" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:text="Type here:"/> + + <EditText android:id="@+id/entry_4" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:layout_below="@id/label_4"/> + + <Button android:id="@+id/ok_4" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_below="@id/entry_4" + android:layout_alignParentRight="true" + android:layout_marginLeft="10px" + android:text="OK"/> + + <Button android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_toLeftOf="@id/ok_4" + android:layout_alignTop="@id/ok_4" + android:text="Cancel"/> + </RelativeLayout> + + <RelativeLayout android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:background="#FF000000" + android:padding="10px" + android:layoutDirection="locale"> + + <TextView android:id="@+id/label_4" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:text="Type here:"/> + + <EditText android:id="@+id/entry_4" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:layout_below="@id/label_4"/> + + <Button android:id="@+id/ok_4" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_below="@id/entry_4" + android:layout_alignParentRight="true" + android:layout_marginLeft="10px" + android:text="OK"/> + + <Button android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_toLeftOf="@id/ok_4" + android:layout_alignTop="@id/ok_4" + android:text="Cancel"/> + </RelativeLayout> + + </LinearLayout> + +</FrameLayout>
\ No newline at end of file diff --git a/tests/BiDiTests/res/layout/relative_layout_2_rtl.xml b/tests/BiDiTests/res/layout/relative_layout_2_rtl.xml new file mode 100644 index 000000000000..729f1ca36a56 --- /dev/null +++ b/tests/BiDiTests/res/layout/relative_layout_2_rtl.xml @@ -0,0 +1,183 @@ +<?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. +--> + +<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/relative_layout_2_rtl" + android:layout_width="fill_parent" + android:layout_height="fill_parent"> + + <LinearLayout android:orientation="vertical" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:layoutDirection="rtl"> + + <RelativeLayout android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:background="#FF000000" + android:padding="10px"> + + <TextView android:id="@+id/label_1" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:text="Type here:"/> + + <EditText android:id="@+id/entry_1" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:layout_below="@id/label_1"/> + + <Button android:id="@+id/ok_1" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_below="@id/entry_1" + android:layout_alignParentRight="true" + android:layout_marginLeft="10px" + android:text="OK"/> + + <Button android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_toLeftOf="@id/ok_1" + android:layout_alignTop="@id/ok_1" + android:text="Cancel"/> + </RelativeLayout> + + <RelativeLayout android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:background="#FF000000" + android:padding="10px" + android:layoutDirection="ltr"> + + <TextView android:id="@+id/label_2" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:text="Type here:"/> + + <EditText android:id="@+id/entry_2" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:layout_below="@id/label_2"/> + + <Button android:id="@+id/ok_2" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_below="@id/entry_2" + android:layout_alignParentRight="true" + android:layout_marginLeft="10px" + android:text="OK"/> + + <Button android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_toLeftOf="@id/ok_2" + android:layout_alignTop="@id/ok_2" + android:text="Cancel"/> + </RelativeLayout> + + <RelativeLayout android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:background="#FF000000" + android:padding="10px" + android:layoutDirection="inherit"> + + <TextView android:id="@+id/label_3" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:text="Type here:"/> + + <EditText android:id="@+id/entry_3" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:layout_below="@id/label_3"/> + + <Button android:id="@+id/ok_3" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_below="@id/entry_3" + android:layout_alignParentRight="true" + android:layout_marginLeft="10px" + android:text="OK"/> + + <Button android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_toLeftOf="@id/ok_3" + android:layout_alignTop="@id/ok_3" + android:text="Cancel"/> + </RelativeLayout> + + <RelativeLayout android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:background="#FF000000" + android:padding="10px" + android:layoutDirection="rtl"> + + <TextView android:id="@+id/label_4" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:text="Type here:"/> + + <EditText android:id="@+id/entry_4" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:layout_below="@id/label_4"/> + + <Button android:id="@+id/ok_4" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_below="@id/entry_4" + android:layout_alignParentRight="true" + android:layout_marginLeft="10px" + android:text="OK"/> + + <Button android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_toLeftOf="@id/ok_4" + android:layout_alignTop="@id/ok_4" + android:text="Cancel"/> + </RelativeLayout> + + <RelativeLayout android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:background="#FF000000" + android:padding="10px" + android:layoutDirection="locale"> + + <TextView android:id="@+id/label_4" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:text="Type here:"/> + + <EditText android:id="@+id/entry_4" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:layout_below="@id/label_4"/> + + <Button android:id="@+id/ok_4" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_below="@id/entry_4" + android:layout_alignParentRight="true" + android:layout_marginLeft="10px" + android:text="OK"/> + + <Button android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_toLeftOf="@id/ok_4" + android:layout_alignTop="@id/ok_4" + android:text="Cancel"/> + </RelativeLayout> + + </LinearLayout> + +</FrameLayout>
\ No newline at end of file diff --git a/tests/BiDiTests/res/layout/relative_layout_ltr.xml b/tests/BiDiTests/res/layout/relative_layout_ltr.xml index d789707dfe62..461ec989bc63 100644 --- a/tests/BiDiTests/res/layout/relative_layout_ltr.xml +++ b/tests/BiDiTests/res/layout/relative_layout_ltr.xml @@ -15,74 +15,78 @@ --> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:id="@+id/frame_layout_ltr" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:layoutDirection="ltr" - android:background="#FF000000"> + android:id="@+id/relative_layout_ltr" + android:layout_width="fill_parent" + android:layout_height="fill_parent"> + + <FrameLayout android:layout_width="match_parent" + android:layout_height="match_parent" + android:layoutDirection="ltr" + android:background="#FF000000"> <RelativeLayout - android:layout_width="100dp" - android:layout_height="100dp" - android:layout_gravity="right|center_vertical" - android:background="#FFFF0000"> + android:layout_width="100dp" + android:layout_height="100dp" + android:layout_gravity="right|center_vertical" + android:background="#FFFF0000"> </RelativeLayout> <RelativeLayout - android:layout_width="100dp" - android:layout_height="100dp" - android:layout_gravity="left|center_vertical" - android:background="#FF00FF00"> + android:layout_width="100dp" + android:layout_height="100dp" + android:layout_gravity="left|center_vertical" + android:background="#FF00FF00"> </RelativeLayout> <RelativeLayout - android:layout_width="100dp" - android:layout_height="100dp" - android:layout_gravity="top|center_horizontal" - android:background="#FF0000FF"> + android:layout_width="100dp" + android:layout_height="100dp" + android:layout_gravity="top|center_horizontal" + android:background="#FF0000FF"> </RelativeLayout> <RelativeLayout - android:layout_width="100dp" - android:layout_height="100dp" - android:layout_gravity="bottom|center_horizontal" - android:background="#FF00FFFF"> + android:layout_width="100dp" + android:layout_height="100dp" + android:layout_gravity="bottom|center_horizontal" + android:background="#FF00FFFF"> </RelativeLayout> <RelativeLayout - android:layout_width="100dp" - android:layout_height="100dp" - android:layout_gravity="top|start" - android:background="#FFFFFFFF"> + android:layout_width="100dp" + android:layout_height="100dp" + android:layout_gravity="top|start" + android:background="#FFFFFFFF"> </RelativeLayout> <RelativeLayout - android:layout_width="100dp" - android:layout_height="100dp" - android:layout_gravity="top|end" - android:background="#FFFFFF00"> + android:layout_width="100dp" + android:layout_height="100dp" + android:layout_gravity="top|end" + android:background="#FFFFFF00"> </RelativeLayout> <RelativeLayout - android:layout_width="100dp" - android:layout_height="100dp" - android:layout_gravity="bottom|start" - android:background="#FFFFFFFF"> + android:layout_width="100dp" + android:layout_height="100dp" + android:layout_gravity="bottom|start" + android:background="#FFFFFFFF"> </RelativeLayout> <RelativeLayout - android:layout_width="100dp" - android:layout_height="100dp" - android:layout_gravity="bottom|end" - android:background="#FFFFFF00"> + android:layout_width="100dp" + android:layout_height="100dp" + android:layout_gravity="bottom|end" + android:background="#FFFFFF00"> </RelativeLayout> <RelativeLayout - android:layout_width="100dp" - android:layout_height="100dp" - android:layout_gravity="center_horizontal|center_vertical" - android:background="#FF888888"> + android:layout_width="100dp" + android:layout_height="100dp" + android:layout_gravity="center_horizontal|center_vertical" + android:background="#FF888888"> </RelativeLayout> + + </FrameLayout> -</FrameLayout> - +</FrameLayout>
\ No newline at end of file diff --git a/tests/BiDiTests/res/layout/relative_layout_ltr_2.xml b/tests/BiDiTests/res/layout/relative_layout_ltr_2.xml deleted file mode 100644 index a13ef8bfc0ad..000000000000 --- a/tests/BiDiTests/res/layout/relative_layout_ltr_2.xml +++ /dev/null @@ -1,155 +0,0 @@ -<?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:id="@+id/relative_layout_ltr" - android:orientation="vertical" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:layoutDirection="ltr"> - - <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="fill_parent" - android:layout_height="wrap_content" - android:background="#FF000000" - android:padding="10px"> - - <TextView android:id="@+id/label_1" - android:layout_width="fill_parent" - android:layout_height="wrap_content" - android:text="Type here:" /> - - <EditText android:id="@+id/entry_1" - android:layout_width="fill_parent" - android:layout_height="wrap_content" - android:layout_below="@id/label_1" /> - - <Button android:id="@+id/ok_1" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_below="@id/entry_1" - android:layout_alignParentRight="true" - android:layout_marginLeft="10px" - android:text="OK" /> - - <Button android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_toLeftOf="@id/ok_1" - android:layout_alignTop="@id/ok_1" - android:text="Cancel" /> - - </RelativeLayout> - - <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="fill_parent" - android:layout_height="wrap_content" - android:background="#FF000000" - android:padding="10px" - android:layoutDirection="ltr"> - - <TextView android:id="@+id/label_2" - android:layout_width="fill_parent" - android:layout_height="wrap_content" - android:text="Type here:" /> - - <EditText android:id="@+id/entry_2" - android:layout_width="fill_parent" - android:layout_height="wrap_content" - android:layout_below="@id/label_2" /> - - <Button android:id="@+id/ok_2" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_below="@id/entry_2" - android:layout_alignParentRight="true" - android:layout_marginLeft="10px" - android:text="OK" /> - - <Button android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_toLeftOf="@id/ok_2" - android:layout_alignTop="@id/ok_2" - android:text="Cancel" /> - - </RelativeLayout> - - <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="fill_parent" - android:layout_height="wrap_content" - android:background="#FF000000" - android:padding="10px" - android:layoutDirection="inherit"> - - <TextView android:id="@+id/label_3" - android:layout_width="fill_parent" - android:layout_height="wrap_content" - android:text="Type here:" /> - - <EditText android:id="@+id/entry_3" - android:layout_width="fill_parent" - android:layout_height="wrap_content" - android:layout_below="@id/label_3" /> - - <Button android:id="@+id/ok_3" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_below="@id/entry_3" - android:layout_alignParentRight="true" - android:layout_marginLeft="10px" - android:text="OK" /> - - <Button android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_toLeftOf="@id/ok_3" - android:layout_alignTop="@id/ok_3" - android:text="Cancel" /> - - </RelativeLayout> - - <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="fill_parent" - android:layout_height="wrap_content" - android:background="#FF000000" - android:padding="10px" - android:layoutDirection="rtl"> - - <TextView android:id="@+id/label_4" - android:layout_width="fill_parent" - android:layout_height="wrap_content" - android:text="Type here:" /> - - <EditText android:id="@+id/entry_4" - android:layout_width="fill_parent" - android:layout_height="wrap_content" - android:layout_below="@id/label_4" /> - - <Button android:id="@+id/ok_4" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_below="@id/entry_4" - android:layout_alignParentRight="true" - android:layout_marginLeft="10px" - android:text="OK" /> - - <Button android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_toLeftOf="@id/ok_4" - android:layout_alignTop="@id/ok_4" - android:text="Cancel" /> - - </RelativeLayout> - -</LinearLayout>
\ No newline at end of file diff --git a/tests/BiDiTests/res/layout/relative_layout_rtl.xml b/tests/BiDiTests/res/layout/relative_layout_rtl.xml index 580892474206..545d16ebf2fd 100644 --- a/tests/BiDiTests/res/layout/relative_layout_rtl.xml +++ b/tests/BiDiTests/res/layout/relative_layout_rtl.xml @@ -15,74 +15,78 @@ --> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:id="@+id/frame_layout_rtl" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:layoutDirection="rtl" - android:background="#FF000000"> + android:id="@+id/relative_layout_rtl" + android:layout_width="fill_parent" + android:layout_height="fill_parent"> + + <FrameLayout android:layout_width="match_parent" + android:layout_height="match_parent" + android:layoutDirection="rtl" + android:background="#FF000000"> <RelativeLayout - android:layout_width="100dp" - android:layout_height="100dp" - android:layout_gravity="right|center_vertical" - android:background="#FFFF0000"> + android:layout_width="100dp" + android:layout_height="100dp" + android:layout_gravity="right|center_vertical" + android:background="#FFFF0000"> </RelativeLayout> <RelativeLayout - android:layout_width="100dp" - android:layout_height="100dp" - android:layout_gravity="left|center_vertical" - android:background="#FF00FF00"> + android:layout_width="100dp" + android:layout_height="100dp" + android:layout_gravity="left|center_vertical" + android:background="#FF00FF00"> </RelativeLayout> <RelativeLayout - android:layout_width="100dp" - android:layout_height="100dp" - android:layout_gravity="top|center_horizontal" - android:background="#FF0000FF"> + android:layout_width="100dp" + android:layout_height="100dp" + android:layout_gravity="top|center_horizontal" + android:background="#FF0000FF"> </RelativeLayout> <RelativeLayout - android:layout_width="100dp" - android:layout_height="100dp" - android:layout_gravity="bottom|center_horizontal" - android:background="#FF00FFFF"> + android:layout_width="100dp" + android:layout_height="100dp" + android:layout_gravity="bottom|center_horizontal" + android:background="#FF00FFFF"> </RelativeLayout> <RelativeLayout - android:layout_width="100dp" - android:layout_height="100dp" - android:layout_gravity="top|start" - android:background="#FFFFFFFF"> + android:layout_width="100dp" + android:layout_height="100dp" + android:layout_gravity="top|start" + android:background="#FFFFFFFF"> </RelativeLayout> <RelativeLayout - android:layout_width="100dp" - android:layout_height="100dp" - android:layout_gravity="top|end" - android:background="#FFFFFF00"> + android:layout_width="100dp" + android:layout_height="100dp" + android:layout_gravity="top|end" + android:background="#FFFFFF00"> </RelativeLayout> <RelativeLayout - android:layout_width="100dp" - android:layout_height="100dp" - android:layout_gravity="bottom|start" - android:background="#FFFFFFFF"> + android:layout_width="100dp" + android:layout_height="100dp" + android:layout_gravity="bottom|start" + android:background="#FFFFFFFF"> </RelativeLayout> <RelativeLayout - android:layout_width="100dp" - android:layout_height="100dp" - android:layout_gravity="bottom|end" - android:background="#FFFFFF00"> + android:layout_width="100dp" + android:layout_height="100dp" + android:layout_gravity="bottom|end" + android:background="#FFFFFF00"> </RelativeLayout> <RelativeLayout - android:layout_width="100dp" - android:layout_height="100dp" - android:layout_gravity="center_horizontal|center_vertical" - android:background="#FF888888"> + android:layout_width="100dp" + android:layout_height="100dp" + android:layout_gravity="center_horizontal|center_vertical" + android:background="#FF888888"> </RelativeLayout> + + </FrameLayout> -</FrameLayout> - +</FrameLayout>
\ No newline at end of file diff --git a/tests/BiDiTests/res/layout/relative_layout_rtl_2.xml b/tests/BiDiTests/res/layout/relative_layout_rtl_2.xml deleted file mode 100644 index 1a6b3d54a04d..000000000000 --- a/tests/BiDiTests/res/layout/relative_layout_rtl_2.xml +++ /dev/null @@ -1,155 +0,0 @@ -<?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:id="@+id/relative_layout_ltr" - android:orientation="vertical" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:layoutDirection="rtl"> - - <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="fill_parent" - android:layout_height="wrap_content" - android:background="#FF000000" - android:padding="10px"> - - <TextView android:id="@+id/label_1" - android:layout_width="fill_parent" - android:layout_height="wrap_content" - android:text="Type here:" /> - - <EditText android:id="@+id/entry_1" - android:layout_width="fill_parent" - android:layout_height="wrap_content" - android:layout_below="@id/label_1" /> - - <Button android:id="@+id/ok_1" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_below="@id/entry_1" - android:layout_alignParentRight="true" - android:layout_marginLeft="10px" - android:text="OK" /> - - <Button android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_toLeftOf="@id/ok_1" - android:layout_alignTop="@id/ok_1" - android:text="Cancel" /> - - </RelativeLayout> - - <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="fill_parent" - android:layout_height="wrap_content" - android:background="#FF000000" - android:padding="10px" - android:layoutDirection="ltr"> - - <TextView android:id="@+id/label_2" - android:layout_width="fill_parent" - android:layout_height="wrap_content" - android:text="Type here:" /> - - <EditText android:id="@+id/entry_2" - android:layout_width="fill_parent" - android:layout_height="wrap_content" - android:layout_below="@id/label_2" /> - - <Button android:id="@+id/ok_2" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_below="@id/entry_2" - android:layout_alignParentRight="true" - android:layout_marginLeft="10px" - android:text="OK" /> - - <Button android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_toLeftOf="@id/ok_2" - android:layout_alignTop="@id/ok_2" - android:text="Cancel" /> - - </RelativeLayout> - - <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="fill_parent" - android:layout_height="wrap_content" - android:background="#FF000000" - android:padding="10px" - android:layoutDirection="inherit"> - - <TextView android:id="@+id/label_3" - android:layout_width="fill_parent" - android:layout_height="wrap_content" - android:text="Type here:" /> - - <EditText android:id="@+id/entry_3" - android:layout_width="fill_parent" - android:layout_height="wrap_content" - android:layout_below="@id/label_3" /> - - <Button android:id="@+id/ok_3" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_below="@id/entry_3" - android:layout_alignParentRight="true" - android:layout_marginLeft="10px" - android:text="OK" /> - - <Button android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_toLeftOf="@id/ok_3" - android:layout_alignTop="@id/ok_3" - android:text="Cancel" /> - - </RelativeLayout> - - <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="fill_parent" - android:layout_height="wrap_content" - android:background="#FF000000" - android:padding="10px" - android:layoutDirection="rtl"> - - <TextView android:id="@+id/label_4" - android:layout_width="fill_parent" - android:layout_height="wrap_content" - android:text="Type here:" /> - - <EditText android:id="@+id/entry_4" - android:layout_width="fill_parent" - android:layout_height="wrap_content" - android:layout_below="@id/label_4" /> - - <Button android:id="@+id/ok_4" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_below="@id/entry_4" - android:layout_alignParentRight="true" - android:layout_marginLeft="10px" - android:text="OK" /> - - <Button android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_toLeftOf="@id/ok_4" - android:layout_alignTop="@id/ok_4" - android:text="Cancel" /> - - </RelativeLayout> - -</LinearLayout>
\ No newline at end of file diff --git a/tests/BiDiTests/res/layout/table_layout_locale.xml b/tests/BiDiTests/res/layout/table_layout_locale.xml new file mode 100644 index 000000000000..2589b405ad68 --- /dev/null +++ b/tests/BiDiTests/res/layout/table_layout_locale.xml @@ -0,0 +1,258 @@ +<?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. +--> + +<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/table_layout_locale" + android:layout_width="fill_parent" + android:layout_height="fill_parent"> + + <LinearLayout android:orientation="vertical" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:layoutDirection="locale"> + + <TableLayout android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:stretchColumns="1,2"> + + <TableRow> + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button1_text" + android:textSize="24dip" + /> + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button_right_text" + android:textSize="24dip" + android:gravity="right" + /> + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button_after_text" + android:textSize="24dip" + android:gravity="after" + /> + </TableRow> + + <TableRow> + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button2_text" + android:textSize="24dip" + /> + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button_left_text" + android:textSize="24dip" + android:gravity="left" + /> + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button_before_text" + android:textSize="24dip" + android:gravity="before" + /> + </TableRow> + </TableLayout> + + <TableLayout android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:stretchColumns="1,2" + android:layoutDirection="inherit"> + + <TableRow> + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button1_text" + android:textSize="24dip" + /> + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button_right_text" + android:textSize="24dip" + android:gravity="right" + /> + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button_after_text" + android:textSize="24dip" + android:gravity="after" + /> + </TableRow> + + <TableRow> + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button2_text" + android:textSize="24dip" + /> + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button_left_text" + android:textSize="24dip" + android:gravity="left" + /> + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button_before_text" + android:textSize="24dip" + android:gravity="before" + /> + </TableRow> + </TableLayout> + + <TableLayout android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:stretchColumns="1,2" + android:layoutDirection="ltr"> + + <TableRow> + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button1_text" + android:textSize="24dip" + /> + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button_right_text" + android:textSize="24dip" + android:gravity="right" + /> + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button_after_text" + android:textSize="24dip" + android:gravity="after" + /> + </TableRow> + + <TableRow> + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button2_text" + android:textSize="24dip" + /> + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button_left_text" + android:textSize="24dip" + android:gravity="left" + /> + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button_before_text" + android:textSize="24dip" + android:gravity="before" + /> + </TableRow> + </TableLayout> + + <TableLayout android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:stretchColumns="1,2" + android:layoutDirection="rtl"> + + <TableRow> + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button1_text" + android:textSize="24dip" + /> + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button_right_text" + android:textSize="24dip" + android:gravity="right" + /> + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button_after_text" + android:textSize="24dip" + android:gravity="after" + /> + </TableRow> + + <TableRow> + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button2_text" + android:textSize="24dip" + /> + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button_left_text" + android:textSize="24dip" + android:gravity="left" + /> + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button_before_text" + android:textSize="24dip" + android:gravity="before" + /> + </TableRow> + </TableLayout> + + <TableLayout android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:stretchColumns="1,2" + android:layoutDirection="locale"> + + <TableRow> + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button1_text" + android:textSize="24dip" + /> + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button_right_text" + android:textSize="24dip" + android:gravity="right" + /> + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button_after_text" + android:textSize="24dip" + android:gravity="after" + /> + </TableRow> + + <TableRow> + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button2_text" + android:textSize="24dip" + /> + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button_left_text" + android:textSize="24dip" + android:gravity="left" + /> + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button_before_text" + android:textSize="24dip" + android:gravity="before" + /> + </TableRow> + </TableLayout> + + </LinearLayout> + +</FrameLayout>
\ No newline at end of file diff --git a/tests/BiDiTests/res/layout/table_layout_ltr.xml b/tests/BiDiTests/res/layout/table_layout_ltr.xml index 8e1891e7014c..d8d412ced44b 100644 --- a/tests/BiDiTests/res/layout/table_layout_ltr.xml +++ b/tests/BiDiTests/res/layout/table_layout_ltr.xml @@ -14,202 +14,245 @@ limitations under the License. --> -<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:id="@+id/linear_layout_ltr" - android:orientation="vertical" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:layoutDirection="ltr"> - - <TableLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:stretchColumns="1,2"> - - <TableRow> - <Button android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:text="@string/button1_text" - android:textSize="24dip" - /> - <Button android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:text="@string/button_right_text" - android:textSize="24dip" - android:gravity="right" - /> - <Button android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:text="@string/button_after_text" - android:textSize="24dip" - android:gravity="after" - /> - </TableRow> - - <TableRow> - <Button android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:text="@string/button2_text" - android:textSize="24dip" - /> - <Button android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:text="@string/button_left_text" - android:textSize="24dip" - android:gravity="left" - /> - <Button android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:text="@string/button_before_text" - android:textSize="24dip" - android:gravity="before" - /> - </TableRow> - - </TableLayout> - - <TableLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:stretchColumns="1,2" - android:layoutDirection="inherit"> - - <TableRow> - <Button android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:text="@string/button1_text" - android:textSize="24dip" - /> - <Button android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:text="@string/button_right_text" - android:textSize="24dip" - android:gravity="right" - /> - <Button android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:text="@string/button_after_text" - android:textSize="24dip" - android:gravity="after" - /> - </TableRow> - - <TableRow> - <Button android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:text="@string/button2_text" - android:textSize="24dip" - /> - <Button android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:text="@string/button_left_text" - android:textSize="24dip" - android:gravity="left" - /> - <Button android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:text="@string/button_before_text" - android:textSize="24dip" - android:gravity="before" - /> - </TableRow> - - </TableLayout> - - <TableLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:stretchColumns="1,2" - android:layoutDirection="ltr"> - - <TableRow> - <Button android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:text="@string/button1_text" - android:textSize="24dip" - /> - <Button android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:text="@string/button_right_text" - android:textSize="24dip" - android:gravity="right" - /> - <Button android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:text="@string/button_after_text" - android:textSize="24dip" - android:gravity="after" - /> - </TableRow> - - <TableRow> - <Button android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:text="@string/button2_text" - android:textSize="24dip" - /> - <Button android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:text="@string/button_left_text" - android:textSize="24dip" - android:gravity="left" - /> - <Button android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:text="@string/button_before_text" - android:textSize="24dip" - android:gravity="before" - /> - </TableRow> - - </TableLayout> - - <TableLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:stretchColumns="1,2" - android:layoutDirection="rtl"> - - <TableRow> - <Button android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:text="@string/button1_text" - android:textSize="24dip" - /> - <Button android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:text="@string/button_right_text" - android:textSize="24dip" - android:gravity="right" - /> - <Button android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:text="@string/button_after_text" - android:textSize="24dip" - android:gravity="after" - /> - </TableRow> - - <TableRow> - <Button android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:text="@string/button2_text" - android:textSize="24dip" - /> - <Button android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:text="@string/button_left_text" - android:textSize="24dip" - android:gravity="left" - /> - <Button android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:text="@string/button_before_text" - android:textSize="24dip" - android:gravity="before" - /> - </TableRow> - - </TableLayout> - -</LinearLayout>
\ No newline at end of file +<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/table_layout_ltr" + android:layout_width="fill_parent" + android:layout_height="fill_parent"> + + <LinearLayout android:orientation="vertical" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:layoutDirection="ltr"> + + <TableLayout android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:stretchColumns="1,2"> + + <TableRow> + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button1_text" + android:textSize="24dip" + /> + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button_right_text" + android:textSize="24dip" + android:gravity="right" + /> + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button_after_text" + android:textSize="24dip" + android:gravity="after" + /> + </TableRow> + + <TableRow> + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button2_text" + android:textSize="24dip" + /> + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button_left_text" + android:textSize="24dip" + android:gravity="left" + /> + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button_before_text" + android:textSize="24dip" + android:gravity="before" + /> + </TableRow> + </TableLayout> + + <TableLayout android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:stretchColumns="1,2" + android:layoutDirection="inherit"> + + <TableRow> + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button1_text" + android:textSize="24dip" + /> + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button_right_text" + android:textSize="24dip" + android:gravity="right" + /> + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button_after_text" + android:textSize="24dip" + android:gravity="after" + /> + </TableRow> + + <TableRow> + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button2_text" + android:textSize="24dip" + /> + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button_left_text" + android:textSize="24dip" + android:gravity="left" + /> + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button_before_text" + android:textSize="24dip" + android:gravity="before" + /> + </TableRow> + </TableLayout> + + <TableLayout android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:stretchColumns="1,2" + android:layoutDirection="ltr"> + + <TableRow> + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button1_text" + android:textSize="24dip" + /> + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button_right_text" + android:textSize="24dip" + android:gravity="right" + /> + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button_after_text" + android:textSize="24dip" + android:gravity="after" + /> + </TableRow> + + <TableRow> + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button2_text" + android:textSize="24dip" + /> + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button_left_text" + android:textSize="24dip" + android:gravity="left" + /> + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button_before_text" + android:textSize="24dip" + android:gravity="before" + /> + </TableRow> + </TableLayout> + + <TableLayout android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:stretchColumns="1,2" + android:layoutDirection="rtl"> + + <TableRow> + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button1_text" + android:textSize="24dip" + /> + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button_right_text" + android:textSize="24dip" + android:gravity="right" + /> + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button_after_text" + android:textSize="24dip" + android:gravity="after" + /> + </TableRow> + + <TableRow> + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button2_text" + android:textSize="24dip" + /> + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button_left_text" + android:textSize="24dip" + android:gravity="left" + /> + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button_before_text" + android:textSize="24dip" + android:gravity="before" + /> + </TableRow> + </TableLayout> + + <TableLayout android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:stretchColumns="1,2" + android:layoutDirection="locale"> + + <TableRow> + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button1_text" + android:textSize="24dip" + /> + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button_right_text" + android:textSize="24dip" + android:gravity="right" + /> + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button_after_text" + android:textSize="24dip" + android:gravity="after" + /> + </TableRow> + + <TableRow> + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button2_text" + android:textSize="24dip" + /> + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button_left_text" + android:textSize="24dip" + android:gravity="left" + /> + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button_before_text" + android:textSize="24dip" + android:gravity="before" + /> + </TableRow> + </TableLayout> + + </LinearLayout> + +</FrameLayout>
\ No newline at end of file diff --git a/tests/BiDiTests/res/layout/table_layout_rtl.xml b/tests/BiDiTests/res/layout/table_layout_rtl.xml index bd664e4900db..53130fe273a0 100644 --- a/tests/BiDiTests/res/layout/table_layout_rtl.xml +++ b/tests/BiDiTests/res/layout/table_layout_rtl.xml @@ -14,202 +14,245 @@ limitations under the License. --> -<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:id="@+id/linear_layout_ltr" - android:orientation="vertical" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:layoutDirection="rtl"> - - <TableLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:stretchColumns="1,2"> - - <TableRow> - <Button android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:text="@string/button1_text" - android:textSize="24dip" - /> - <Button android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:text="@string/button_right_text" - android:textSize="24dip" - android:gravity="right" - /> - <Button android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:text="@string/button_after_text" - android:textSize="24dip" - android:gravity="after" - /> - </TableRow> - - <TableRow> - <Button android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:text="@string/button2_text" - android:textSize="24dip" - /> - <Button android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:text="@string/button_left_text" - android:textSize="24dip" - android:gravity="left" - /> - <Button android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:text="@string/button_before_text" - android:textSize="24dip" - android:gravity="before" - /> - </TableRow> - - </TableLayout> - - <TableLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:stretchColumns="1,2" - android:layoutDirection="inherit"> - - <TableRow> - <Button android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:text="@string/button1_text" - android:textSize="24dip" - /> - <Button android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:text="@string/button_right_text" - android:textSize="24dip" - android:gravity="right" - /> - <Button android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:text="@string/button_after_text" - android:textSize="24dip" - android:gravity="after" - /> - </TableRow> - - <TableRow> - <Button android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:text="@string/button2_text" - android:textSize="24dip" - /> - <Button android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:text="@string/button_left_text" - android:textSize="24dip" - android:gravity="left" - /> - <Button android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:text="@string/button_before_text" - android:textSize="24dip" - android:gravity="before" - /> - </TableRow> - - </TableLayout> - - <TableLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:stretchColumns="1,2" - android:layoutDirection="ltr"> - - <TableRow> - <Button android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:text="@string/button1_text" - android:textSize="24dip" - /> - <Button android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:text="@string/button_right_text" - android:textSize="24dip" - android:gravity="right" - /> - <Button android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:text="@string/button_after_text" - android:textSize="24dip" - android:gravity="after" - /> - </TableRow> - - <TableRow> - <Button android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:text="@string/button2_text" - android:textSize="24dip" - /> - <Button android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:text="@string/button_left_text" - android:textSize="24dip" - android:gravity="left" - /> - <Button android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:text="@string/button_before_text" - android:textSize="24dip" - android:gravity="before" - /> - </TableRow> - - </TableLayout> - - <TableLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:stretchColumns="1,2" - android:layoutDirection="rtl"> - - <TableRow> - <Button android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:text="@string/button1_text" - android:textSize="24dip" - /> - <Button android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:text="@string/button_right_text" - android:textSize="24dip" - android:gravity="right" - /> - <Button android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:text="@string/button_after_text" - android:textSize="24dip" - android:gravity="after" - /> - </TableRow> - - <TableRow> - <Button android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:text="@string/button2_text" - android:textSize="24dip" - /> - <Button android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:text="@string/button_left_text" - android:textSize="24dip" - android:gravity="left" - /> - <Button android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:text="@string/button_before_text" - android:textSize="24dip" - android:gravity="before" - /> - </TableRow> - - </TableLayout> - -</LinearLayout>
\ No newline at end of file +<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/table_layout_rtl" + android:layout_width="fill_parent" + android:layout_height="fill_parent"> + + <LinearLayout android:orientation="vertical" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:layoutDirection="rtl"> + + <TableLayout android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:stretchColumns="1,2"> + + <TableRow> + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button1_text" + android:textSize="24dip" + /> + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button_right_text" + android:textSize="24dip" + android:gravity="right" + /> + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button_after_text" + android:textSize="24dip" + android:gravity="after" + /> + </TableRow> + + <TableRow> + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button2_text" + android:textSize="24dip" + /> + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button_left_text" + android:textSize="24dip" + android:gravity="left" + /> + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button_before_text" + android:textSize="24dip" + android:gravity="before" + /> + </TableRow> + </TableLayout> + + <TableLayout android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:stretchColumns="1,2" + android:layoutDirection="inherit"> + + <TableRow> + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button1_text" + android:textSize="24dip" + /> + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button_right_text" + android:textSize="24dip" + android:gravity="right" + /> + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button_after_text" + android:textSize="24dip" + android:gravity="after" + /> + </TableRow> + + <TableRow> + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button2_text" + android:textSize="24dip" + /> + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button_left_text" + android:textSize="24dip" + android:gravity="left" + /> + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button_before_text" + android:textSize="24dip" + android:gravity="before" + /> + </TableRow> + </TableLayout> + + <TableLayout android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:stretchColumns="1,2" + android:layoutDirection="ltr"> + + <TableRow> + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button1_text" + android:textSize="24dip" + /> + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button_right_text" + android:textSize="24dip" + android:gravity="right" + /> + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button_after_text" + android:textSize="24dip" + android:gravity="after" + /> + </TableRow> + + <TableRow> + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button2_text" + android:textSize="24dip" + /> + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button_left_text" + android:textSize="24dip" + android:gravity="left" + /> + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button_before_text" + android:textSize="24dip" + android:gravity="before" + /> + </TableRow> + </TableLayout> + + <TableLayout android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:stretchColumns="1,2" + android:layoutDirection="rtl"> + + <TableRow> + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button1_text" + android:textSize="24dip" + /> + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button_right_text" + android:textSize="24dip" + android:gravity="right" + /> + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button_after_text" + android:textSize="24dip" + android:gravity="after" + /> + </TableRow> + + <TableRow> + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button2_text" + android:textSize="24dip" + /> + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button_left_text" + android:textSize="24dip" + android:gravity="left" + /> + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button_before_text" + android:textSize="24dip" + android:gravity="before" + /> + </TableRow> + </TableLayout> + + <TableLayout android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:stretchColumns="1,2" + android:layoutDirection="locale"> + + <TableRow> + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button1_text" + android:textSize="24dip" + /> + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button_right_text" + android:textSize="24dip" + android:gravity="right" + /> + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button_after_text" + android:textSize="24dip" + android:gravity="after" + /> + </TableRow> + + <TableRow> + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button2_text" + android:textSize="24dip" + /> + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button_left_text" + android:textSize="24dip" + android:gravity="left" + /> + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button_before_text" + android:textSize="24dip" + android:gravity="before" + /> + </TableRow> + </TableLayout> + + </LinearLayout> + +</FrameLayout>
\ No newline at end of file diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestActivity.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestActivity.java index 266268313ab8..a3a004130c90 100644 --- a/tests/BiDiTests/src/com/android/bidi/BiDiTestActivity.java +++ b/tests/BiDiTests/src/com/android/bidi/BiDiTestActivity.java @@ -16,12 +16,56 @@ package com.android.bidi; -import android.app.TabActivity; -import android.content.Intent; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import android.app.Activity; +import android.app.Fragment; +import android.app.FragmentTransaction; import android.os.Bundle; -import android.widget.TabHost; - -public class BiDiTestActivity extends TabActivity { +import android.view.View; +import android.widget.AdapterView; +import android.widget.ListView; +import android.widget.SimpleAdapter; + +public class BiDiTestActivity extends Activity { + + private static final String KEY_CLASS = "class"; + private static final String KEY_TITLE = "title"; + private static final String KEY_FRAGMENT_ID = "id"; + + private ListView mList; + + private AdapterView.OnItemClickListener mOnClickListener = + new AdapterView.OnItemClickListener() { + public void onItemClick(AdapterView<?> parent, View v, int position, long id) { + onListItemClick((ListView)parent, v, position, id); + } + }; + + private void onListItemClick(ListView lv, View v, int position, long id) { + // Show the test + Map<String, Object> map = (Map<String, Object>)lv.getItemAtPosition(position); + int fragmentId = (Integer) map.get(KEY_FRAGMENT_ID); + Fragment fragment = getFragmentManager().findFragmentById(fragmentId); + if (fragment == null) { + try { + // Create an instance of the test + Class<? extends Fragment> clazz = (Class<? extends Fragment>) map.get(KEY_CLASS); + fragment = clazz.newInstance(); + + // Replace the old test fragment with the new one + FragmentTransaction ft = getFragmentManager().beginTransaction(); + ft.replace(R.id.testframe, fragment); + ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE); + ft.commit(); + } catch (InstantiationException e) { + } catch (IllegalAccessException e) { + } + } + } @Override protected void onCreate(Bundle savedInstanceState) { @@ -29,74 +73,52 @@ public class BiDiTestActivity extends TabActivity { setContentView(R.layout.main); - TabHost tabHost = getTabHost(); - TabHost.TabSpec spec; - Intent intent; - - // Create an Intent to launch an Activity for the tab (to be reused) - intent = new Intent().setClass(this, BiDiTestBasicActivity.class); - - // Initialize a TabSpec for each tab and add it to the TabHost - spec = tabHost.newTabSpec("basic").setIndicator("Basic"). - setContent(intent); - tabHost.addTab(spec); - - // Do the same for the other tabs - intent = new Intent().setClass(this, BiDiTestCanvasActivity.class); - spec = tabHost.newTabSpec("canvas").setIndicator("Canvas"). - setContent(intent); - tabHost.addTab(spec); - - intent = new Intent().setClass(this, BiDiTestLinearLayoutLtrActivity.class); - spec = tabHost.newTabSpec("linear-layout-ltr").setIndicator("Linear LTR"). - setContent(intent); - tabHost.addTab(spec); - - intent = new Intent().setClass(this, BiDiTestLinearLayoutRtlActivity.class); - spec = tabHost.newTabSpec("linear-layout-rtl").setIndicator("Linear RTL"). - setContent(intent); - tabHost.addTab(spec); - - intent = new Intent().setClass(this, BiDiTestFrameLayoutLtrActivity.class); - spec = tabHost.newTabSpec("frame-layout-ltr").setIndicator("Frame LTR"). - setContent(intent); - tabHost.addTab(spec); - - intent = new Intent().setClass(this, BiDiTestFrameLayoutRtlActivity.class); - spec = tabHost.newTabSpec("frame-layout-rtl").setIndicator("Frame RTL"). - setContent(intent); - tabHost.addTab(spec); - - intent = new Intent().setClass(this, BiDiTestRelativeLayoutLtrActivity.class); - spec = tabHost.newTabSpec("relative-layout-ltr").setIndicator("Relative LTR"). - setContent(intent); - tabHost.addTab(spec); - - intent = new Intent().setClass(this, BiDiTestRelativeLayoutRtlActivity.class); - spec = tabHost.newTabSpec("relative-layout-rtl").setIndicator("Relative RTL"). - setContent(intent); - tabHost.addTab(spec); - - intent = new Intent().setClass(this, BiDiTestRelativeLayoutLtrActivity2.class); - spec = tabHost.newTabSpec("relative-layout-ltr-2").setIndicator("Relative2 LTR"). - setContent(intent); - tabHost.addTab(spec); - - intent = new Intent().setClass(this, BiDiTestRelativeLayoutRtlActivity2.class); - spec = tabHost.newTabSpec("relative-layout-rtl-2").setIndicator("Relative2 RTL"). - setContent(intent); - tabHost.addTab(spec); - - intent = new Intent().setClass(this, BiDiTestTableLayoutLtrActivity.class); - spec = tabHost.newTabSpec("table-layout-ltr").setIndicator("Table LTR"). - setContent(intent); - tabHost.addTab(spec); + mList = (ListView) findViewById(R.id.testlist); + mList.setChoiceMode(ListView.CHOICE_MODE_SINGLE); + mList.setFocusableInTouchMode(true); + + final SimpleAdapter adapter = new SimpleAdapter(this, getTests(), + R.layout.custom_list_item, new String[]{"title"}, + new int[]{android.R.id.text1}); + mList.setAdapter(adapter); + + mList.setOnItemClickListener(mOnClickListener); + } - intent = new Intent().setClass(this, BiDiTestTableLayoutRtlActivity.class); - spec = tabHost.newTabSpec("table-layout-rtl").setIndicator("Table RTL"). - setContent(intent); - tabHost.addTab(spec); + private void addItem(List<Map<String, Object>> data, String name, + Class<? extends Fragment> clazz, int fragmentId) { + Map<String, Object> temp = new HashMap<String, Object>(); + temp.put(KEY_TITLE, name); + temp.put(KEY_CLASS, clazz); + temp.put(KEY_FRAGMENT_ID, fragmentId); + data.add(temp); + } - tabHost.setCurrentTab(0); + private List<Map<String, Object>> getTests() { + List<Map<String, Object>> result = new ArrayList<Map<String, Object>>(); + + addItem(result, "Basic", BiDiTestBasic.class, R.id.basic); + addItem(result, "Canvas", BiDiTestCanvas.class, R.id.canvas); + + addItem(result, "Linear LTR", BiDiTestLinearLayoutLtr.class, R.id.linear_layout_ltr); + addItem(result, "Linear RTL", BiDiTestLinearLayoutRtl.class, R.id.linear_layout_rtl); + addItem(result, "Linear LOC", BiDiTestLinearLayoutLocale.class, R.id.linear_layout_locale); + + addItem(result, "Frame LTR", BiDiTestFrameLayoutLtr.class, R.id.frame_layout_ltr); + addItem(result, "Frame RTL", BiDiTestFrameLayoutRtl.class, R.id.frame_layout_rtl); + addItem(result, "Frame LOC", BiDiTestFrameLayoutLocale.class, R.id.frame_layout_locale); + + addItem(result, "Relative LTR", BiDiTestRelativeLayoutLtr.class, R.id.relative_layout_ltr); + addItem(result, "Relative RTL", BiDiTestRelativeLayoutRtl.class, R.id.relative_layout_rtl); + + addItem(result, "Relative2 LTR", BiDiTestRelativeLayout2Ltr.class, R.id.relative_layout_2_ltr); + addItem(result, "Relative2 RTL", BiDiTestRelativeLayout2Rtl.class, R.id.relative_layout_2_rtl); + addItem(result, "Relative2 LOC", BiDiTestRelativeLayout2Locale.class, R.id.relative_layout_2_locale); + + addItem(result, "Table LTR", BiDiTestTableLayoutLtr.class, R.id.table_layout_ltr); + addItem(result, "Table RTL", BiDiTestTableLayoutRtl.class, R.id.table_layout_rtl); + addItem(result, "Table LOC", BiDiTestTableLayoutLocale.class, R.id.table_layout_locale); + + return result; } }
\ No newline at end of file diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestLinearLayoutLtrActivity.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestBasic.java index 280af6aeb107..9b3918d9aaa3 100644 --- a/tests/BiDiTests/src/com/android/bidi/BiDiTestLinearLayoutLtrActivity.java +++ b/tests/BiDiTests/src/com/android/bidi/BiDiTestBasic.java @@ -16,15 +16,17 @@ package com.android.bidi; -import android.app.Activity; +import android.app.Fragment; import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; -public class BiDiTestLinearLayoutLtrActivity extends Activity { - +public class BiDiTestBasic extends Fragment { + @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - setContentView(R.layout.linear_layout_ltr); + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + return inflater.inflate(R.layout.basic, container, false); } } diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestCanvasActivity.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestCanvas.java index 3ab75d525869..33ed731749e2 100644 --- a/tests/BiDiTests/src/com/android/bidi/BiDiTestCanvasActivity.java +++ b/tests/BiDiTests/src/com/android/bidi/BiDiTestCanvas.java @@ -16,30 +16,39 @@ package com.android.bidi; -import android.app.Activity; +import android.app.Fragment; import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; import android.widget.SeekBar; import static com.android.bidi.BiDiTestConstants.FONT_MAX_SIZE; import static com.android.bidi.BiDiTestConstants.FONT_MIN_SIZE; -public class BiDiTestCanvasActivity extends Activity { +public class BiDiTestCanvas extends Fragment { static final int INIT_TEXT_SIZE = (FONT_MAX_SIZE - FONT_MIN_SIZE) / 2; private BiDiTestView testView; private SeekBar textSizeSeekBar; + private View currentView; @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + currentView = inflater.inflate(R.layout.canvas, container, false); + return currentView; + } - setContentView(R.layout.canvas); + @Override + public void onViewCreated(View view, Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); - testView = (BiDiTestView) findViewById(R.id.testview); + testView = (BiDiTestView) currentView.findViewById(R.id.testview); testView.setCurrentTextSize(INIT_TEXT_SIZE); - textSizeSeekBar = (SeekBar) findViewById(R.id.seekbar); + textSizeSeekBar = (SeekBar) currentView.findViewById(R.id.seekbar); textSizeSeekBar.setProgress(INIT_TEXT_SIZE); textSizeSeekBar.setMax(FONT_MAX_SIZE - FONT_MIN_SIZE); diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestFrameLayoutLocale.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestFrameLayoutLocale.java new file mode 100644 index 000000000000..900bcd171d58 --- /dev/null +++ b/tests/BiDiTests/src/com/android/bidi/BiDiTestFrameLayoutLocale.java @@ -0,0 +1,33 @@ +/* + * 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.bidi; + +import android.app.Fragment; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +public class BiDiTestFrameLayoutLocale extends Fragment { + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + return inflater.inflate(R.layout.frame_layout_locale, container, false); + } +} + diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestFrameLayoutRtlActivity.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestFrameLayoutLtr.java index 6012a5c7b0da..43900da3e25c 100644 --- a/tests/BiDiTests/src/com/android/bidi/BiDiTestFrameLayoutRtlActivity.java +++ b/tests/BiDiTests/src/com/android/bidi/BiDiTestFrameLayoutLtr.java @@ -16,16 +16,18 @@ package com.android.bidi; -import android.app.Activity; +import android.app.Fragment; import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; -public class BiDiTestFrameLayoutRtlActivity extends Activity { +public class BiDiTestFrameLayoutLtr extends Fragment { @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - setContentView(R.layout.frame_layout_rtl); + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + return inflater.inflate(R.layout.frame_layout_ltr, container, false); } } diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestBasicActivity.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestFrameLayoutRtl.java index 2a8de0494c5a..a261449abc08 100644 --- a/tests/BiDiTests/src/com/android/bidi/BiDiTestBasicActivity.java +++ b/tests/BiDiTests/src/com/android/bidi/BiDiTestFrameLayoutRtl.java @@ -16,15 +16,18 @@ package com.android.bidi; -import android.app.Activity; +import android.app.Fragment; import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; -public class BiDiTestBasicActivity extends Activity { +public class BiDiTestFrameLayoutRtl extends Fragment { @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - setContentView(R.layout.basic); + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + return inflater.inflate(R.layout.frame_layout_rtl, container, false); } } + diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestLinearLayoutLocale.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestLinearLayoutLocale.java new file mode 100644 index 000000000000..ad686df8f775 --- /dev/null +++ b/tests/BiDiTests/src/com/android/bidi/BiDiTestLinearLayoutLocale.java @@ -0,0 +1,32 @@ +/* + * 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.bidi; + +import android.app.Fragment; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +public class BiDiTestLinearLayoutLocale extends Fragment { + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + return inflater.inflate(R.layout.linear_layout_locale, container, false); + } +} diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestLinearLayoutLtr.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestLinearLayoutLtr.java new file mode 100644 index 000000000000..da9195ac14c0 --- /dev/null +++ b/tests/BiDiTests/src/com/android/bidi/BiDiTestLinearLayoutLtr.java @@ -0,0 +1,32 @@ +/* + * 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.bidi; + +import android.app.Fragment; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +public class BiDiTestLinearLayoutLtr extends Fragment { + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + return inflater.inflate(R.layout.linear_layout_ltr, container, false); + } +} diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestLinearLayoutRtl.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestLinearLayoutRtl.java new file mode 100644 index 000000000000..dfe247fb5874 --- /dev/null +++ b/tests/BiDiTests/src/com/android/bidi/BiDiTestLinearLayoutRtl.java @@ -0,0 +1,32 @@ +/* + * 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.bidi; + +import android.app.Fragment; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +public class BiDiTestLinearLayoutRtl extends Fragment { + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + return inflater.inflate(R.layout.linear_layout_rtl, container, false); + } +} diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestLinearLayoutRtlActivity.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestLinearLayoutRtlActivity.java deleted file mode 100644 index 7121a62c36c1..000000000000 --- a/tests/BiDiTests/src/com/android/bidi/BiDiTestLinearLayoutRtlActivity.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.bidi; - -import android.app.Activity; -import android.os.Bundle; - -public class BiDiTestLinearLayoutRtlActivity extends Activity { - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - setContentView(R.layout.linear_layout_rtl); - } -} diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestRelativeLayout2Locale.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestRelativeLayout2Locale.java new file mode 100644 index 000000000000..957f189875ba --- /dev/null +++ b/tests/BiDiTests/src/com/android/bidi/BiDiTestRelativeLayout2Locale.java @@ -0,0 +1,33 @@ +/* + * 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.bidi; + +import android.app.Fragment; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +public class BiDiTestRelativeLayout2Locale extends Fragment { + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + return inflater.inflate(R.layout.relative_layout_2_locale, container, false); + } +} + diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestRelativeLayout2Ltr.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestRelativeLayout2Ltr.java new file mode 100644 index 000000000000..a27b3a4b7aa2 --- /dev/null +++ b/tests/BiDiTests/src/com/android/bidi/BiDiTestRelativeLayout2Ltr.java @@ -0,0 +1,33 @@ +/* + * 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.bidi; + +import android.app.Fragment; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +public class BiDiTestRelativeLayout2Ltr extends Fragment { + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + return inflater.inflate(R.layout.relative_layout_2_ltr, container, false); + } +} + diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestRelativeLayout2Rtl.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestRelativeLayout2Rtl.java new file mode 100644 index 000000000000..6185a6f4a7ae --- /dev/null +++ b/tests/BiDiTests/src/com/android/bidi/BiDiTestRelativeLayout2Rtl.java @@ -0,0 +1,33 @@ +/* + * 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.bidi; + +import android.app.Fragment; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +public class BiDiTestRelativeLayout2Rtl extends Fragment { + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + return inflater.inflate(R.layout.relative_layout_2_rtl, container, false); + } +} + diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestRelativeLayoutLtr.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestRelativeLayoutLtr.java new file mode 100644 index 000000000000..d854e7af999a --- /dev/null +++ b/tests/BiDiTests/src/com/android/bidi/BiDiTestRelativeLayoutLtr.java @@ -0,0 +1,33 @@ +/* + * 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.bidi; + +import android.app.Fragment; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +public class BiDiTestRelativeLayoutLtr extends Fragment { + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + return inflater.inflate(R.layout.relative_layout_ltr, container, false); + } +} + diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestRelativeLayoutRtl.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestRelativeLayoutRtl.java new file mode 100644 index 000000000000..ed5607a35d26 --- /dev/null +++ b/tests/BiDiTests/src/com/android/bidi/BiDiTestRelativeLayoutRtl.java @@ -0,0 +1,33 @@ +/* + * 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.bidi; + +import android.app.Fragment; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +public class BiDiTestRelativeLayoutRtl extends Fragment { + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + return inflater.inflate(R.layout.relative_layout_rtl, container, false); + } +} + diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestRelativeLayoutRtlActivity.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestRelativeLayoutRtlActivity.java deleted file mode 100644 index 683b7a38a42d..000000000000 --- a/tests/BiDiTests/src/com/android/bidi/BiDiTestRelativeLayoutRtlActivity.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.bidi; - -import android.app.Activity; -import android.os.Bundle; - -public class BiDiTestRelativeLayoutRtlActivity extends Activity { - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - setContentView(R.layout.relative_layout_rtl); - } -} - diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestRelativeLayoutRtlActivity2.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestRelativeLayoutRtlActivity2.java deleted file mode 100644 index db2af7f20d31..000000000000 --- a/tests/BiDiTests/src/com/android/bidi/BiDiTestRelativeLayoutRtlActivity2.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.bidi; - -import android.app.Activity; -import android.os.Bundle; - -public class BiDiTestRelativeLayoutRtlActivity2 extends Activity { - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - setContentView(R.layout.relative_layout_rtl_2); - } -} - diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestTableLayoutLocale.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestTableLayoutLocale.java new file mode 100644 index 000000000000..7172c9421037 --- /dev/null +++ b/tests/BiDiTests/src/com/android/bidi/BiDiTestTableLayoutLocale.java @@ -0,0 +1,33 @@ +/* + * 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.bidi; + +import android.app.Fragment; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +public class BiDiTestTableLayoutLocale extends Fragment { + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + return inflater.inflate(R.layout.table_layout_locale, container, false); + } +} + diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestFrameLayoutLtrActivity.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestTableLayoutLtr.java index 6ce4fe4f8c7c..ef75b5ee669d 100644 --- a/tests/BiDiTests/src/com/android/bidi/BiDiTestFrameLayoutLtrActivity.java +++ b/tests/BiDiTests/src/com/android/bidi/BiDiTestTableLayoutLtr.java @@ -16,16 +16,18 @@ package com.android.bidi; -import android.app.Activity; +import android.app.Fragment; import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; -public class BiDiTestFrameLayoutLtrActivity extends Activity { +public class BiDiTestTableLayoutLtr extends Fragment { @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - setContentView(R.layout.frame_layout_ltr); + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + return inflater.inflate(R.layout.table_layout_ltr, container, false); } } diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestTableLayoutLtrActivity.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestTableLayoutLtrActivity.java deleted file mode 100644 index 0719daebe346..000000000000 --- a/tests/BiDiTests/src/com/android/bidi/BiDiTestTableLayoutLtrActivity.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.bidi; - -import android.app.Activity; -import android.os.Bundle; - -public class BiDiTestTableLayoutLtrActivity extends Activity { - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - setContentView(R.layout.table_layout_ltr); - } -} - diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestTableLayoutRtl.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestTableLayoutRtl.java new file mode 100644 index 000000000000..d3c20ffdbcf1 --- /dev/null +++ b/tests/BiDiTests/src/com/android/bidi/BiDiTestTableLayoutRtl.java @@ -0,0 +1,33 @@ +/* + * 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.bidi; + +import android.app.Fragment; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +public class BiDiTestTableLayoutRtl extends Fragment { + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + return inflater.inflate(R.layout.table_layout_rtl, container, false); + } +} + diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestTableLayoutRtlActivity.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestTableLayoutRtlActivity.java deleted file mode 100644 index 3553ed89a4b7..000000000000 --- a/tests/BiDiTests/src/com/android/bidi/BiDiTestTableLayoutRtlActivity.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.bidi; - -import android.app.Activity; -import android.os.Bundle; - -public class BiDiTestTableLayoutRtlActivity extends Activity { - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - setContentView(R.layout.table_layout_rtl); - } -} - diff --git a/tests/GridLayoutTest/res/layout/grid3.xml b/tests/GridLayoutTest/res/layout/grid3.xml index ace7b4c6fd87..31dc75abfb9c 100644 --- a/tests/GridLayoutTest/res/layout/grid3.xml +++ b/tests/GridLayoutTest/res/layout/grid3.xml @@ -19,59 +19,61 @@ android:layout_width="match_parent" android:layout_height="match_parent" + android:useDefaultMargins="true" + android:marginsIncludedInAlignment="false" + android:columnCount="4" > - <Button - android:text="fill" - android:width="200dip" - android:height="100dip" - android:layout_marginLeft="50dip" - android:layout_row="0" - android:layout_column="0" - android:layout_gravity="fill_horizontal" + <TextView + android:text="Email account" + android:textSize="48dip" + android:layout_columnSpan="4" + android:layout_gravity="center_horizontal" /> - <EditText - android:layout_row="0" - android:layout_column="1" + <TextView + android:text="You can configure email in just a few steps:" + android:textSize="20dip" + android:layout_columnSpan="4" + android:layout_gravity="left" /> - <Button - android:text="left" - android:layout_row="1" - android:layout_column="0" + <TextView + android:text="Email address:" + android:layout_gravity="right" /> <EditText - android:layout_row="1" - android:layout_column="1" + android:layout_width="100dip" /> - <Button - android:text="right" - android:layout_row="2" + <TextView + android:text="Password:" android:layout_column="0" android:layout_gravity="right" /> <EditText - android:layout_margin="50dip" - android:textSize="100dip" - android:layout_row="2" - android:layout_column="1" + android:layout_width="50dip" /> - <Button - android:text="center" - android:layout_row="3" - android:layout_column="0" - android:layout_gravity="center_horizontal" + <Space + android:layout_rowWeight="1" + android:layout_columnWeight="1" + android:layout_row="4" + android:layout_column="2" /> - <EditText - android:layout_height="fill_parent" - android:layout_row="3" - android:layout_column="1" + <Button + android:text="Manual setup" + android:layout_row="5" + android:layout_column="3" + android:layout_gravity="fill_horizontal" /> + <Button + android:text="Next" + android:layout_column="3" + android:layout_gravity="fill_horizontal" + /> </GridLayout> diff --git a/tests/GridLayoutTest/src/com/android/test/layout/AbstractLayoutTest.java b/tests/GridLayoutTest/src/com/android/test/layout/AbstractLayoutTest.java index 937eacb3b00a..4d3a843cdf87 100644 --- a/tests/GridLayoutTest/src/com/android/test/layout/AbstractLayoutTest.java +++ b/tests/GridLayoutTest/src/com/android/test/layout/AbstractLayoutTest.java @@ -19,19 +19,19 @@ package com.android.test.layout; import android.app.Activity; import android.content.Context; import android.os.Bundle; -import android.os.Debug; import android.util.Log; -import android.view.Gravity; import android.view.View; import android.view.ViewGroup; import android.widget.Button; +import static android.view.Gravity.*; + public abstract class AbstractLayoutTest extends Activity { - public static final String[] HORIZONTAL_NAMES = new String[] { "LEFT", "center", "east", "fill" }; - public static final int[] HORIZONTAL_ALIGNMENTS = new int[] { Gravity.LEFT, Gravity.CENTER, Gravity.RIGHT, Gravity.FILL }; - public static final String[] VERTICAL_NAMES = new String[] { "north", "center", "baseline", "south", "fill" }; - public static final int[] VERTICAL_ALIGNMENTS = new int[] { Gravity.TOP, Gravity.CENTER, Gravity.NO_GRAVITY, Gravity.BOTTOM, Gravity.FILL }; + public static final String[] HORIZONTAL_NAMES = { "LEFT", "CENTER", "RIGHT", "FILL" }; + public static final int[] HORIZONTAL_ALIGNMENTS = { LEFT, CENTER, RIGHT, FILL }; + public static final String[] VERTICAL_NAMES = { "TOP", "CENTER", "BASELINE", "BOTTOM", "FILL" }; + public static final int[] VERTICAL_ALIGNMENTS = { TOP, CENTER, NO_GRAVITY, BOTTOM, FILL }; public View create(Context context, String name, int size) { Button result = new Button(context); diff --git a/tests/GridLayoutTest/src/com/android/test/layout/AlignmentTest.java b/tests/GridLayoutTest/src/com/android/test/layout/AlignmentTest.java index c6f390e6a2b1..505c83dedf1e 100755 --- a/tests/GridLayoutTest/src/com/android/test/layout/AlignmentTest.java +++ b/tests/GridLayoutTest/src/com/android/test/layout/AlignmentTest.java @@ -31,10 +31,10 @@ import static android.widget.GridLayout.*; public class AlignmentTest extends Activity { - public static final String[] HORIZONTAL_NAMES = new String[]{"LEFT", "center", "east", "fill"}; - public static final Alignment[] HORIZONTAL_ALIGNMENTS = new Alignment[]{LEFT, CENTER, RIGHT, FILL}; - public static final String[] VERTICAL_NAMES = new String[]{"north", "center", "baseline", "south", "fill"}; - public static final Alignment[] VERTICAL_ALIGNMENTS = new Alignment[]{TOP, CENTER, BASELINE, BOTTOM, FILL}; + public static final String[] HORIZONTAL_NAMES = {"LEFT", "center", "east", "fill"}; + public static final Alignment[] HORIZONTAL_ALIGNMENTS = {LEFT, CENTER, RIGHT, FILL}; + public static final String[] VERTICAL_NAMES = {"north", "center", "baseline", "south", "fill"}; + public static final Alignment[] VERTICAL_ALIGNMENTS = {TOP, CENTER, BASELINE, BOTTOM, FILL}; private static Context CONTEXT; public static interface ViewFactory { @@ -72,7 +72,8 @@ public class AlignmentTest extends Activity { } }; - public static final ViewFactory[] FACTORIES = new ViewFactory[]{BUTTON_FACTORY, LABEL_FACTORY, TEXT_FIELD_FACTORY}; + public static final ViewFactory[] FACTORIES = + {BUTTON_FACTORY, LABEL_FACTORY, TEXT_FIELD_FACTORY}; public static ViewGroup create(Context context1) { CONTEXT = context1; @@ -86,7 +87,9 @@ public class AlignmentTest extends Activity { Group rowGroup = new Group(i, va); Group colGroup = new Group(j, ha); LayoutParams layoutParams = new LayoutParams(rowGroup, colGroup); - container.addView(FACTORIES[(i + j) % FACTORIES.length].create(VERTICAL_NAMES[i] + "-" + HORIZONTAL_NAMES[j], 20), layoutParams); + String name = VERTICAL_NAMES[i] + "-" + HORIZONTAL_NAMES[j]; + ViewFactory factory = FACTORIES[(i + j) % FACTORIES.length]; + container.addView(factory.create(name, 20), layoutParams); } } @@ -105,7 +108,8 @@ public class AlignmentTest extends Activity { GridLayout p = (GridLayout) v.getParent(); p.layout(0, 0, 1000 + (i % 2), 500 + (i % 2)); } - System.out.println("Time: " + (float) (System.currentTimeMillis() - start) / N * 1000 + "mics"); + float time = (float) (System.currentTimeMillis() - start) / N * 1000; + System.out.println("Time: " + time + "mics"); } protected void onCreate(Bundle savedInstanceState) { diff --git a/tests/GridLayoutTest/src/com/android/test/layout/GridLayoutTest.java b/tests/GridLayoutTest/src/com/android/test/layout/GridLayoutTest.java index b4451e8c453e..c5681e2c146d 100644 --- a/tests/GridLayoutTest/src/com/android/test/layout/GridLayoutTest.java +++ b/tests/GridLayoutTest/src/com/android/test/layout/GridLayoutTest.java @@ -36,8 +36,8 @@ public class GridLayoutTest extends AbstractLayoutTest { GridLayout.Group rowGroup = new GridLayout.Group(UNDEFINED, null); GridLayout.Group colGroup = new GridLayout.Group(UNDEFINED, null); GridLayout.LayoutParams lp = new GridLayout.LayoutParams(rowGroup, colGroup); + //GridLayout.LayoutParams lp = new GridLayout.LayoutParams(); lp.setGravity(va | ha); -// View v = create(VERTICAL_NAMES[i] + "-" + HORIZONTAL_NAMES[j], 20); View v = create(context, VERTICAL_NAMES[i] + "-" + HORIZONTAL_NAMES[j], 20); container.addView(v, lp); } diff --git a/tests/GridLayoutTest/src/com/android/test/layout/LinearLayoutTest.java b/tests/GridLayoutTest/src/com/android/test/layout/LinearLayoutTest.java index fbd1239aabb3..c7f466561339 100644 --- a/tests/GridLayoutTest/src/com/android/test/layout/LinearLayoutTest.java +++ b/tests/GridLayoutTest/src/com/android/test/layout/LinearLayoutTest.java @@ -22,20 +22,19 @@ import android.view.ViewGroup; import android.widget.LinearLayout; import static android.widget.LinearLayout.*; +import static android.widget.LinearLayout.LayoutParams.*; public class LinearLayoutTest extends AbstractLayoutTest { public ViewGroup create(Context context) { LinearLayout container = new LinearLayout(context); container.setOrientation(LinearLayout.VERTICAL); -// container.setUseDefaultMargins(true); for (int i = 0; i < VERTICAL_ALIGNMENTS.length; i++) { int va = VERTICAL_ALIGNMENTS[i]; for (int j = 0; j < HORIZONTAL_ALIGNMENTS.length; j++) { int ha = HORIZONTAL_ALIGNMENTS[j]; - LayoutParams lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); + LayoutParams lp = new LayoutParams(WRAP_CONTENT, WRAP_CONTENT); lp.gravity = va | ha; -// View v = create(VERTICAL_NAMES[i] + "-" + HORIZONTAL_NAMES[j], 20); View v = create(context, VERTICAL_NAMES[i] + "-" + HORIZONTAL_NAMES[j], 20); container.addView(v, lp); } diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/GLTextureViewActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/GLTextureViewActivity.java index 7f970989bb4b..9bb5ba8e7aaf 100644 --- a/tests/HwAccelerationTest/src/com/android/test/hwui/GLTextureViewActivity.java +++ b/tests/HwAccelerationTest/src/com/android/test/hwui/GLTextureViewActivity.java @@ -52,13 +52,7 @@ public class GLTextureViewActivity extends Activity implements TextureView.Surfa } @Override - protected void onDestroy() { - super.onDestroy(); - mRenderThread.finish(); - } - - @Override - public void onSurfaceTextureAvailable(SurfaceTexture surface) { + public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) { mRenderThread = new RenderThread(surface); mRenderThread.start(); @@ -81,6 +75,16 @@ public class GLTextureViewActivity extends Activity implements TextureView.Surfa public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) { } + @Override + public void onSurfaceTextureDestroyed(SurfaceTexture surface) { + mRenderThread.finish(); + try { + mRenderThread.join(); + } catch (InterruptedException e) { + Log.e(RenderThread.LOG_TAG, "Could not wait for render thread"); + } + } + private static class RenderThread extends Thread { private static final String LOG_TAG = "GLTextureView"; @@ -108,26 +112,23 @@ public class GLTextureViewActivity extends Activity implements TextureView.Surfa public void run() { initGL(); - float red = 0.0f; + float red = 1.0f; while (!mFinished) { checkCurrent(); + Log.d(LOG_TAG, "Rendering frame"); + GLES20.glClearColor(red, 0.0f, 0.0f, 1.0f); - int error = GLES20.glGetError(); - if (error != GLES20.GL_NO_ERROR) { - Log.w(LOG_TAG, "GL error = 0x" + Integer.toHexString(error)); - } + checkGlError(); GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); - error = GLES20.glGetError(); - if (error != GLES20.GL_NO_ERROR) { - Log.w(LOG_TAG, "GL error = 0x" + Integer.toHexString(error)); - } + checkGlError(); if (!mEgl.eglSwapBuffers(mEglDisplay, mEglSurface)) { throw new RuntimeException("Cannot swap buffers"); } - + checkEglError(); + try { Thread.sleep(20); } catch (InterruptedException e) { @@ -141,6 +142,20 @@ public class GLTextureViewActivity extends Activity implements TextureView.Surfa finishGL(); } + private void checkEglError() { + int error = mEgl.eglGetError(); + if (error != EGL10.EGL_SUCCESS) { + Log.w(LOG_TAG, "EGL error = 0x" + Integer.toHexString(error)); + } + } + + private void checkGlError() { + int error = GLES20.glGetError(); + if (error != GLES20.GL_NO_ERROR) { + Log.w(LOG_TAG, "GL error = 0x" + Integer.toHexString(error)); + } + } + private void finishGL() { mEgl.eglDestroyContext(mEglDisplay, mEglContext); mEgl.eglDestroySurface(mEglDisplay, mEglSurface); diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/TextureViewActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/TextureViewActivity.java index 2feda57a1351..fa2e39a4ed7c 100644 --- a/tests/HwAccelerationTest/src/com/android/test/hwui/TextureViewActivity.java +++ b/tests/HwAccelerationTest/src/com/android/test/hwui/TextureViewActivity.java @@ -16,6 +16,7 @@ package com.android.test.hwui; +import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import android.animation.ValueAnimator; import android.app.Activity; @@ -25,6 +26,7 @@ import android.os.Bundle; import android.view.Gravity; import android.view.TextureView; import android.view.View; +import android.widget.Button; import android.widget.FrameLayout; import java.io.IOException; @@ -33,27 +35,44 @@ import java.io.IOException; public class TextureViewActivity extends Activity implements TextureView.SurfaceTextureListener { private Camera mCamera; private TextureView mTextureView; + private FrameLayout mContent; + private AnimatorSet mAnimatorSet; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + mContent = new FrameLayout(this); + mTextureView = new TextureView(this); mTextureView.setSurfaceTextureListener(this); - setContentView(mTextureView, new FrameLayout.LayoutParams(500, 400, Gravity.CENTER)); - } + Button button = new Button(this); + button.setText("Remove/Add"); + button.setOnClickListener(new View.OnClickListener() { + private boolean mAdded = true; - @Override - protected void onDestroy() { - super.onDestroy(); + @Override + public void onClick(View v) { + if (mAdded) { + mAnimatorSet.cancel(); + mContent.removeView(mTextureView); + } else { + mContent.addView(mTextureView); + } + mAdded = !mAdded; + } + }); - mCamera.stopPreview(); - mCamera.release(); + mContent.addView(mTextureView, new FrameLayout.LayoutParams(500, 400, Gravity.CENTER)); + mContent.addView(button, new FrameLayout.LayoutParams( + FrameLayout.LayoutParams.WRAP_CONTENT, FrameLayout.LayoutParams.WRAP_CONTENT, + Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM)); + setContentView(mContent); } @Override - public void onSurfaceTextureAvailable(SurfaceTexture surface) { + public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) { mCamera = Camera.open(); try { @@ -66,27 +85,35 @@ public class TextureViewActivity extends Activity implements TextureView.Surface mTextureView.setCameraDistance(5000); - ObjectAnimator animator = ObjectAnimator.ofFloat(mTextureView, "rotationY", 0.0f, 360.0f); - animator.setRepeatMode(ObjectAnimator.REVERSE); - animator.setRepeatCount(ObjectAnimator.INFINITE); - animator.setDuration(4000); - animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + ObjectAnimator rotationY = ObjectAnimator.ofFloat(mTextureView, "rotationY", 0.0f, 360.0f); + rotationY.setRepeatMode(ObjectAnimator.REVERSE); + rotationY.setRepeatCount(ObjectAnimator.INFINITE); + rotationY.setDuration(4000); + rotationY.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { ((View) mTextureView.getParent()).invalidate(); } }); - animator.start(); - animator = ObjectAnimator.ofFloat(mTextureView, "alpha", 1.0f, 0.0f); - animator.setRepeatMode(ObjectAnimator.REVERSE); - animator.setRepeatCount(ObjectAnimator.INFINITE); - animator.setDuration(4000); - animator.start(); + ObjectAnimator alpha = ObjectAnimator.ofFloat(mTextureView, "alpha", 1.0f, 0.0f); + alpha.setRepeatMode(ObjectAnimator.REVERSE); + alpha.setRepeatCount(ObjectAnimator.INFINITE); + alpha.setDuration(4000); + + mAnimatorSet = new AnimatorSet(); + mAnimatorSet.play(alpha).with(rotationY); + mAnimatorSet.start(); } @Override public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) { // Ignored, the Camera does all the work for us } + + @Override + public void onSurfaceTextureDestroyed(SurfaceTexture surface) { + mCamera.stopPreview(); + mCamera.release(); + } } diff --git a/tools/aapt/ResourceTable.cpp b/tools/aapt/ResourceTable.cpp index 5c5b4fdc3269..81b924af8d7e 100644 --- a/tools/aapt/ResourceTable.cpp +++ b/tools/aapt/ResourceTable.cpp @@ -1963,10 +1963,11 @@ uint32_t ResourceTable::getResId(const String16& ref, bool onlyPublic) const { String16 package, type, name; + bool refOnlyPublic = true; if (!ResTable::expandResourceRef( ref.string(), ref.size(), &package, &type, &name, defType, defPackage ? defPackage:&mAssetsPackage, - outErrorMsg)) { + outErrorMsg, &refOnlyPublic)) { NOISY(printf("Expanding resource: ref=%s\n", String8(ref).string())); NOISY(printf("Expanding resource: defType=%s\n", @@ -1979,7 +1980,7 @@ uint32_t ResourceTable::getResId(const String16& ref, String8(name).string())); return 0; } - uint32_t res = getResId(package, type, name, onlyPublic); + uint32_t res = getResId(package, type, name, onlyPublic && refOnlyPublic); NOISY(printf("Expanded resource: p=%s, t=%s, n=%s, res=%d\n", String8(package).string(), String8(type).string(), String8(name).string(), res)); diff --git a/tools/aapt/ResourceTable.h b/tools/aapt/ResourceTable.h index bbb81408c830..734c541f9b61 100644 --- a/tools/aapt/ResourceTable.h +++ b/tools/aapt/ResourceTable.h @@ -162,13 +162,13 @@ public: uint32_t getResId(const String16& package, const String16& type, const String16& name, - bool onlyPublic = false) const; + bool onlyPublic = true) const; uint32_t getResId(const String16& ref, const String16* defType = NULL, const String16* defPackage = NULL, const char** outErrorMsg = NULL, - bool onlyPublic = false) const; + bool onlyPublic = true) const; static bool isValidResourceName(const String16& s); diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java index 4fa924d0da57..7380fc1e92bf 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java @@ -78,6 +78,8 @@ import java.util.IdentityHashMap; import java.util.Map; import java.util.TreeMap; import java.util.Map.Entry; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicReference; /** * Custom implementation of Context/Activity to handle non compiled resources. @@ -299,12 +301,17 @@ public final class BridgeContext extends Activity { public Pair<View, Boolean> inflateView(ResourceReference resource, ViewGroup parent, boolean attachToRoot, boolean skipCallbackParser) { - String layoutName = resource.getName(); boolean isPlatformLayout = resource.isFramework(); if (isPlatformLayout == false && skipCallbackParser == false) { // check if the project callback can provide us with a custom parser. - ILayoutPullParser parser = mProjectCallback.getParser(layoutName); + ILayoutPullParser parser; + if (resource instanceof ResourceValue) { + parser = mProjectCallback.getParser((ResourceValue) resource); + } else { + parser = mProjectCallback.getParser(resource.getName()); + } + if (parser != null) { BridgeXmlBlockParser blockParser = new BridgeXmlBlockParser(parser, this, resource.isFramework()); @@ -372,7 +379,7 @@ public final class BridgeContext extends Activity { } else { Bridge.getLog().error(LayoutLog.TAG_BROKEN, String.format("Layout %s%s does not exist.", isPlatformLayout ? "android:" : "", - layoutName), null); + resource.getName()), null); } return Pair.of(null, false); @@ -507,11 +514,12 @@ public final class BridgeContext extends Activity { return null; } - boolean[] frameworkAttributes = new boolean[1]; - TreeMap<Integer, String> styleNameMap = searchAttrs(attrs, frameworkAttributes); + AtomicBoolean frameworkAttributes = new AtomicBoolean(); + AtomicReference<String> attrName = new AtomicReference<String>(); + TreeMap<Integer, String> styleNameMap = searchAttrs(attrs, frameworkAttributes, attrName); BridgeTypedArray ta = ((BridgeResources) mSystemResources).newTypeArray(attrs.length, - isPlatformFile); + isPlatformFile, frameworkAttributes.get(), attrName.get()); // look for a custom style. String customStyle = null; @@ -602,7 +610,7 @@ public final class BridgeContext extends Activity { } String namespace = BridgeConstants.NS_RESOURCES; - if (frameworkAttributes[0] == false) { + if (frameworkAttributes.get() == false) { // need to use the application namespace namespace = mProjectCallback.getNamespace(); } @@ -679,10 +687,12 @@ public final class BridgeContext extends Activity { */ private BridgeTypedArray createStyleBasedTypedArray(StyleResourceValue style, int[] attrs) throws Resources.NotFoundException { - TreeMap<Integer, String> styleNameMap = searchAttrs(attrs, null); + AtomicBoolean frameworkAttributes = new AtomicBoolean(); + AtomicReference<String> attrName = new AtomicReference<String>(); + TreeMap<Integer, String> styleNameMap = searchAttrs(attrs, frameworkAttributes, attrName); BridgeTypedArray ta = ((BridgeResources) mSystemResources).newTypeArray(attrs.length, - false /* platformResourceFlag */); + style.isFramework(), frameworkAttributes.get(), attrName.get()); // loop through all the values in the style map, and init the TypedArray with // the style we got from the dynamic id @@ -714,10 +724,13 @@ public final class BridgeContext extends Activity { * that is used to reference the attribute later in the TypedArray. * * @param attrs An attribute array reference given to obtainStyledAttributes. + * @param outFrameworkFlag out value indicating if the attr array is a framework value + * @param outAttrName out value for the resolved attr name. * @return A sorted map Attribute-Value to Attribute-Name for all attributes declared by the * attribute array. Returns null if nothing is found. */ - private TreeMap<Integer,String> searchAttrs(int[] attrs, boolean[] outFrameworkFlag) { + private TreeMap<Integer,String> searchAttrs(int[] attrs, AtomicBoolean outFrameworkFlag, + AtomicReference<String> outAttrName) { // get the name of the array from the framework resources String arrayName = Bridge.resolveResourceId(attrs); if (arrayName != null) { @@ -734,7 +747,10 @@ public final class BridgeContext extends Activity { } if (outFrameworkFlag != null) { - outFrameworkFlag[0] = true; + outFrameworkFlag.set(true); + } + if (outAttrName != null) { + outAttrName.set(arrayName); } return attributes; @@ -756,7 +772,10 @@ public final class BridgeContext extends Activity { } if (outFrameworkFlag != null) { - outFrameworkFlag[0] = false; + outFrameworkFlag.set(false); + } + if (outAttrName != null) { + outAttrName.set(arrayName); } return attributes; diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeResources.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeResources.java index 345f053582d7..d0b90fb25af8 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeResources.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeResources.java @@ -125,8 +125,10 @@ public final class BridgeResources extends Resources { mProjectCallback = projectCallback; } - public BridgeTypedArray newTypeArray(int numEntries, boolean platformFile) { - return new BridgeTypedArray(this, mContext, numEntries, platformFile); + public BridgeTypedArray newTypeArray(int numEntries, boolean platformFile, + boolean platformStyleable, String styleableName) { + return new BridgeTypedArray(this, mContext, numEntries, platformFile, + platformStyleable, styleableName); } private ResourceValue getResourceValue(int id, boolean[] platformResFlag_out) { @@ -232,7 +234,7 @@ public final class BridgeResources extends Resources { try { // check if the current parser can provide us with a custom parser. if (mPlatformResourceFlag[0] == false) { - parser = mProjectCallback.getParser(value.getName()); + parser = mProjectCallback.getParser(value); } // create a new one manually if needed. diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeTypedArray.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeTypedArray.java index d4600a14f42e..b1fbf08f592f 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeTypedArray.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeTypedArray.java @@ -16,6 +16,7 @@ package com.android.layoutlib.bridge.android; +import com.android.ide.common.rendering.api.DeclareStyleableResourceValue; import com.android.ide.common.rendering.api.LayoutLog; import com.android.ide.common.rendering.api.RenderResources; import com.android.ide.common.rendering.api.ResourceValue; @@ -49,18 +50,23 @@ import java.util.Map; */ public final class BridgeTypedArray extends TypedArray { - private BridgeResources mBridgeResources; - private BridgeContext mContext; + private final BridgeResources mBridgeResources; + private final BridgeContext mContext; + private final boolean mPlatformFile; + private final boolean mPlatformStyleable; + private final String mStyleableName; + private ResourceValue[] mResourceData; private String[] mNames; - private final boolean mPlatformFile; public BridgeTypedArray(BridgeResources resources, BridgeContext context, int len, - boolean platformFile) { + boolean platformFile, boolean platformStyleable, String styleableName) { super(null, null, null, 0); mBridgeResources = resources; mContext = context; mPlatformFile = platformFile; + mPlatformStyleable = platformStyleable; + mStyleableName = styleableName; mResourceData = new ResourceValue[len]; mNames = new String[len]; } @@ -202,7 +208,18 @@ public final class BridgeTypedArray extends TypedArray { // Field is not null and is not an integer. // Check for possible constants and try to find them. // Get the map of attribute-constant -> IntegerValue - Map<String, Integer> map = Bridge.getEnumValues(mNames[index]); + Map<String, Integer> map = null; + if (mPlatformStyleable) { + map = Bridge.getEnumValues(mNames[index]); + } else { + // get the styleable matching the resolved name + RenderResources res = mContext.getRenderResources(); + ResourceValue styleable = res.getProjectResource(ResourceType.DECLARE_STYLEABLE, + mStyleableName); + if (styleable instanceof DeclareStyleableResourceValue) { + map = ((DeclareStyleableResourceValue) styleable).getAttributeValues(mNames[index]); + } + } if (map != null) { // accumulator to store the value of the 1+ constants. diff --git a/voip/java/com/android/server/sip/SipService.java b/voip/java/com/android/server/sip/SipService.java index dc669896e35c..afa696cce1de 100644 --- a/voip/java/com/android/server/sip/SipService.java +++ b/voip/java/com/android/server/sip/SipService.java @@ -82,6 +82,7 @@ public final class SipService extends ISipService.Stub { private WifiScanProcess mWifiScanProcess; private WifiManager.WifiLock mWifiLock; private boolean mWifiOnly; + private IntervalMeasurementProcess mIntervalMeasurementProcess; private MyExecutor mExecutor; @@ -96,6 +97,7 @@ public final class SipService extends ISipService.Stub { private ConnectivityReceiver mConnectivityReceiver; private boolean mWifiEnabled; private SipWakeLock mMyWakeLock; + private int mKeepAliveInterval; /** * Starts the SIP service. Do nothing if the SIP API is not supported on the @@ -441,12 +443,14 @@ public final class SipService extends ISipService.Stub { if (connected) { mLocalIp = determineLocalIp(); + mKeepAliveInterval = -1; for (SipSessionGroupExt group : mSipGroups.values()) { group.onConnectivityChanged(true); } if (isWifi && (mWifiLock != null)) stopWifiScanner(); } else { mMyWakeLock.reset(); // in case there's a leak + stopPortMappingMeasurement(); if (isWifi && (mWifiLock != null)) startWifiScanner(); } } catch (SipException e) { @@ -454,6 +458,18 @@ public final class SipService extends ISipService.Stub { } } + private void stopPortMappingMeasurement() { + if (mIntervalMeasurementProcess != null) { + mIntervalMeasurementProcess.stop(); + mIntervalMeasurementProcess = null; + } + } + + private void startPortMappingLifetimeMeasurement(SipSessionGroup group) { + mIntervalMeasurementProcess = new IntervalMeasurementProcess(group); + mIntervalMeasurementProcess.start(); + } + private synchronized void addPendingSession(ISipSession session) { try { cleanUpPendingSessions(); @@ -687,6 +703,93 @@ public final class SipService extends ISipService.Stub { } } + private class IntervalMeasurementProcess extends SipSessionAdapter + implements Runnable { + private static final String TAG = "\\INTERVAL/"; + private static final int MAX_INTERVAL = 120; // seconds + private static final int MIN_INTERVAL = SHORT_EXPIRY_TIME; + private static final int PASS_THRESHOLD = 6; + private SipSessionGroupExt mGroup; + private SipSessionGroup.SipSessionImpl mSession; + private boolean mRunning; + private int mMinInterval = 10; + private int mMaxInterval = MAX_INTERVAL; + private int mInterval = MAX_INTERVAL / 2; + private int mPassCounter = 0; + private WakeupTimer mTimer = new WakeupTimer(mContext); + + + public IntervalMeasurementProcess(SipSessionGroup group) { + try { + mGroup = new SipSessionGroupExt( + group.getLocalProfile(), null, null); + mSession = (SipSessionGroup.SipSessionImpl) + mGroup.createSession(this); + } catch (Exception e) { + Log.w(TAG, "start interval measurement error: " + e); + } + } + + public void start() { + if (mRunning) return; + mRunning = true; + mTimer.set(mInterval * 1000, this); + if (DEBUGV) Log.v(TAG, "start interval measurement"); + run(); + } + + public void stop() { + mRunning = false; + mTimer.cancel(this); + } + + private void restart() { + mTimer.cancel(this); + mTimer.set(mInterval * 1000, this); + } + + private void calculateNewInterval() { + if (!mSession.isReRegisterRequired()) { + if (++mPassCounter != PASS_THRESHOLD) return; + // update the interval, since the current interval is good to + // keep the port mapping. + mKeepAliveInterval = mMinInterval = mInterval; + } else { + // Since the rport is changed, shorten the interval. + mSession.clearReRegisterRequired(); + mMaxInterval = mInterval; + } + if ((mMaxInterval - mMinInterval) < MIN_INTERVAL) { + // update mKeepAliveInterval and stop measurement. + stop(); + mKeepAliveInterval = mMinInterval; + if (DEBUGV) Log.v(TAG, "measured interval: " + mKeepAliveInterval); + } else { + // calculate the new interval and continue. + mInterval = (mMaxInterval + mMinInterval) / 2; + mPassCounter = 0; + if (DEBUGV) { + Log.v(TAG, " current interval: " + mKeepAliveInterval + + "test new interval: " + mInterval); + } + restart(); + } + } + + public void run() { + synchronized (SipService.this) { + if (!mRunning) return; + try { + mSession.sendKeepAlive(); + calculateNewInterval(); + } catch (Throwable t) { + stop(); + Log.w(TAG, "interval measurement error: " + t); + } + } + } + } + // KeepAliveProcess is controlled by AutoRegistrationProcess. // All methods will be invoked in sync with SipService.this. private class KeepAliveProcess implements Runnable { @@ -694,6 +797,7 @@ public final class SipService extends ISipService.Stub { private static final int INTERVAL = 10; private SipSessionGroup.SipSessionImpl mSession; private boolean mRunning = false; + private int mInterval = INTERVAL; public KeepAliveProcess(SipSessionGroup.SipSessionImpl session) { mSession = session; @@ -705,6 +809,12 @@ public final class SipService extends ISipService.Stub { mTimer.set(INTERVAL * 1000, this); } + private void restart(int duration) { + if (DEBUG) Log.d(TAG, "Refresh NAT port mapping " + duration + "s later."); + mTimer.cancel(this); + mTimer.set(duration * 1000, this); + } + // timeout handler public void run() { synchronized (SipService.this) { @@ -721,6 +831,10 @@ public final class SipService extends ISipService.Stub { mMyWakeLock.acquire(mSession); mSession.register(EXPIRY_TIME); } + if (mKeepAliveInterval > mInterval) { + mInterval = mKeepAliveInterval; + restart(mInterval); + } } catch (Throwable t) { Log.w(TAG, "keepalive error: " + t); } @@ -761,6 +875,17 @@ public final class SipService extends ISipService.Stub { // return right away if no active network connection. if (mSession == null) return; + synchronized (SipService.this) { + if (isBehindNAT(mLocalIp) + && (mIntervalMeasurementProcess == null) + && (mKeepAliveInterval == -1)) { + // Start keep-alive interval measurement, here we allow + // the first profile only as the target service provider + // to measure the life time of NAT port mapping. + startPortMappingLifetimeMeasurement(group); + } + } + // start unregistration to clear up old registration at server // TODO: when rfc5626 is deployed, use reg-id and sip.instance // in registration to avoid adding duplicate entries to server diff --git a/voip/java/com/android/server/sip/SipSessionGroup.java b/voip/java/com/android/server/sip/SipSessionGroup.java index aa616a9e0fa1..b5f1a1737446 100644 --- a/voip/java/com/android/server/sip/SipSessionGroup.java +++ b/voip/java/com/android/server/sip/SipSessionGroup.java @@ -397,7 +397,7 @@ class SipSessionGroup implements SipListener { // for registration boolean mReRegisterFlag = false; - int mRPort; + int mRPort = 0; // lightweight timer class SessionTimer { @@ -447,7 +447,6 @@ class SipSessionGroup implements SipListener { mState = SipSession.State.READY_TO_CALL; mInviteReceived = null; mPeerSessionDescription = null; - mRPort = 0; mAuthenticationRetryCount = 0; if (mDialog != null) mDialog.delete(); diff --git a/wifi/java/android/net/wifi/WifiConfigStore.java b/wifi/java/android/net/wifi/WifiConfigStore.java index 7f9fc31b5fed..d83b968538d2 100644 --- a/wifi/java/android/net/wifi/WifiConfigStore.java +++ b/wifi/java/android/net/wifi/WifiConfigStore.java @@ -478,6 +478,21 @@ class WifiConfigStore { } } + /** + * clear IP configuration for a given network id + */ + static void clearIpConfiguration(int netId) { + synchronized (sConfiguredNetworks) { + WifiConfiguration config = sConfiguredNetworks.get(netId); + if (config != null && config.linkProperties != null) { + // Clear everything except proxy + ProxyProperties proxy = config.linkProperties.getHttpProxy(); + config.linkProperties.clear(); + config.linkProperties.setHttpProxy(proxy); + } + } + } + /** * Fetch the proxy properties for a given network id diff --git a/wifi/java/android/net/wifi/WifiStateMachine.java b/wifi/java/android/net/wifi/WifiStateMachine.java index bd6da6447c9a..6df37bbddc3a 100644 --- a/wifi/java/android/net/wifi/WifiStateMachine.java +++ b/wifi/java/android/net/wifi/WifiStateMachine.java @@ -1439,9 +1439,6 @@ public class WifiStateMachine extends StateMachine { mDhcpStateMachine = null; } - /* Disable interface */ - NetworkUtils.disableInterface(mInterfaceName); - /* Reset data structures */ mWifiInfo.setInetAddress(null); mWifiInfo.setBSSID(null); @@ -1456,10 +1453,13 @@ public class WifiStateMachine extends StateMachine { /* Clear network properties */ mLinkProperties.clear(); + /* Clear IP settings if the network used DHCP */ + if (!WifiConfigStore.isUsingStaticIp(mLastNetworkId)) { + WifiConfigStore.clearIpConfiguration(mLastNetworkId); + } mLastBssid= null; mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID; - } void handlePreDhcpSetup() { |