summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJosh Guilfoyle <Josh.Guilfoyle@T-Mobile.com>2009-11-19 17:43:25 -0800
committerJosh Guilfoyle <Josh.Guilfoyle@T-Mobile.com>2009-11-24 13:29:47 -0800
commit6fff487e464c7cb044ffac0e1dd73d353c82f2ee (patch)
tree2dd74850f731150b32759a1ee47c1341e72550bd
parent9db3d07b9620b4269ab33f78604a36327e536ce1 (diff)
parent9effa6dbd3c7d95e243fcc694f80f2628eac95ca (diff)
downloadframeworks_base-6fff487e464c7cb044ffac0e1dd73d353c82f2ee.zip
frameworks_base-6fff487e464c7cb044ffac0e1dd73d353c82f2ee.tar.gz
frameworks_base-6fff487e464c7cb044ffac0e1dd73d353c82f2ee.tar.bz2
Merge branch 'themes-1.5r2' into themes-eclair
Conflicts: api/current.xml core/java/android/app/ActivityThread.java core/java/android/app/ApplicationContext.java core/java/android/app/Dialog.java core/java/android/app/SearchDialog.java core/java/android/content/Context.java core/java/android/content/Intent.java core/java/android/content/pm/PackageInfo.java core/java/android/content/pm/PackageParser.java core/java/android/content/res/Configuration.java core/java/android/content/res/Resources.java core/java/android/widget/RemoteViews.java core/java/android/widget/TabWidget.java core/java/com/android/internal/os/ZygoteInit.java core/jni/android_util_AssetManager.cpp core/res/AndroidManifest.xml core/res/res/layout/search_dropdown_item_2line.xml core/res/res/layout/select_dialog_item.xml core/res/res/layout/select_dialog_multichoice.xml core/res/res/layout/select_dialog_singlechoice.xml core/res/res/layout/tab_indicator.xml core/res/res/values/attrs.xml core/res/res/values/public.xml core/res/res/values/strings.xml core/res/res/values/themes.xml libs/utils/Android.mk libs/utils/AssetManager.cpp media/java/android/media/RingtoneManager.java services/java/com/android/server/PackageManagerService.java services/java/com/android/server/SystemServer.java services/java/com/android/server/am/ActivityManagerService.java services/java/com/android/server/status/StatusBarService.java tools/aapt/Main.cpp
-rw-r--r--api/current.xml542
-rw-r--r--core/java/android/app/ActivityManager.java24
-rw-r--r--core/java/android/app/ActivityThread.java156
-rw-r--r--core/java/android/app/AlertDialog.java38
-rw-r--r--core/java/android/app/ApplicationContext.java144
-rw-r--r--core/java/android/app/DatePickerDialog.java2
-rw-r--r--core/java/android/app/Dialog.java23
-rw-r--r--core/java/android/app/ProgressDialog.java6
-rw-r--r--core/java/android/app/SearchDialog.java8
-rw-r--r--core/java/android/app/TimePickerDialog.java7
-rw-r--r--core/java/android/content/ContentResolver.java31
-rw-r--r--core/java/android/content/Context.java20
-rw-r--r--core/java/android/content/IExtendedContentProvider.java22
-rw-r--r--core/java/android/content/Intent.java54
-rw-r--r--core/java/android/content/pm/ActivityInfo.java68
-rw-r--r--core/java/android/content/pm/ApplicationInfo.java21
-rw-r--r--core/java/android/content/pm/BaseThemeInfo.java297
-rw-r--r--core/java/android/content/pm/IPackageManager.aidl3
-rw-r--r--core/java/android/content/pm/PackageInfo.java77
-rw-r--r--core/java/android/content/pm/PackageManager.java10
-rw-r--r--core/java/android/content/pm/PackageParser.java83
-rw-r--r--core/java/android/content/pm/SoundsInfo.java170
-rwxr-xr-xcore/java/android/content/pm/ThemeInfo.aidl3
-rw-r--r--core/java/android/content/pm/ThemeInfo.java306
-rw-r--r--core/java/android/content/res/AssetManager.java86
-rw-r--r--core/java/android/content/res/Configuration.java75
-rw-r--r--core/java/android/content/res/CustomTheme.java114
-rw-r--r--core/java/android/content/res/Resources.java73
-rw-r--r--core/java/android/content/res/TypedArray.java54
-rw-r--r--core/java/android/content/res/XmlBlock.java4
-rw-r--r--core/java/android/os/SystemProperties.java47
-rw-r--r--core/java/android/text/method/CharacterPickerDialog.java2
-rw-r--r--core/java/android/util/AttributeSet.java2
-rw-r--r--core/java/android/util/XmlPullAttributes.java5
-rw-r--r--core/java/android/view/ContextThemeWrapper.java84
-rw-r--r--core/java/android/view/View.java2
-rw-r--r--core/java/android/widget/AbsListView.java2
-rw-r--r--core/java/android/widget/CheckedTextView.java2
-rw-r--r--core/java/android/widget/CompoundButton.java2
-rw-r--r--core/java/android/widget/LinearLayout.java8
-rw-r--r--core/java/android/widget/ListView.java26
-rw-r--r--core/java/android/widget/ProgressBar.java4
-rw-r--r--core/java/android/widget/RemoteViews.java18
-rw-r--r--core/java/android/widget/TabWidget.java89
-rw-r--r--core/java/com/android/internal/app/AlertActivity.java2
-rw-r--r--core/java/com/android/internal/app/AlertController.java22
-rw-r--r--core/java/com/android/internal/app/RingtonePickerActivity.java56
-rw-r--r--core/java/com/android/internal/os/ZygoteInit.java2
-rw-r--r--core/java/com/android/internal/view/menu/ContextMenuBuilder.java21
-rw-r--r--core/java/com/android/internal/view/menu/MenuBuilder.java31
-rw-r--r--core/java/com/android/internal/view/menu/MenuDialogHelper.java19
-rw-r--r--core/jni/android_util_AssetManager.cpp310
-rw-r--r--core/res/AndroidManifest.xml16
-rwxr-xr-xcore/res/res/drawable/pluto_mall_icon.pngbin0 -> 7550 bytes
-rw-r--r--core/res/res/layout/list_menu_item_layout.xml10
-rw-r--r--core/res/res/layout/number_picker.xml11
-rw-r--r--core/res/res/layout/search_dropdown_item_2line.xml59
-rw-r--r--core/res/res/layout/select_dialog.xml2
-rw-r--r--core/res/res/layout/select_dialog_item.xml2
-rw-r--r--core/res/res/layout/select_dialog_multichoice.xml3
-rw-r--r--core/res/res/layout/select_dialog_singlechoice.xml4
-rw-r--r--core/res/res/layout/simple_list_item_1.xml1
-rw-r--r--core/res/res/layout/simple_list_item_2.xml2
-rw-r--r--core/res/res/layout/status_bar_expanded.xml5
-rw-r--r--core/res/res/layout/status_bar_latest_event.xml5
-rw-r--r--core/res/res/layout/status_bar_latest_event_content.xml9
-rw-r--r--core/res/res/layout/tab_indicator.xml12
-rw-r--r--core/res/res/values/attrs.xml56
-rw-r--r--core/res/res/values/public.xml27
-rw-r--r--core/res/res/values/strings.xml5
-rw-r--r--core/res/res/values/styles.xml65
-rw-r--r--core/res/res/values/themes.xml41
-rw-r--r--data/etc/platform.xml5
-rw-r--r--graphics/java/android/graphics/drawable/Drawable.java5
-rw-r--r--graphics/java/android/graphics/drawable/GradientDrawable.java5
-rw-r--r--graphics/java/android/graphics/drawable/LayerDrawable.java23
-rw-r--r--include/utils/AssetManager.h30
-rw-r--r--include/utils/ResourceTypes.h4
-rw-r--r--include/utils/ZipEntry.h345
-rw-r--r--include/utils/ZipFile.h270
-rw-r--r--libs/utils/Android.mk2
-rw-r--r--libs/utils/AssetManager.cpp209
-rw-r--r--libs/utils/ResourceTypes.cpp233
-rw-r--r--media/java/android/media/Ringtone.java28
-rw-r--r--media/java/android/media/RingtoneManager.java107
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java4
-rw-r--r--services/java/Android.mk1
-rw-r--r--services/java/com/android/server/AppsLaunchFailureReceiver.java57
-rw-r--r--services/java/com/android/server/PackageManagerService.java163
-rw-r--r--services/java/com/android/server/SystemServer.java16
-rw-r--r--services/java/com/android/server/am/ActivityManagerService.java78
-rw-r--r--services/java/com/android/server/status/ExpandedView.java4
-rw-r--r--services/java/com/android/server/status/LatestItemView.java5
-rw-r--r--services/java/com/android/server/status/StatusBarService.java103
-rw-r--r--test-runner/android/test/mock/MockContext.java2
-rw-r--r--test-runner/android/test/mock/MockPackageManager.java7
-rw-r--r--tools/aapt/Bundle.h5
-rw-r--r--tools/aapt/Main.cpp13
-rw-r--r--tools/aapt/ResourceTable.cpp11
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeXmlBlockParser.java5
100 files changed, 4868 insertions, 484 deletions
diff --git a/api/current.xml b/api/current.xml
index 32d0f1e..4898339 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -1758,6 +1758,17 @@
visibility="public"
>
</field>
+<field name="alertDialogTheme"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843448"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="allowBackup"
type="int"
transient="false"
@@ -2110,6 +2121,17 @@
visibility="public"
>
</field>
+<field name="bottomLeftStrip"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843451"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="bottomMedium"
type="int"
transient="false"
@@ -2143,6 +2165,17 @@
visibility="public"
>
</field>
+<field name="bottomRightStrip"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843452"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="bufferType"
type="int"
transient="false"
@@ -2198,6 +2231,28 @@
visibility="public"
>
</field>
+<field name="buttonStyleTimePickerDown"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843457"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="buttonStyleTimePickerUp"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843456"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="buttonStyleToggle"
type="int"
transient="false"
@@ -2913,6 +2968,17 @@
visibility="public"
>
</field>
+<field name="dialogTheme"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843447"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="dialogTitle"
type="int"
transient="false"
@@ -3441,6 +3507,17 @@
visibility="public"
>
</field>
+<field name="expandedMenuTheme"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843459"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="exported"
type="int"
transient="false"
@@ -4145,6 +4222,17 @@
visibility="public"
>
</field>
+<field name="iconMenuTheme"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843460"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="iconPreview"
type="int"
transient="false"
@@ -5289,6 +5377,28 @@
visibility="public"
>
</field>
+<field name="listItemBackground"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843446"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="listItemTextViewStyle"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843450"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="listPreferredItemHeight"
type="int"
transient="false"
@@ -5520,6 +5630,17 @@
visibility="public"
>
</field>
+<field name="menuItemBackground"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843458"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="mimeType"
type="int"
transient="false"
@@ -6983,6 +7104,17 @@
visibility="public"
>
</field>
+<field name="searchDialogTheme"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843449"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="searchMode"
type="int"
transient="false"
@@ -7742,6 +7874,17 @@
visibility="public"
>
</field>
+<field name="tabIndicatorStyle"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843453"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="tabWidgetStyle"
type="int"
transient="false"
@@ -8061,6 +8204,17 @@
visibility="public"
>
</field>
+<field name="textAppearanceTab"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843454"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="textCheckMark"
type="int"
transient="false"
@@ -8424,6 +8578,17 @@
visibility="public"
>
</field>
+<field name="timePickerInputStyle"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843455"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="tint"
type="int"
transient="false"
@@ -13253,6 +13418,17 @@
visibility="public"
>
</field>
+<field name="Widget_EditText_TimePicker"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16973926"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="Widget_ExpandableListView"
type="int"
transient="false"
@@ -13495,6 +13671,17 @@
visibility="public"
>
</field>
+<field name="Widget_TabIndicator"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16973925"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="Widget_TabWidget"
type="int"
transient="false"
@@ -39818,6 +40005,17 @@
visibility="public"
>
</field>
+<field name="PLUTO_ISTHEMEABLE_ATTRIBUTE_NAME"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;isThemeable&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="className"
type="java.lang.String"
transient="false"
@@ -40006,6 +40204,234 @@
</parameter>
</method>
</class>
+<class name="BaseThemeInfo"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="android.os.Parcelable">
+</implements>
+<constructor name="BaseThemeInfo"
+ type="android.content.pm.BaseThemeInfo"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+</constructor>
+<constructor name="BaseThemeInfo"
+ type="android.content.pm.BaseThemeInfo"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+<parameter name="source" type="android.os.Parcel">
+</parameter>
+</constructor>
+<method name="changeDrmFlagIfNeeded"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+<parameter name="resourcePath" type="java.lang.String">
+</parameter>
+</method>
+<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="author"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="copyright"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="favesAppImageName"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="favesImageName"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="name"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="notificationRingtoneFileName"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="notificationRingtoneName"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="preview"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ringtoneFileName"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ringtoneName"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="soundPackName"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="styleResourceId"
+ type="int"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="themeId"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="themeStyleName"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="thumbnail"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="wallpaperImageName"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
<class name="ComponentInfo"
extends="android.content.pm.PackageItemInfo"
abstract="false"
@@ -40748,6 +41174,16 @@
visibility="public"
>
</field>
+<field name="isThemeApk"
+ type="boolean"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="packageName"
type="java.lang.String"
transient="false"
@@ -41412,6 +41848,17 @@
<parameter name="flags" type="int">
</parameter>
</method>
+<method name="getInstalledThemePackages"
+ return="java.util.List&lt;android.content.pm.PackageInfo&gt;"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="getInstallerPackageName"
return="java.lang.String"
abstract="true"
@@ -43347,6 +43794,76 @@
>
</field>
</class>
+<class name="SoundsInfo"
+ extends="android.content.pm.BaseThemeInfo"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="SoundsInfo"
+ type="android.content.pm.SoundsInfo"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parser" type="org.xmlpull.v1.XmlPullParser">
+</parameter>
+<parameter name="res" type="android.content.res.Resources">
+</parameter>
+<parameter name="attrs" type="android.util.AttributeSet">
+</parameter>
+<exception name="XmlPullParserException" type="org.xmlpull.v1.XmlPullParserException">
+</exception>
+</constructor>
+<field name="CREATOR"
+ type="android.os.Parcelable.Creator"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+<class name="ThemeInfo"
+ extends="android.content.pm.BaseThemeInfo"
+ abstract="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="ThemeInfo"
+ type="android.content.pm.ThemeInfo"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parser" type="org.xmlpull.v1.XmlPullParser">
+</parameter>
+<parameter name="res" type="android.content.res.Resources">
+</parameter>
+<parameter name="attrs" type="android.util.AttributeSet">
+</parameter>
+<exception name="XmlPullParserException" type="org.xmlpull.v1.XmlPullParserException">
+</exception>
+</constructor>
+<field name="CREATOR"
+ type="android.os.Parcelable.Creator"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
</package>
<package name="android.content.res"
>
@@ -132925,6 +133442,17 @@
<parameter name="flags" type="int">
</parameter>
</method>
+<method name="getInstalledThemePackages"
+ return="java.util.List&lt;android.content.pm.PackageInfo&gt;"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="getInstallerPackageName"
return="java.lang.String"
abstract="false"
@@ -186340,6 +186868,20 @@
<parameter name="attrs" type="android.util.AttributeSet">
</parameter>
</constructor>
+<constructor name="LinearLayout"
+ type="android.widget.LinearLayout"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+<parameter name="attrs" type="android.util.AttributeSet">
+</parameter>
+<parameter name="defStyle" type="int">
+</parameter>
+</constructor>
<method name="getBaselineAlignedChildIndex"
return="int"
abstract="false"
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index d709deb..969cdd9 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -21,6 +21,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.pm.ConfigurationInfo;
import android.content.pm.IPackageDataObserver;
+import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.os.Debug;
import android.os.RemoteException;
@@ -923,4 +924,27 @@ public class ActivityManager {
return null;
}
+ /**
+ * @hide
+ */
+ public Configuration getConfiguration() {
+ try {
+ return ActivityManagerNative.getDefault().getConfiguration();
+ } catch (RemoteException e) {
+ return null;
+ }
+ }
+
+ /**
+ * @throws SecurityException Throws SecurityException if the caller does
+ * not hold the {@link android.Manifest.permission#CHANGE_CONFIGURATION} permission.
+ *
+ * @hide
+ */
+ public void updateConfiguration(Configuration values) throws SecurityException {
+ try {
+ ActivityManagerNative.getDefault().updateConfiguration(values);
+ } catch (RemoteException e) {
+ }
+ }
}
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index b116bf8..0f5b5f5 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -16,14 +16,24 @@
package android.app;
+import com.android.internal.os.BinderInternal;
+import com.android.internal.os.RuntimeInit;
+import com.android.internal.os.SamplingProfilerIntegration;
+import com.android.internal.util.ArrayUtils;
+
+import dalvik.system.SamplingProfiler;
+
+import org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl;
+
import android.content.BroadcastReceiver;
import android.content.ComponentCallbacks;
import android.content.ComponentName;
import android.content.ContentProvider;
import android.content.Context;
+import android.content.ContextWrapper;
import android.content.IContentProvider;
-import android.content.Intent;
import android.content.IIntentReceiver;
+import android.content.Intent;
import android.content.ServiceConnection;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
@@ -35,11 +45,13 @@ import android.content.pm.ServiceInfo;
import android.content.res.AssetManager;
import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
+import android.content.res.CustomTheme;
import android.content.res.Resources;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteDebug;
import android.graphics.Bitmap;
import android.graphics.Canvas;
+import android.net.Uri;
import android.net.http.AndroidHttpClient;
import android.os.Bundle;
import android.os.Debug;
@@ -53,12 +65,14 @@ import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
+import android.text.TextUtils;
import android.util.AndroidRuntimeException;
import android.util.Config;
import android.util.DisplayMetrics;
import android.util.EventLog;
import android.util.Log;
import android.view.Display;
+import android.view.InflateException;
import android.view.View;
import android.view.ViewDebug;
import android.view.ViewManager;
@@ -66,13 +80,6 @@ import android.view.Window;
import android.view.WindowManager;
import android.view.WindowManagerImpl;
-import com.android.internal.os.BinderInternal;
-import com.android.internal.os.RuntimeInit;
-import com.android.internal.os.SamplingProfilerIntegration;
-import com.android.internal.util.ArrayUtils;
-
-import org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl;
-
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileOutputStream;
@@ -88,8 +95,6 @@ import java.util.Map;
import java.util.TimeZone;
import java.util.regex.Pattern;
-import dalvik.system.SamplingProfiler;
-
final class IntentReceiverLeaked extends AndroidRuntimeException {
public IntentReceiverLeaked(String msg) {
super(msg);
@@ -176,8 +181,14 @@ public final class ActivityThread {
* @param resDir the resource directory.
* @param compInfo the compability info. It will use the default compatibility info when it's
* null.
+ *
+ * @deprecated use {@link #getTopLevelResources(String, CompatibilityInfo, boolean)} instead.
*/
Resources getTopLevelResources(String resDir, CompatibilityInfo compInfo) {
+ return getTopLevelResources(resDir, compInfo, false);
+ }
+
+ Resources getTopLevelResources(String resDir, CompatibilityInfo compInfo, boolean isThemable) {
synchronized (mPackages) {
// Resources is app scale dependent.
ResourcesKey key = new ResourcesKey(resDir, compInfo.applicationScale);
@@ -201,9 +212,28 @@ public final class ActivityThread {
//}
AssetManager assets = new AssetManager();
+ assets.setThemeSupport(isThemable);
if (assets.addAssetPath(resDir) == 0) {
return null;
}
+ Configuration config = getConfiguration();
+ if (isThemable && config != null) {
+ if (config.customTheme == null) {
+ config.customTheme = CustomTheme.getDefault();
+ }
+
+ if (!TextUtils.isEmpty(config.customTheme.getThemePackageName())) {
+ PackageInfo pi = getPackageInfo(config.customTheme.getThemePackageName(), 0);
+ if (pi != null) {
+ String themeResDir = pi.getResDir();
+ if (assets.addAssetPath(themeResDir) != 0) {
+ assets.setThemePackageName(config.customTheme.getThemePackageName());
+ } else {
+ Log.e(TAG, "Unable to add theme resdir=" + themeResDir);
+ }
+ }
+ }
+ }
//Log.i(TAG, "Resource: key=" + key + ", display metrics=" + metrics);
DisplayMetrics metrics = getDisplayMetricsLocked(false);
@@ -221,11 +251,17 @@ public final class ActivityThread {
/**
* Creates the top level resources for the given package.
+ *
+ * @deprecated {@link #getTopLevelResources(String, PackageInfo, boolean)}
*/
Resources getTopLevelResources(String resDir, PackageInfo pkgInfo) {
return getTopLevelResources(resDir, pkgInfo.mCompatibilityInfo);
}
+ Resources getTopLevelResources(String resDir, PackageInfo pkgInfo, boolean themeable) {
+ return getTopLevelResources(resDir, pkgInfo.mCompatibilityInfo, themeable);
+ }
+
final Handler getHandler() {
return mH;
}
@@ -233,7 +269,7 @@ public final class ActivityThread {
public final static class PackageInfo {
private final ActivityThread mActivityThread;
- private final ApplicationInfo mApplicationInfo;
+ /* package */ final ApplicationInfo mApplicationInfo;
private final String mPackageName;
private final String mAppDir;
private final String mResDir;
@@ -477,12 +513,18 @@ public final class ActivityThread {
public AssetManager getAssets(ActivityThread mainThread) {
return getResources(mainThread).getAssets();
}
-
- public Resources getResources(ActivityThread mainThread) {
- if (mResources == null) {
- mResources = mainThread.getTopLevelResources(mResDir, this);
+
+ public Resources getResources(ActivityThread mainThread, boolean themeable,
+ boolean force) {
+ if (mResources == null || force == true) {
+ mResources = mainThread.getTopLevelResources(mResDir, this, themeable);
}
- return mResources;
+ return mResources;
+ }
+
+ /** @deprecated use {@link #getResources(ActivityThread, boolean, boolean)} instead. */
+ public Resources getResources(ActivityThread mainThread) {
+ return getResources(mainThread, false, false);
}
public Application makeApplication(boolean forceDefaultAppClass,
@@ -2424,7 +2466,18 @@ public final class ActivityThread {
activity.mStartedActivity = false;
int theme = r.activityInfo.getThemeResource();
if (theme != 0) {
- activity.setTheme(theme);
+ // Following is a workaround to have those activity managed dialogs to be themed when the theme flag is on.
+ if (r.activityInfo.isThemeable() && (theme == android.R.style.Theme_Dialog ||
+ theme == com.android.internal.R.style.Theme_Dialog_Alert)) {
+ if (theme == android.R.style.Theme_Dialog) {
+ activity.setTheme(Dialog.resolveDefaultTheme(activity, 0, android.R.styleable.Theme_dialogTheme,
+ com.android.internal.R.style.Theme_Dialog));
+ } else if (theme == com.android.internal.R.style.Theme_Dialog_Alert) {
+ activity.setTheme(AlertDialog.resolveDefaultTheme(activity, 0));
+ }
+ } else {
+ activity.setTheme(theme);
+ }
}
activity.mCalled = false;
@@ -2465,6 +2518,16 @@ public final class ActivityThread {
} catch (Exception e) {
if (!mInstrumentation.onException(activity, e)) {
+ if (e instanceof InflateException) {
+ Log.e(TAG, "Failed to inflate", e);
+ String pkg = null;
+ if (r.packageInfo != null && !TextUtils.isEmpty(r.packageInfo.getPackageName())) {
+ pkg = r.packageInfo.getPackageName();
+ }
+ Intent intent = new Intent(Intent.ACTION_APP_LAUNCH_FAILURE,
+ (pkg != null)? Uri.fromParts("package", pkg, null) : null);
+ getSystemContext().sendBroadcast(intent);
+ }
throw new RuntimeException(
"Unable to start activity " + component
+ ": " + e.toString(), e);
@@ -3707,6 +3770,19 @@ public final class ActivityThread {
}
}
+ private String getPackageResDir(String packageName) {
+ android.content.pm.PackageInfo pi;
+ try {
+ pi = getPackageManager().getPackageInfo(packageName, 0);
+ if (pi == null || pi.applicationInfo == null)
+ return null;
+ return pi.applicationInfo.publicSourceDir;
+ } catch (RemoteException e) {
+ Log.e("ActivityThread", "Exception in getPackageResDir", e);
+ }
+ return null;
+ }
+
final void handleConfigurationChanged(Configuration config) {
synchronized (mRelaunchingActivities) {
@@ -3722,11 +3798,13 @@ public final class ActivityThread {
if (DEBUG_CONFIGURATION) Log.v(TAG, "Handle configuration changed: "
+ config);
+ int diff;
+
synchronized(mPackages) {
if (mConfiguration == null) {
mConfiguration = new Configuration();
}
- mConfiguration.updateFrom(config);
+ diff = mConfiguration.updateFrom(config);
DisplayMetrics dm = getDisplayMetricsLocked(true);
// set it for java, this also affects newly created Resources
@@ -3747,7 +3825,34 @@ public final class ActivityThread {
WeakReference<Resources> v = it.next();
Resources r = v.get();
if (r != null) {
+ boolean themeChanged = (diff & ActivityInfo.CONFIG_THEME_RESOURCE) != 0;
+ if (themeChanged) {
+ AssetManager am = r.getAssets();
+ /*
+ * Dynamically modify the AssetManager object to
+ * replace the old asset path with the new one. This
+ * is made possibly by native layer changes made by
+ * T-Mobile.
+ */
+ if (am.hasThemeSupport()) {
+ String oldThemePackage = am.getThemePackageName();
+ if (!TextUtils.isEmpty(oldThemePackage)) {
+ am.setThemePackageName(null);
+ am.removeAssetPath(oldThemePackage,
+ getPackageResDir(oldThemePackage));
+ }
+ String newThemePackage = config.customTheme.getThemePackageName();
+ String resDir = getPackageResDir(newThemePackage);
+ if (resDir != null) {
+ am.setThemePackageName(newThemePackage);
+ am.updateResourcesWithAssetPath(resDir);
+ }
+ }
+ }
r.updateConfiguration(config, dm);
+ if (themeChanged) {
+ r.updateStringCache();
+ }
//Log.i(TAG, "Updated app resources " + v.getKey()
// + " " + r + ": " + r.getConfiguration());
} else {
@@ -3762,7 +3867,20 @@ public final class ActivityThread {
final int N = callbacks.size();
for (int i=0; i<N; i++) {
- performConfigurationChanged(callbacks.get(i), config);
+ ComponentCallbacks cb = callbacks.get(i);
+
+ // We removed the old resources object from the mActiveResources
+ // cache, now we need to trigger an update for each application.
+ if ((diff & ActivityInfo.CONFIG_THEME_RESOURCE) != 0) {
+ if (cb instanceof Activity || cb instanceof Application) {
+ Context context = ((ContextWrapper)cb).getBaseContext();
+ if (context instanceof ApplicationContext) {
+ ((ApplicationContext)context).refreshResourcesIfNecessary();
+ }
+ }
+ }
+
+ performConfigurationChanged(cb, config);
}
}
diff --git a/core/java/android/app/AlertDialog.java b/core/java/android/app/AlertDialog.java
index 20a579a..3feee4a 100644
--- a/core/java/android/app/AlertDialog.java
+++ b/core/java/android/app/AlertDialog.java
@@ -56,19 +56,25 @@ public class AlertDialog extends Dialog implements DialogInterface {
private AlertController mAlert;
protected AlertDialog(Context context) {
- this(context, com.android.internal.R.style.Theme_Dialog_Alert);
+ this(context, 0);
}
protected AlertDialog(Context context, int theme) {
- super(context, theme);
- mAlert = new AlertController(context, this, getWindow());
+ super(context, resolveDefaultTheme(context, theme));
+ mAlert = new AlertController(getContext(), this, getWindow());
}
protected AlertDialog(Context context, boolean cancelable, OnCancelListener cancelListener) {
- super(context, com.android.internal.R.style.Theme_Dialog_Alert);
+ super(context, resolveDefaultTheme(context, 0));
setCancelable(cancelable);
setOnCancelListener(cancelListener);
- mAlert = new AlertController(context, this, getWindow());
+ mAlert = new AlertController(getContext(), this, getWindow());
+ }
+
+ static int resolveDefaultTheme(Context context, int theme) {
+ return Dialog.resolveDefaultTheme(context, theme,
+ android.R.styleable.Theme_alertDialogTheme,
+ com.android.internal.R.style.Theme_Dialog_Alert);
}
/**
@@ -264,13 +270,15 @@ public class AlertDialog extends Dialog implements DialogInterface {
}
public static class Builder {
+ private final Context mContext;
private final AlertController.AlertParams P;
/**
* Constructor using a context for this builder and the {@link AlertDialog} it creates.
*/
public Builder(Context context) {
- P = new AlertController.AlertParams(context);
+ mContext = context;
+ P = new AlertController.AlertParams();
}
/**
@@ -279,7 +287,7 @@ public class AlertDialog extends Dialog implements DialogInterface {
* @return This Builder object to allow for chaining of calls to set methods
*/
public Builder setTitle(int titleId) {
- P.mTitle = P.mContext.getText(titleId);
+ P.mTitle = mContext.getText(titleId);
return this;
}
@@ -315,7 +323,7 @@ public class AlertDialog extends Dialog implements DialogInterface {
* @return This Builder object to allow for chaining of calls to set methods
*/
public Builder setMessage(int messageId) {
- P.mMessage = P.mContext.getText(messageId);
+ P.mMessage = mContext.getText(messageId);
return this;
}
@@ -357,7 +365,7 @@ public class AlertDialog extends Dialog implements DialogInterface {
* @return This Builder object to allow for chaining of calls to set methods
*/
public Builder setPositiveButton(int textId, final OnClickListener listener) {
- P.mPositiveButtonText = P.mContext.getText(textId);
+ P.mPositiveButtonText = mContext.getText(textId);
P.mPositiveButtonListener = listener;
return this;
}
@@ -383,7 +391,7 @@ public class AlertDialog extends Dialog implements DialogInterface {
* @return This Builder object to allow for chaining of calls to set methods
*/
public Builder setNegativeButton(int textId, final OnClickListener listener) {
- P.mNegativeButtonText = P.mContext.getText(textId);
+ P.mNegativeButtonText = mContext.getText(textId);
P.mNegativeButtonListener = listener;
return this;
}
@@ -409,7 +417,7 @@ public class AlertDialog extends Dialog implements DialogInterface {
* @return This Builder object to allow for chaining of calls to set methods
*/
public Builder setNeutralButton(int textId, final OnClickListener listener) {
- P.mNeutralButtonText = P.mContext.getText(textId);
+ P.mNeutralButtonText = mContext.getText(textId);
P.mNeutralButtonListener = listener;
return this;
}
@@ -465,7 +473,7 @@ public class AlertDialog extends Dialog implements DialogInterface {
* @return This Builder object to allow for chaining of calls to set methods
*/
public Builder setItems(int itemsId, final OnClickListener listener) {
- P.mItems = P.mContext.getResources().getTextArray(itemsId);
+ P.mItems = mContext.getResources().getTextArray(itemsId);
P.mOnClickListener = listener;
return this;
}
@@ -538,7 +546,7 @@ public class AlertDialog extends Dialog implements DialogInterface {
*/
public Builder setMultiChoiceItems(int itemsId, boolean[] checkedItems,
final OnMultiChoiceClickListener listener) {
- P.mItems = P.mContext.getResources().getTextArray(itemsId);
+ P.mItems = mContext.getResources().getTextArray(itemsId);
P.mOnCheckboxClickListener = listener;
P.mCheckedItems = checkedItems;
P.mIsMultiChoice = true;
@@ -617,7 +625,7 @@ public class AlertDialog extends Dialog implements DialogInterface {
*/
public Builder setSingleChoiceItems(int itemsId, int checkedItem,
final OnClickListener listener) {
- P.mItems = P.mContext.getResources().getTextArray(itemsId);
+ P.mItems = mContext.getResources().getTextArray(itemsId);
P.mOnClickListener = listener;
P.mCheckedItem = checkedItem;
P.mIsSingleChoice = true;
@@ -783,7 +791,7 @@ public class AlertDialog extends Dialog implements DialogInterface {
* to do and want this to be created and displayed.
*/
public AlertDialog create() {
- final AlertDialog dialog = new AlertDialog(P.mContext);
+ final AlertDialog dialog = new AlertDialog(mContext);
P.apply(dialog.mAlert);
dialog.setCancelable(P.mCancelable);
dialog.setOnCancelListener(P.mOnCancelListener);
diff --git a/core/java/android/app/ApplicationContext.java b/core/java/android/app/ApplicationContext.java
index f48f150..126ddef 100644
--- a/core/java/android/app/ApplicationContext.java
+++ b/core/java/android/app/ApplicationContext.java
@@ -20,6 +20,23 @@ import com.android.internal.policy.PolicyManager;
import com.android.internal.util.XmlUtils;
import com.google.android.collect.Maps;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.WeakHashMap;
+import java.util.Set;
+import java.util.HashSet;
+import java.util.Map.Entry;
+
import org.xmlpull.v1.XmlPullParserException;
import android.content.BroadcastReceiver;
@@ -52,7 +69,10 @@ import android.content.pm.PermissionInfo;
import android.content.pm.ProviderInfo;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
+import android.content.pm.ThemeInfo;
import android.content.res.AssetManager;
+import android.content.res.Configuration;
+import android.content.res.CustomTheme;
import android.content.res.Resources;
import android.content.res.XmlResourceParser;
import android.database.sqlite.SQLiteDatabase;
@@ -80,9 +100,11 @@ import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.Vibrator;
+import android.os.Process;
import android.os.FileUtils.FileStatus;
import android.telephony.TelephonyManager;
import android.text.ClipboardManager;
+import android.text.TextUtils;
import android.util.AndroidRuntimeException;
import android.util.Log;
import android.view.ContextThemeWrapper;
@@ -110,6 +132,10 @@ import java.util.Set;
import java.util.WeakHashMap;
import java.util.Map.Entry;
+import com.android.internal.policy.PolicyManager;
+import com.android.internal.util.XmlUtils;
+import com.google.android.collect.Maps;
+
class ReceiverRestrictedContext extends ContextWrapper {
ReceiverRestrictedContext(Context base) {
super(base);
@@ -152,6 +178,7 @@ class ApplicationContext extends Context {
private static final Object sSync = new Object();
private static AlarmManager sAlarmManager;
+
private static PowerManager sPowerManager;
private static ConnectivityManager sConnectivityManager;
private static WifiManager sWifiManager;
@@ -183,6 +210,7 @@ class ApplicationContext extends Context {
private boolean mRestricted;
private AccountManager mAccountManager; // protected by mSync
+
private final Object mSync = new Object();
private File mDatabasesDir;
@@ -216,6 +244,20 @@ class ApplicationContext extends Context {
return mResources;
}
+ /**
+ * Refresh resources object which may have been changed by a theme
+ * configuration change.
+ */
+ /* package */ void refreshResourcesIfNecessary() {
+ if (mResources == Resources.getSystem()) {
+ return;
+ }
+
+ if (mPackageInfo.mApplicationInfo.isThemeable) {
+ mTheme = null;
+ }
+ }
+
@Override
public PackageManager getPackageManager() {
if (mPackageManager != null) {
@@ -250,23 +292,62 @@ class ApplicationContext extends Context {
public void setTheme(int resid) {
mThemeResource = resid;
}
+
+ private int determineDefaultThemeResource() {
+ if (getResources() != Resources.getSystem() && mPackageInfo.mApplicationInfo.isThemeable) {
+ try {
+ Configuration config = ActivityManagerNative.getDefault().getConfiguration();
+ if (config.customTheme != null) {
+ int themeId = CustomTheme.getStyleId(this,
+ config.customTheme.getThemePackageName(),
+ config.customTheme.getThemeId());
+ if (themeId == -1) {
+ CustomTheme defaultTheme = CustomTheme.getDefault();
+ if (config.customTheme.equals(defaultTheme)) {
+ return com.android.internal.R.style.Theme;
+ } else {
+ themeId = CustomTheme.getStyleId(this,
+ defaultTheme.getThemePackageName(),
+ defaultTheme.getThemeId());
+ if (themeId == -1) {
+ return com.android.internal.R.style.Theme;
+ } else {
+ return themeId;
+ }
+ }
+ } else {
+ return themeId;
+ }
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "Unable to access configuration, reverting to original system default theme", e);
+ }
+ }
+
+ /* Fallback... */
+ return com.android.internal.R.style.Theme;
+ }
@Override
public Resources.Theme getTheme() {
if (mTheme == null) {
+ int themeId;
if (mThemeResource == 0) {
- mThemeResource = com.android.internal.R.style.Theme;
+ themeId = determineDefaultThemeResource();
+ } else {
+ themeId = mThemeResource;
}
+
mTheme = mResources.newTheme();
- mTheme.applyStyle(mThemeResource, true);
+ mTheme.applyStyle(themeId, true);
}
return mTheme;
}
@Override
public ClassLoader getClassLoader() {
- return mPackageInfo != null ?
- mPackageInfo.getClassLoader() : ClassLoader.getSystemClassLoader();
+ return mPackageInfo != null ? mPackageInfo.getClassLoader()
+ : ClassLoader.getSystemClassLoader();
}
@Override
@@ -539,6 +620,40 @@ class ApplicationContext extends Context {
getWallpaperManager().setStream(data);
}
+ // If the default theme specifies wallpaper, returns the wallpaper Uri, otherwise returns null
+ private InputStream getDefaultThemeWallpaperStream() {
+ CustomTheme defaultTheme = CustomTheme.getDefault();
+ String themeId = defaultTheme.getThemeId();
+ String packageName = defaultTheme.getThemePackageName();
+ if (!TextUtils.isEmpty(themeId) &&
+ !TextUtils.isEmpty(packageName)) {
+ try {
+ PackageInfo pi = getPackageManager().getPackageInfo(packageName, 0);
+ ThemeInfo[] infos = pi.themeInfos;
+ String wallpaperPath = null;
+ if (infos != null) {
+ for (ThemeInfo ti : infos) {
+ if (ti.themeId.equals(themeId)) {
+ wallpaperPath = ti.wallpaperImageName;
+ break;
+ }
+ }
+ }
+ if (TextUtils.isEmpty(wallpaperPath)) {
+ return null;
+ }
+ // Unfortunately, we can't use ContentProvider and walpaper uri:
+ // due to timing issue, the uri of interest may still be not
+ // available by the time launcher needs to render the wallpaper.
+ Resources res = getPackageManager().getResourcesForApplication(packageName);
+ return res.getAssets().open(wallpaperPath);
+ } catch (Exception e) {
+ Log.e(TAG, "Can't get wallpaper for default theme in clearWallpaper", e);
+ }
+ }
+ return null;
+ }
+
@Override
public void clearWallpaper() throws IOException {
getWallpaperManager().clear();
@@ -932,7 +1047,7 @@ class ApplicationContext extends Context {
}
return sAlarmManager;
}
-
+
private PowerManager getPowerManager() {
synchronized (sSync) {
if (sPowerManager == null) {
@@ -1363,7 +1478,8 @@ class ApplicationContext extends Context {
IBinder activityToken, ActivityThread mainThread,
Resources container) {
mPackageInfo = packageInfo;
- mResources = mPackageInfo.getResources(mainThread);
+ mResources = mPackageInfo.getResources(mainThread,
+ packageInfo.mApplicationInfo.isThemeable, false);
if (container != null && container.getCompatibilityInfo().applicationScale !=
mResources.getCompatibilityInfo().applicationScale) {
@@ -1372,7 +1488,8 @@ class ApplicationContext extends Context {
" compatiblity info:" + container.getDisplayMetrics());
}
mResources = mainThread.getTopLevelResources(
- mPackageInfo.getResDir(), container.getCompatibilityInfo().copy());
+ mPackageInfo.getResDir(), container.getCompatibilityInfo().copy(),
+ packageInfo.mApplicationInfo.isThemeable);
}
mMainThread = mainThread;
mContentResolver = new ApplicationContentResolver(this, mainThread);
@@ -1763,6 +1880,16 @@ class ApplicationContext extends Context {
}
@Override
+ public List<PackageInfo> getInstalledThemePackages() {
+ try {
+ return mPM.getInstalledThemePackages();
+ } catch (RemoteException e) {
+ throw new RuntimeException("Package manager has died", e);
+ }
+ }
+
+
+ @Override
public List<ApplicationInfo> getInstalledApplications(int flags) {
try {
return mPM.getInstalledApplications(flags);
@@ -2026,7 +2153,8 @@ class ApplicationContext extends Context {
}
Resources r = mContext.mMainThread.getTopLevelResources(
app.uid == Process.myUid() ? app.sourceDir
- : app.publicSourceDir, mContext.mPackageInfo);
+ : app.publicSourceDir, mContext.mPackageInfo,
+ app.isThemeable);
if (r != null) {
return r;
}
diff --git a/core/java/android/app/DatePickerDialog.java b/core/java/android/app/DatePickerDialog.java
index 78bbb4f..08e143b 100644
--- a/core/java/android/app/DatePickerDialog.java
+++ b/core/java/android/app/DatePickerDialog.java
@@ -80,7 +80,7 @@ public class DatePickerDialog extends AlertDialog implements OnClickListener,
int year,
int monthOfYear,
int dayOfMonth) {
- this(context, com.android.internal.R.style.Theme_Dialog_Alert,
+ this(context, 0,
callBack, year, monthOfYear, dayOfMonth);
}
diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java
index 58e8b32..4ee74d3 100644
--- a/core/java/android/app/Dialog.java
+++ b/core/java/android/app/Dialog.java
@@ -22,6 +22,7 @@ import android.content.Context;
import android.content.DialogInterface;
import android.content.ComponentName;
import android.content.ContextWrapper;
+import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle;
@@ -134,8 +135,9 @@ public class Dialog implements DialogInterface, Window.Callback,
* <var>context</var>. If 0, the default dialog theme will be used.
*/
public Dialog(Context context, int theme) {
- mContext = new ContextThemeWrapper(
- context, theme == 0 ? com.android.internal.R.style.Theme_Dialog : theme);
+ mContext = new ContextThemeWrapper(context,
+ resolveDefaultTheme(context, theme, android.R.styleable.Theme_dialogTheme,
+ com.android.internal.R.style.Theme_Dialog));
mWindowManager = (WindowManager)context.getSystemService("window");
Window w = PolicyManager.makeNewWindow(mContext);
mWindow = w;
@@ -147,6 +149,23 @@ public class Dialog implements DialogInterface, Window.Callback,
}
/**
+ * This method is provided to work around the constructor pattern limitation
+ * present in Dialog. We must resolve theme==0 to the runtime specified
+ * theme, but this cannot be done by subclasses except through this method.
+ */
+ static int resolveDefaultTheme(Context context, int theme, int themeAttrIndex,
+ int staticDefault) {
+ if (theme != 0) {
+ return theme;
+ } else {
+ TypedArray a = context.obtainStyledAttributes(android.R.styleable.Theme);
+ int newTheme = a.getResourceId(themeAttrIndex, staticDefault);
+ a.recycle();
+ return newTheme;
+ }
+ }
+
+ /**
* @deprecated
* @hide
*/
diff --git a/core/java/android/app/ProgressDialog.java b/core/java/android/app/ProgressDialog.java
index bdea069..03b2c05 100644
--- a/core/java/android/app/ProgressDialog.java
+++ b/core/java/android/app/ProgressDialog.java
@@ -73,13 +73,13 @@ public class ProgressDialog extends AlertDialog {
private Handler mViewUpdateHandler;
public ProgressDialog(Context context) {
- this(context, com.android.internal.R.style.Theme_Dialog_Alert);
+ this(context, 0);
}
public ProgressDialog(Context context, int theme) {
- super(context, theme);
+ super(context, resolveDefaultTheme(context, theme));
}
-
+
public static ProgressDialog show(Context context, CharSequence title,
CharSequence message) {
return show(context, title, message, false);
diff --git a/core/java/android/app/SearchDialog.java b/core/java/android/app/SearchDialog.java
index e5a769b..df277e5 100644
--- a/core/java/android/app/SearchDialog.java
+++ b/core/java/android/app/SearchDialog.java
@@ -159,7 +159,7 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
* @param context Application Context we can use for system acess
*/
public SearchDialog(Context context) {
- super(context, com.android.internal.R.style.Theme_GlobalSearchBar);
+ super(context, resolveDefaultTheme(context, 0));
// Save voice intent for later queries/launching
mVoiceWebSearchIntent = new Intent(RecognizerIntent.ACTION_WEB_SEARCH);
@@ -171,6 +171,12 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
mVoiceAppSearchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
}
+ static int resolveDefaultTheme(Context context, int theme) {
+ return Dialog.resolveDefaultTheme(context, theme,
+ android.R.styleable.Theme_searchDialogTheme,
+ com.android.internal.R.style.Theme_SearchBar);
+ }
+
/**
* Create the search dialog and any resources that are used for the
* entire lifetime of the dialog.
diff --git a/core/java/android/app/TimePickerDialog.java b/core/java/android/app/TimePickerDialog.java
index 002b01f..2fa2ea1 100644
--- a/core/java/android/app/TimePickerDialog.java
+++ b/core/java/android/app/TimePickerDialog.java
@@ -73,8 +73,7 @@ public class TimePickerDialog extends AlertDialog implements OnClickListener,
public TimePickerDialog(Context context,
OnTimeSetListener callBack,
int hourOfDay, int minute, boolean is24HourView) {
- this(context, com.android.internal.R.style.Theme_Dialog_Alert,
- callBack, hourOfDay, minute, is24HourView);
+ this(context, 0, callBack, hourOfDay, minute, is24HourView);
}
/**
@@ -95,7 +94,7 @@ public class TimePickerDialog extends AlertDialog implements OnClickListener,
mInitialMinute = minute;
mIs24HourView = is24HourView;
- mDateFormat = DateFormat.getTimeFormat(context);
+ mDateFormat = DateFormat.getTimeFormat(getContext());
mCalendar = Calendar.getInstance();
updateTitle(mInitialHourOfDay, mInitialMinute);
@@ -104,7 +103,7 @@ public class TimePickerDialog extends AlertDialog implements OnClickListener,
setIcon(R.drawable.ic_dialog_time);
LayoutInflater inflater =
- (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View view = inflater.inflate(R.layout.time_picker_dialog, null);
setView(view);
mTimePicker = (TimePicker) view.findViewById(R.id.timePicker);
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index c4b0807..f87aceb 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -342,6 +342,17 @@ public abstract class ContentResolver {
// with sufficient testing.
return new FileInputStream(uri.getPath());
} else {
+ // This is a work around for the following bug.
+ // If an asset is stored in a separate file, then AssetFileDescriptor.createInputStream
+ // works. However, if an asset is stored in .apk or .zip file, then
+ // AssetFileDescriptor.createInputStream returns a stream which does not
+ // contain valid data (I can repro the bug using SDK 1.1 and "regular" apk).
+ // To work around the bug, we try to get the input stream from AssetManager
+ // first and only if that failed, fall back to the "standard" approach.
+ InputStream stream = openInputStreamEx(uri);
+ if (stream != null) {
+ return stream;
+ }
AssetFileDescriptor fd = openAssetFileDescriptor(uri, "r");
try {
return fd != null ? fd.createInputStream() : null;
@@ -351,6 +362,26 @@ public abstract class ContentResolver {
}
}
+ private InputStream openInputStreamEx(Uri uri) {
+ IContentProvider provider = acquireProvider(uri);
+ ContentProvider cp = null;
+ if (provider == null) {
+ return null;
+ }
+ if (provider instanceof ContentProvider.Transport) {
+ cp = ((ContentProvider.Transport)provider).getContentProvider();
+ } else if (provider instanceof ContentProvider) {
+ cp = (ContentProvider)provider;
+ }
+ if (cp == null) {
+ return null;
+ }
+ if (cp instanceof IExtendedContentProvider) {
+ return ((IExtendedContentProvider)cp).openInputStream(uri);
+ }
+ return null;
+ }
+
/**
* Synonym for {@link #openOutputStream(Uri, String)
* openOutputStream(uri, "w")}.
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 8f1c671..34d04a3 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -17,11 +17,20 @@
package android.content;
import android.content.pm.ApplicationInfo;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
import android.content.pm.PackageManager;
import android.content.res.AssetManager;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteException;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
@@ -31,13 +40,6 @@ import android.os.Handler;
import android.os.Looper;
import android.util.AttributeSet;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-
/**
* Interface to global information about an application environment. This is
* an abstract class whose implementation is provided by
@@ -200,7 +202,7 @@ public abstract class Context {
int resid, int[] attrs) throws Resources.NotFoundException {
return getTheme().obtainStyledAttributes(resid, attrs);
}
-
+
/**
* Retrieve styled attribute information in this Context's theme. See
* {@link Resources.Theme#obtainStyledAttributes(AttributeSet, int[], int, int)}
@@ -1291,7 +1293,7 @@ public abstract class Context {
* @see android.text.ClipboardManager
*/
public static final String CLIPBOARD_SERVICE = "clipboard";
-
+
/**
* Use with {@link #getSystemService} to retrieve a
* {@link android.view.inputmethod.InputMethodManager} for accessing input
diff --git a/core/java/android/content/IExtendedContentProvider.java b/core/java/android/content/IExtendedContentProvider.java
new file mode 100644
index 0000000..7cbb19a
--- /dev/null
+++ b/core/java/android/content/IExtendedContentProvider.java
@@ -0,0 +1,22 @@
+package android.content;
+
+import java.io.InputStream;
+
+import android.net.Uri;
+
+/**
+ * The interface which "extends" IContentProvider.
+ * ContentProviders may implement the interface
+ * to work around the following bug.
+ * If an image asset is stored in a separate file,
+ * then AssetFileDescriptor.createInputStream returns stream with valid data.
+ * However, if an image asset is stored in .apk or .zip file, then
+ * AssetFileDescriptor.createInputStream returns a stream which does not
+ * contain valid data (the bug repro with SDK 1.1 and "regular" apk).
+ * To address this issue, ContentProviders may want to implement this interface.
+ *
+ * @hide
+ */
+public interface IExtendedContentProvider {
+ public InputStream openInputStream(Uri uri);
+}
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index b785dbf..e47099e 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1756,6 +1756,26 @@ public class Intent implements Parcelable {
public static final String ACTION_PRE_BOOT_COMPLETED =
"android.intent.action.PRE_BOOT_COMPLETED";
+ /**
+ * Broadcast Action: Indicate that unrecoverable error happened during app launch.
+ * Could indicate that curently applied theme is malicious.
+ * @hide
+ */
+ public static final String ACTION_APP_LAUNCH_FAILURE = "com.tmobile.intent.action.APP_LAUNCH_FAILURE";
+
+ /**
+ * Broadcast Action: Request to reset the unrecoverable errors count to 0.
+ * @hide
+ */
+ public static final String ACTION_APP_LAUNCH_FAILURE_RESET = "com.tmobile.intent.action.APP_LAUNCH_FAILURE_RESET";
+
+ /**
+ * Activity Action: Pick wallpaper from a list.
+ * Used instead of SET_WALLPAPER when we only need to pick wallpaper and do not set it.
+ * @hide
+ */
+ public static final String ACTION_PICK_WALLPAPER = "com.tmobile.intent.action.PICK_WALLPAPER";
+
// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
// Standard intent categories (see addCategory()).
@@ -1883,6 +1903,7 @@ public class Intent implements Parcelable {
*/
public static final String CATEGORY_FRAMEWORK_INSTRUMENTATION_TEST =
"android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST";
+
/**
* An activity to run when device is inserted into a car dock.
* Used with {@link #ACTION_MAIN} to launch an activity.
@@ -1898,6 +1919,14 @@ public class Intent implements Parcelable {
@SdkConstant(SdkConstantType.INTENT_CATEGORY)
public static final String CATEGORY_DESK_DOCK = "android.intent.category.DESK_DOCK";
+ /**
+ * Used to indicate that a theme package has been installed or un-installed.
+ *
+ * @hide
+ */
+ public static final String CATEGORY_THEME_PACKAGE_INSTALLED_STATE_CHANGE =
+ "com.tmobile.intent.category.THEME_PACKAGE_INSTALL_STATE_CHANGE";
+
// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
// Standard extra data keys.
@@ -2112,6 +2141,31 @@ public class Intent implements Parcelable {
public static final String EXTRA_CLIENT_INTENT =
"android.intent.extra.client_intent";
+ /**
+ * Used as a string extra field in {@link com.tmobile.intent.action.PICK_WALLPAPER}
+ * intents to tell the caller how to access bitmap resource.
+ * This can be either a Uri, a resource id or a relative path for raw resource.
+ *
+ * @hide
+ */
+ public static final String EXTRA_WALLPAPER_IMAGE = "com.tmobile.intent.extra.WALLPAPER_IMAGE";
+
+ /**
+ * Used as a string extra field in {@link com.tmobile.intent.action.PICK_WALLPAPER}
+ * intents to tell the caller the bitmap UI name (to be shown to the user).
+ *
+ * @hide
+ */
+ public static final String EXTRA_WALLPAPER_IMAGE_NAME = "com.tmobile.intent.extra.WALLPAPER_IMAGE_NAME";
+
+ /**
+ * Used as a bitmap extra field in {@link com.tmobile.intent.action.PICK_WALLPAPER}
+ * intents containing thumbnail image.
+ *
+ * @hide
+ */
+ public static final String EXTRA_WALLPAPER_THUMBNAIL = "com.tmobile.intent.extra.EXTRA_WALLPAPER_THUMBNAIL";
+
// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
// Intent flags (see mFlags variable).
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index 87da55f..0ffac89 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -243,6 +243,14 @@ public class ActivityInfo extends ComponentInfo
* {@link android.R.attr#configChanges} attribute.
*/
public static final int CONFIG_ORIENTATION = 0x0080;
+
+ /**
+ * @hide
+ */
+ public static final int CONFIG_THEME_RESOURCE = 0x008000;
+
+
+
/**
* Bit in {@link #configChanges} that indicates that the activity
* can itself handle changes to the screen layout. Set from the
@@ -279,7 +287,45 @@ public class ActivityInfo extends ComponentInfo
* the mode from the theme will be used.
*/
public int softInputMode;
-
+
+ /**
+ * isThemeable flag is not explicitly set - use isThemeable value from ApllicationInfo.
+ */
+ private static final int ISTHEMEABLE_INHERITED = 0;
+
+ /**
+ * isThemeable flag is explicitly set to false.
+ */
+ private static final int ISTHEMEABLE_FALSE = 1;
+
+ /**
+ * isThemeable flag is explicitly set to true.
+ */
+ private static final int ISTHEMEABLE_TRUE = 2;
+
+ /**
+ * Is given activity theme agnostic, i.e. behaves properly when default theme is changed.
+ * {@hide}
+ */
+ private int isThemeable = ISTHEMEABLE_INHERITED;
+
+ /**
+ * {@hide}
+ */
+ public boolean getIsThemeable() {
+ if (isThemeable == ISTHEMEABLE_INHERITED) {
+ return applicationInfo != null && applicationInfo.isThemeable;
+ }
+ return isThemeable != ISTHEMEABLE_FALSE;
+ }
+
+ /**
+ * {@hide}
+ */
+ public void setIsThemeable(boolean value) {
+ isThemeable = value? ISTHEMEABLE_TRUE : ISTHEMEABLE_FALSE;
+ }
+
public ActivityInfo() {
}
@@ -294,6 +340,7 @@ public class ActivityInfo extends ComponentInfo
screenOrientation = orig.screenOrientation;
configChanges = orig.configChanges;
softInputMode = orig.softInputMode;
+ isThemeable = orig.isThemeable;
}
/**
@@ -306,6 +353,22 @@ public class ActivityInfo extends ComponentInfo
public final int getThemeResource() {
return theme != 0 ? theme : applicationInfo.theme;
}
+
+ /**
+ * @hide
+ */
+ public final boolean isThemeable() {
+ switch (isThemeable) {
+ case ISTHEMEABLE_TRUE:
+ return true;
+
+ case ISTHEMEABLE_INHERITED:
+ return applicationInfo.isThemeable;
+
+ default:
+ return false;
+ }
+ }
public void dump(Printer pw, String prefix) {
super.dumpFront(pw, prefix);
@@ -318,6 +381,7 @@ public class ActivityInfo extends ComponentInfo
pw.println(prefix + "screenOrientation=" + screenOrientation
+ " configChanges=0x" + Integer.toHexString(configChanges)
+ " softInputMode=0x" + Integer.toHexString(softInputMode));
+ pw.println(prefix + "isThemeable=" + isThemeable);
super.dumpBack(pw, prefix);
}
@@ -342,6 +406,7 @@ public class ActivityInfo extends ComponentInfo
dest.writeInt(screenOrientation);
dest.writeInt(configChanges);
dest.writeInt(softInputMode);
+ dest.writeInt(isThemeable);
}
public static final Parcelable.Creator<ActivityInfo> CREATOR
@@ -365,5 +430,6 @@ public class ActivityInfo extends ComponentInfo
screenOrientation = source.readInt();
configChanges = source.readInt();
softInputMode = source.readInt();
+ isThemeable = source.readInt();
}
}
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 7a65af8..dce3806 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -268,6 +268,24 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
*/
public boolean enabled = true;
+ /**
+ * Is given application theme agnostic, i.e. behaves properly when default theme is changed.
+ * {@hide}
+ */
+ public boolean isThemeable = false;
+
+ private static final String PLUTO_SCHEMA = "http://www.w3.org/2001/pluto.html";
+
+ public static final String PLUTO_ISTHEMEABLE_ATTRIBUTE_NAME = "isThemeable";
+
+ /**
+ *
+ * @hide
+ */
+ public static boolean isPlutoNamespace(String namespace) {
+ return namespace != null && namespace.equalsIgnoreCase(PLUTO_SCHEMA);
+ }
+
public void dump(Printer pw, String prefix) {
super.dumpFront(pw, prefix);
pw.println(prefix + "className=" + className);
@@ -331,6 +349,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
enabled = orig.enabled;
manageSpaceActivityName = orig.manageSpaceActivityName;
descriptionRes = orig.descriptionRes;
+ isThemeable = orig.isThemeable;
}
@@ -362,6 +381,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
dest.writeString(manageSpaceActivityName);
dest.writeString(backupAgentName);
dest.writeInt(descriptionRes);
+ dest.writeInt(isThemeable? 1 : 0);
}
public static final Parcelable.Creator<ApplicationInfo> CREATOR
@@ -392,6 +412,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
manageSpaceActivityName = source.readString();
backupAgentName = source.readString();
descriptionRes = source.readInt();
+ isThemeable = source.readInt() != 0;
}
/**
diff --git a/core/java/android/content/pm/BaseThemeInfo.java b/core/java/android/content/pm/BaseThemeInfo.java
new file mode 100644
index 0000000..e389af7
--- /dev/null
+++ b/core/java/android/content/pm/BaseThemeInfo.java
@@ -0,0 +1,297 @@
+package android.content.pm;
+
+import android.os.Parcelable;
+import android.os.Parcel;
+import android.util.Log;
+import android.util.AttributeSet;
+import android.content.res.Resources;
+
+public class BaseThemeInfo implements Parcelable {
+
+ /**
+ * The name of the wallpaper image file.
+ * Specifies a relative path in assets subfolder.
+ * If the parent's name is "locked" - DRM protected.
+ *
+ * @see wallpaperImage attribute
+ */
+ public String wallpaperImageName;
+
+ /**
+ * The name of the favorites background image file.
+ * Specifies a relative path in assets subfolder.
+ * If the parent's name is "locked" - DRM protected.
+ *
+ * @see favesBackground attribute
+ *
+ */
+ public String favesImageName;
+
+ /**
+ * The name of the favorite apps background image file.
+ * Specifies a relative path in assets subfolder.
+ * If the parent's name is "locked" - DRM protected.
+ *
+ * @see favesAppBackground attribute
+ *
+ */
+ public String favesAppImageName;
+
+ /**
+ * The resource id of theme thumbnail.
+ * Specifies a theme thumbnail image resource as @drawable/foo.
+ *
+ * @see thumbnail attribute
+ *
+ */
+ public String thumbnail;
+
+ /**
+ * The theme id, which does not change when the theme is modified.
+ * Specifies an Android UI Style using style name.
+ *
+ * @see themeId attribute
+ *
+ */
+ public String themeId;
+
+ /**
+ * The style resource id of Android UI Style, supplied by the resource commpiler.
+ * Specifies an Android UI Style id.
+ *
+ * @see styleId attribute
+ *
+ */
+ public int styleResourceId = -1;
+
+ /**
+ * The name of the theme (as displayed by UI).
+ *
+ * @see name attribute
+ *
+ */
+ public String name;
+
+ /**
+ * The name of the call ringtone audio file.
+ * Specifies a relative path in assets subfolder.
+ * If the parent's name is "locked" - DRM protected.
+ *
+ * @see ringtoneFileName attribute
+ *
+ */
+ public String ringtoneFileName;
+
+ /**
+ * The name of the call ringtone as shown to user.
+ *
+ * @see ringtoneName attribute
+ *
+ */
+ public String ringtoneName;
+
+ /**
+ * The name of the notification ringtone audio file.
+ * Specifies a relative path in assets subfolder.
+ * If the parent's name is "locked" - DRM protected.
+ *
+ * @see notificationRingtoneFileName attribute
+ *
+ */
+ public String notificationRingtoneFileName;
+
+ /**
+ * The name of the notification ringtone as shown to user.
+ *
+ * @see notificationRingtoneName attribute
+ *
+ */
+ public String notificationRingtoneName;
+
+ /**
+ * The author name of the theme package.
+ *
+ * @see author attribute
+ *
+ */
+ public String author;
+
+ /**
+ * The copyright text.
+ *
+ * @see copyright attribute
+ *
+ */
+ public String copyright;
+
+ /**
+ * {@hide}
+ */
+ // There is no corresposponding flag in manifest file
+ // This flag is set to true iff any media resource is DRM protected
+ public boolean isDrmProtected = false;
+
+ /**
+ * The name of the "main" theme style (as displayed by UI).
+ *
+ * @see themeStyleName attribute
+ *
+ */
+ public String themeStyleName;
+
+ /**
+ * The filename of the preview image.
+ * Specifies a theme preview image resource as a path into the assets
+ * subfolder.
+ *
+ * @see preview attribute
+ */
+ public String preview;
+
+ /**
+ * {@hide}
+ */
+ public enum InfoObjectType {
+ TYPE_THEME,
+ TYPE_SOUNDPACK,
+ }
+
+ /**
+ * {@hide}
+ */
+ public InfoObjectType type;
+
+ /**
+ * The name of a sound pack.
+ *
+ * @see soundpack attribute
+ *
+ */
+ public String soundPackName;
+
+
+ private static final String LOCKED_NAME = "locked/";
+
+ /*
+ * Describe the kinds of special objects contained in this Parcelable's
+ * marshalled representation.
+ *
+ * @return a bitmask indicating the set of special object types marshalled
+ * by the Parcelable.
+ *
+ * @see android.os.Parcelable#describeContents()
+ */
+ public int describeContents() {
+ return 0;
+ }
+
+ /*
+ * Flatten this object in to a Parcel.
+ *
+ * @param dest The Parcel in which the object should be written.
+ * @param flags Additional flags about how the object should be written.
+ * May be 0 or {@link #PARCELABLE_WRITE_RETURN_VALUE}.
+ *
+ * @see android.os.Parcelable#writeToParcel(android.os.Parcel, int)
+ */
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(objectTypeToInt(type));
+ dest.writeString(wallpaperImageName);
+ dest.writeString(favesImageName);
+ dest.writeString(favesAppImageName);
+ dest.writeString(thumbnail);
+ dest.writeString(themeId);
+ dest.writeInt(styleResourceId);
+ dest.writeString(name);
+ dest.writeString(ringtoneFileName);
+ dest.writeString(notificationRingtoneFileName);
+ dest.writeString(ringtoneName);
+ dest.writeString(notificationRingtoneName);
+ dest.writeString(author);
+ dest.writeString(copyright);
+ dest.writeInt(isDrmProtected? 1 : 0);
+ dest.writeString(soundPackName);
+ dest.writeString(themeStyleName);
+ dest.writeString(preview);
+ }
+
+ /** @hide */
+ public static final Parcelable.Creator<BaseThemeInfo> CREATOR
+ = new Parcelable.Creator<BaseThemeInfo>() {
+ public BaseThemeInfo createFromParcel(Parcel source) {
+ return new BaseThemeInfo(source);
+ }
+
+ public BaseThemeInfo[] newArray(int size) {
+ return new BaseThemeInfo[size];
+ }
+ };
+
+ /** @hide */
+ public final String getResolvedString(Resources res, AttributeSet attrs, int index) {
+ int resId = attrs.getAttributeResourceValue(index, 0);
+ if (resId !=0 ) {
+ return res.getString(resId);
+ }
+ return attrs.getAttributeValue(index);
+ }
+
+ protected BaseThemeInfo() {
+ }
+
+ protected BaseThemeInfo(Parcel source) {
+ type = intToInfoObjectType(source.readInt());
+ wallpaperImageName = source.readString();
+ favesImageName = source.readString();
+ favesAppImageName = source.readString();
+ thumbnail = source.readString();
+ themeId = source.readString();
+ styleResourceId = source.readInt();
+ name = source.readString();
+ ringtoneFileName = source.readString();
+ notificationRingtoneFileName = source.readString();
+ ringtoneName = source.readString();
+ notificationRingtoneName = source.readString();
+ author = source.readString();
+ copyright = source.readString();
+ isDrmProtected = (source.readInt() != 0);
+ soundPackName = source.readString();
+ themeStyleName = source.readString();
+ preview = source.readString();
+ }
+
+ protected void changeDrmFlagIfNeeded(String resourcePath) {
+ if (resourcePath != null && resourcePath.contains(LOCKED_NAME)) {
+ isDrmProtected = true;
+ }
+ }
+
+ private int objectTypeToInt(InfoObjectType type) {
+ switch (type) {
+ case TYPE_THEME:
+ return 0;
+
+ case TYPE_SOUNDPACK:
+ return 1;
+
+ default:
+ Log.e("BaseThemeInfo", "unknown type " + type.toString());
+ return 0;
+ }
+ }
+
+ private InfoObjectType intToInfoObjectType(int value) {
+ switch (value) {
+ case 0:
+ return InfoObjectType.TYPE_THEME;
+
+ case 1:
+ return InfoObjectType.TYPE_SOUNDPACK;
+
+ default:
+ Log.e("BaseThemeInfo", "unknown value " + value);
+ return InfoObjectType.TYPE_THEME;
+ }
+ }
+
+}
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index fc6538f..1758c63 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -34,6 +34,7 @@ import android.content.pm.PermissionGroupInfo;
import android.content.pm.PermissionInfo;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
+import android.content.pm.ThemeInfo;
import android.net.Uri;
import android.content.IntentSender;
@@ -105,6 +106,8 @@ interface IPackageManager {
List<PackageInfo> getInstalledPackages(int flags);
+ List<PackageInfo> getInstalledThemePackages();
+
List<ApplicationInfo> getInstalledApplications(int flags);
/**
diff --git a/core/java/android/content/pm/PackageInfo.java b/core/java/android/content/pm/PackageInfo.java
index a8ce889..f783b96 100644
--- a/core/java/android/content/pm/PackageInfo.java
+++ b/core/java/android/content/pm/PackageInfo.java
@@ -132,9 +132,72 @@ public class PackageInfo implements Parcelable {
*/
public FeatureInfo[] reqFeatures;
+ // Is Theme Apk
+ public boolean isThemeApk = false;
+
+ // ThemeInfo
+ /**
+ * {@hide}
+ */
+ public ThemeInfo [] themeInfos;
+
+ // SoundsInfo
+ /**
+ * {@hide}
+ */
+ public SoundsInfo [] soundInfos;
+
public PackageInfo() {
}
+ /*
+ * Is Theme Apk is DRM protected (contains DRM-protected resources)
+ *
+ */
+ private boolean drmProtectedThemeApk = false;
+
+ /**
+ * @hide
+ *
+ * @return Is Theme Apk is DRM protected (contains DRM-protected resources)
+ */
+ public boolean isDrmProtectedThemeApk() {
+ return drmProtectedThemeApk;
+ }
+
+ /**
+ * @hide
+ *
+ * @param value if Theme Apk is DRM protected (contains DRM-protected resources)
+ */
+ public void setDrmProtectedThemeApk(boolean value) {
+ drmProtectedThemeApk = value;
+ }
+
+ /*
+ * If isThemeApk and isDrmProtectedThemeApk are true - path to hidden locked zip file
+ *
+ */
+ private String lockedZipFilePath;
+
+ /**
+ * @hide
+ *
+ * @return path for hidden locked zip file
+ */
+ public String getLockedZipFilePath() {
+ return lockedZipFilePath;
+ }
+
+ /**
+ * @hide
+ *
+ * @param value path for hidden locked zip file
+ */
+ public void setLockedZipFilePath(String value) {
+ lockedZipFilePath = value;
+ }
+
public String toString() {
return "PackageInfo{"
+ Integer.toHexString(System.identityHashCode(this))
@@ -168,6 +231,13 @@ public class PackageInfo implements Parcelable {
dest.writeTypedArray(signatures, parcelableFlags);
dest.writeTypedArray(configPreferences, parcelableFlags);
dest.writeTypedArray(reqFeatures, parcelableFlags);
+
+ /* Theme-specific. */
+ dest.writeInt((isThemeApk)? 1 : 0);
+ dest.writeInt((drmProtectedThemeApk)? 1 : 0);
+ dest.writeTypedArray(themeInfos, parcelableFlags);
+ dest.writeTypedArray(soundInfos, parcelableFlags);
+ dest.writeString(lockedZipFilePath);
}
public static final Parcelable.Creator<PackageInfo> CREATOR
@@ -202,5 +272,12 @@ public class PackageInfo implements Parcelable {
signatures = source.createTypedArray(Signature.CREATOR);
configPreferences = source.createTypedArray(ConfigurationInfo.CREATOR);
reqFeatures = source.createTypedArray(FeatureInfo.CREATOR);
+
+ /* Theme-specific. */
+ isThemeApk = (source.readInt() != 0);
+ drmProtectedThemeApk = (source.readInt() != 0);
+ themeInfos = source.createTypedArray(ThemeInfo.CREATOR);
+ soundInfos = source.createTypedArray(SoundsInfo.CREATOR);
+ lockedZipFilePath = source.readString();
}
}
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index cd48dcb..c69646e 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -793,6 +793,16 @@ public abstract class PackageManager {
public abstract List<PackageInfo> getInstalledPackages(int flags);
/**
+ * Return a List of all theme packages that are installed
+ * on the device.
+ *
+ * @return A List of PackageInfo objects, one for each theme package
+ * that is installed on the device.
+ *
+ */
+ public abstract List<PackageInfo> getInstalledThemePackages();
+
+ /**
* Check whether a particular package has been granted a particular
* permission.
*
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index b798bde..45daea9 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -158,6 +158,17 @@ public class PackageParser {
return name.endsWith(".apk");
}
+ public static String getLockedZipFilePath(String path) {
+ if (path == null) {
+ return null;
+ }
+ if (isPackageFilename(path)) {
+ return path.substring(0, path.length() - 4) + ".locked.zip";
+ } else {
+ return path + ".locked.zip";
+ }
+ }
+
/**
* Generate and return the {@link PackageInfo} for a parsed package.
*
@@ -173,6 +184,32 @@ public class PackageParser {
pi.versionName = p.mVersionName;
pi.sharedUserId = p.mSharedUserId;
pi.sharedUserLabel = p.mSharedUserLabel;
+ pi.isThemeApk = p.mIsThemeApk;
+ pi.setDrmProtectedThemeApk(false);
+ if (pi.isThemeApk) {
+ int N = p.mThemeInfos.size();
+ if (N > 0) {
+ pi.themeInfos = new ThemeInfo[N];
+ for (int i = 0; i < N; i++) {
+ pi.themeInfos[i] = p.mThemeInfos.get(i);
+ pi.setDrmProtectedThemeApk(pi.isDrmProtectedThemeApk() || pi.themeInfos[i].isDrmProtected);
+ }
+ if (pi.isDrmProtectedThemeApk()) {
+ pi.setLockedZipFilePath(PackageParser.getLockedZipFilePath(p.mPath));
+ }
+ }
+ N = p.mSoundInfos.size();
+ if (N > 0) {
+ pi.soundInfos = new SoundsInfo[N];
+ for (int i = 0; i < N; i++) {
+ pi.soundInfos[i] = p.mSoundInfos.get(i);
+ pi.setDrmProtectedThemeApk(pi.isDrmProtectedThemeApk() || pi.soundInfos[i].isDrmProtected);
+ }
+ if (pi.isDrmProtectedThemeApk()) {
+ pi.setLockedZipFilePath(PackageParser.getLockedZipFilePath(p.mPath));
+ }
+ }
+ }
pi.applicationInfo = p.applicationInfo;
if ((flags&PackageManager.GET_GIDS) != 0) {
pi.gids = gids;
@@ -960,7 +997,14 @@ public class PackageParser {
// Just skip this tag
XmlUtils.skipCurrentTag(parser);
continue;
-
+ } else if (tagName.equals("theme")) {
+ // this is a theme apk.
+ pkg.mIsThemeApk = true;
+ pkg.mThemeInfos.add(new ThemeInfo(parser, res, attrs));
+ } else if (tagName.equals("sounds")) {
+ // this is a theme apk.
+ pkg.mIsThemeApk = true;
+ pkg.mSoundInfos.add(new SoundsInfo(parser, res, attrs));
} else if (RIGID_PARSER) {
outError[0] = "Bad element under <manifest>: "
+ parser.getName();
@@ -1303,12 +1347,26 @@ public class PackageParser {
return a;
}
+ private void setIsThemeable(XmlPullParser parser, AttributeSet attrs, ApplicationInfo ai) {
+ for (int i = 0; i < attrs.getAttributeCount(); i++) {
+ if (!ApplicationInfo.isPlutoNamespace(parser.getAttributeNamespace(i))) {
+ continue;
+ }
+ if (attrs.getAttributeName(i).equalsIgnoreCase(ApplicationInfo.PLUTO_ISTHEMEABLE_ATTRIBUTE_NAME)) {
+ ai.isThemeable = attrs.getAttributeBooleanValue(i, false);
+ return;
+ }
+ }
+ }
+
private boolean parseApplication(Package owner, Resources res,
XmlPullParser parser, AttributeSet attrs, int flags, String[] outError)
throws XmlPullParserException, IOException {
final ApplicationInfo ai = owner.applicationInfo;
final String pkgName = owner.applicationInfo.packageName;
+ setIsThemeable(parser, attrs, ai);
+
TypedArray sa = res.obtainAttributes(attrs,
com.android.internal.R.styleable.AndroidManifestApplication);
@@ -1581,6 +1639,18 @@ public class PackageParser {
return true;
}
+ private void setIsThemeableForActivity(XmlPullParser parser, AttributeSet attrs, ActivityInfo ai) {
+ for (int i = 0; i < attrs.getAttributeCount(); i++) {
+ if (!ApplicationInfo.isPlutoNamespace(parser.getAttributeNamespace(i))) {
+ continue;
+ }
+ if (attrs.getAttributeName(i).equalsIgnoreCase(ApplicationInfo.PLUTO_ISTHEMEABLE_ATTRIBUTE_NAME)) {
+ ai.setIsThemeable(attrs.getAttributeBooleanValue(i, false));
+ return;
+ }
+ }
+ }
+
private Activity parseActivity(Package owner, Resources res,
XmlPullParser parser, AttributeSet attrs, int flags, String[] outError,
boolean receiver) throws XmlPullParserException, IOException {
@@ -1602,6 +1672,8 @@ public class PackageParser {
mParseActivityArgs.flags = flags;
Activity a = new Activity(mParseActivityArgs, new ActivityInfo());
+ setIsThemeableForActivity(parser, attrs, a.info);
+
if (outError[0] != null) {
sa.recycle();
return null;
@@ -2546,6 +2618,15 @@ public class PackageParser {
// For use by package manager to keep track of where it has done dexopt.
public boolean mDidDexOpt;
+ // Is Theme Apk
+ public boolean mIsThemeApk = false;
+
+ // Theme info
+ public final ArrayList<ThemeInfo> mThemeInfos = new ArrayList<ThemeInfo>(0);
+
+ // Sound info
+ public final ArrayList<SoundsInfo> mSoundInfos = new ArrayList<SoundsInfo>(0);
+
// Additional data supplied by callers.
public Object mExtras;
diff --git a/core/java/android/content/pm/SoundsInfo.java b/core/java/android/content/pm/SoundsInfo.java
new file mode 100644
index 0000000..c42c5e7
--- /dev/null
+++ b/core/java/android/content/pm/SoundsInfo.java
@@ -0,0 +1,170 @@
+package android.content.pm;
+
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlPullParser;
+
+import android.os.Parcelable;
+import android.os.Parcel;
+import android.util.AttributeSet;
+import android.content.res.Resources;
+
+import java.util.Map;
+import java.util.HashMap;
+
+/**
+ * Overall information about sound pack. This corresponds
+ * to the information collected from AndroidManifest.xml (sounds tag).
+ *
+ * Below is an example of sounds tag
+ * <sounds
+ * pluto:name="Pluto Default"
+ * pluto:thumbnail="@drawable/app_thumbnail"
+ * pluto:author="John Doe"
+ * pluto:ringtoneFileName="media/audio/ringtone.mp3"
+ * pluto:notificationRingtoneFileName="media/audio/locked/notification.mp3"
+ * pluto:copyright="T-Mobile, 2009"
+ * />
+ *
+ */
+public class SoundsInfo extends BaseThemeInfo {
+
+ private static final String [] attributes = new String [] {
+ "name",
+ "thumbnail",
+ "author",
+ "ringtoneFileName",
+ "notificationRingtoneFileName",
+ "ringtoneName",
+ "notificationRingtoneName",
+ "copyright",
+ };
+
+ private static Map<String, Integer> attributesLookupTable;
+
+ static {
+ attributesLookupTable = new HashMap<String, Integer>();
+ for (int i = 0; i < attributes.length; i++) {
+ attributesLookupTable.put(attributes[i], i);
+ }
+ }
+
+ /**
+ * {@link #name}
+ *
+ */
+ private static final int NAME_INDEX = 0;
+
+ /**
+ * {@link #thumbnail}
+ *
+ */
+ private static final int THUMBNAIL_INDEX = 1;
+
+ /**
+ * {@link #author}
+ *
+ */
+ private static final int AUTHOR_INDEX = 2;
+
+ /**
+ * {@link #ringtoneName}
+ *
+ */
+ private static final int RINGTONE_FILE_NAME_INDEX = 3;
+
+ /**
+ * {@link #notificationRingtoneName}
+ *
+ */
+ private static final int NOTIFICATION_RINGTONE_FILE_NAME_INDEX = 4;
+
+ /**
+ * {@link #ringtoneName}
+ *
+ */
+ private static final int RINGTONE_NAME_INDEX = 5;
+
+ /**
+ * {@link #notificationRingtoneName}
+ *
+ */
+ private static final int NOTIFICATION_RINGTONE_NAME_INDEX = 6;
+
+ /**
+ * {@link #copyright}
+ *
+ */
+ private static final int COPYRIGHT_INDEX = 7;
+
+
+ public SoundsInfo(XmlPullParser parser, Resources res, AttributeSet attrs) throws XmlPullParserException {
+ super();
+
+ type = InfoObjectType.TYPE_SOUNDPACK;
+ Map<String, Integer> tempMap = new HashMap<String, Integer>(attributesLookupTable);
+ for (int i = 0; i < attrs.getAttributeCount(); i++) {
+ if (!ApplicationInfo.isPlutoNamespace(parser.getAttributeNamespace(i))) {
+ continue;
+ }
+ String key = attrs.getAttributeName(i);
+ if (tempMap.containsKey(key)) {
+ int index = tempMap.get(key);
+ tempMap.remove(key);
+
+ switch (index) {
+ case NAME_INDEX:
+ name = getResolvedString(res, attrs, i);
+ break;
+
+ case THUMBNAIL_INDEX:
+ thumbnail = attrs.getAttributeValue(i);
+ break;
+
+ case AUTHOR_INDEX:
+ author = getResolvedString(res, attrs, i);
+ break;
+
+ case RINGTONE_FILE_NAME_INDEX:
+ ringtoneFileName = attrs.getAttributeValue(i);
+ changeDrmFlagIfNeeded(ringtoneFileName);
+ break;
+
+ case NOTIFICATION_RINGTONE_FILE_NAME_INDEX:
+ notificationRingtoneFileName = attrs.getAttributeValue(i);
+ changeDrmFlagIfNeeded(notificationRingtoneFileName);
+ break;
+
+ case RINGTONE_NAME_INDEX:
+ ringtoneName = attrs.getAttributeValue(i);
+ break;
+
+ case NOTIFICATION_RINGTONE_NAME_INDEX:
+ notificationRingtoneName = attrs.getAttributeValue(i);
+
+ case COPYRIGHT_INDEX:
+ copyright = getResolvedString(res, attrs, i);
+ break;
+ }
+ }
+ }
+ if (!tempMap.isEmpty()) {
+ throw new XmlPullParserException("Not all compulsory attributes are specified in <sounds>");
+ }
+ }
+
+ public static final Parcelable.Creator<SoundsInfo> CREATOR
+ = new Parcelable.Creator<SoundsInfo>() {
+ public SoundsInfo createFromParcel(Parcel source) {
+ return new SoundsInfo(source);
+ }
+
+ public SoundsInfo[] newArray(int size) {
+ return new SoundsInfo[size];
+ }
+ };
+
+ private SoundsInfo(Parcel source) {
+ super(source);
+ }
+
+}
diff --git a/core/java/android/content/pm/ThemeInfo.aidl b/core/java/android/content/pm/ThemeInfo.aidl
new file mode 100755
index 0000000..acbc85e
--- /dev/null
+++ b/core/java/android/content/pm/ThemeInfo.aidl
@@ -0,0 +1,3 @@
+package android.content.pm;
+
+parcelable ThemeInfo;
diff --git a/core/java/android/content/pm/ThemeInfo.java b/core/java/android/content/pm/ThemeInfo.java
new file mode 100644
index 0000000..681fda3
--- /dev/null
+++ b/core/java/android/content/pm/ThemeInfo.java
@@ -0,0 +1,306 @@
+/**
+ *
+ */
+package android.content.pm;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlPullParser;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.AttributeSet;
+import android.content.res.Resources;
+
+/**
+ * Overall information about "theme" package. This corresponds
+ * to the information collected from AndroidManifest.xml (theme tag).
+ *
+ * Below is an example of theme tag
+ * <theme
+ * pluto:name="Pluto Default"
+ * pluto:thumbnail="media/images/app_thumbnail.png"
+ * pluto:preview="media/images/preview.png"
+ * pluto:author="John Doe"
+ * pluto:ringtoneFileName="media/audio/ringtone.mp3"
+ * pluto:notificationRingtoneFileName="media/audio/locked/notification.mp3"
+ * pluto:copyright="T-Mobile, 2009"
+ * pluto:wallpaperImage="media/images/wallpaper.jpg"
+ * pluto:favesBackground="media/images/locked/background.jpg"
+ * pluto:soundpackName="<package_name>/<sound_pack_name>"
+ * />
+ *
+ */
+public final class ThemeInfo extends BaseThemeInfo {
+
+ /**
+ * {@link #name}
+ *
+ */
+ private static final int THEME_PACKAGE_INDEX = 0;
+
+ /**
+ * {@link #thumbnail}
+ *
+ */
+ private static final int THUMBNAIL_INDEX = 1;
+
+ /**
+ * {@link #preview}
+ *
+ */
+ private static final int PREVIEW_INDEX = 2;
+
+ /**
+ * {@link #author}
+ *
+ */
+ private static final int AUTHOR_INDEX = 3;
+
+ /**
+ * {@link #themeId}
+ *
+ */
+ private static final int THEME_INDEX = 4;
+
+ /**
+ * {@link #themeStyleName}
+ *
+ */
+ private static final int THEME_STYLE_NAME_INDEX = 5;
+
+ /**
+ * {@link #ringtoneName}
+ *
+ */
+ private static final int RINGTONE_FILE_NAME_INDEX = 6;
+
+ /**
+ * {@link #notificationRingtoneName}
+ *
+ */
+ private static final int NOTIFICATION_RINGTONE_FILE_NAME_INDEX = 7;
+
+ /**
+ * {@link #favesImageName}
+ *
+ */
+ private static final int FAVES_IMAGE_NAME_INDEX = 8;
+
+ /**
+ * {@link #favesAppImageName}
+ *
+ */
+ private static final int FAVES_APP_IMAGE_NAME_INDEX = 9;
+
+ /**
+ * {@link #wallpaperImageName}
+ *
+ */
+ private static final int WALLPAPER_IMAGE_NAME_INDEX = 10;
+
+ /**
+ * {@link #copyright}
+ *
+ */
+ private static final int COPYRIGHT_INDEX = 11;
+
+ /**
+ * {@link #ringtoneName}
+ *
+ */
+ private static final int RINGTONE_NAME_INDEX = 12;
+
+ /**
+ * {@link #notificationRingtoneName}
+ *
+ */
+ private static final int NOTIFICATION_RINGTONE_NAME_INDEX = 13;
+
+ /**
+ * {@link #soundPackName}
+ *
+ */
+ private static final int SOUNDPACK_NAME_INDEX = 14;
+
+ /**
+ * {@link #styleResourceId}
+ *
+ */
+ private static final int STYLE_INDEX = 15;
+
+
+ private static final String [] compulsoryAttributes = new String [] {
+ "name",
+ "thumbnail",
+ "preview",
+ "author",
+ "themeId",
+ "styleName",
+ };
+
+ private static final String [] optionalAttributes = new String [] {
+ "ringtoneFileName",
+ "notificationRingtoneFileName",
+ "favesBackground",
+ "favesAppsBackground",
+ "wallpaperImage",
+ "copyright",
+ "ringtoneName",
+ "notificationRingtoneName",
+ "soundpackName",
+ "styleId",
+ };
+
+ private static Map<String, Integer> attributesLookupTable;
+
+ static {
+ attributesLookupTable = new HashMap<String, Integer>();
+ for (int i = 0; i < compulsoryAttributes.length; i++) {
+ attributesLookupTable.put(compulsoryAttributes[i], i);
+ }
+
+ for (int i = 0; i < optionalAttributes.length; i++) {
+ attributesLookupTable.put(optionalAttributes[i], compulsoryAttributes.length + i);
+ }
+ }
+
+ public ThemeInfo(XmlPullParser parser, Resources res, AttributeSet attrs) throws XmlPullParserException {
+ super();
+
+ type = InfoObjectType.TYPE_THEME;
+ Map<String, Integer> tempMap = new HashMap<String, Integer>(attributesLookupTable);
+ int numberOfCompulsoryAttributes = 0;
+ for (int i = 0; i < attrs.getAttributeCount(); i++) {
+ if (!ApplicationInfo.isPlutoNamespace(parser.getAttributeNamespace(i))) {
+ continue;
+ }
+ String key = attrs.getAttributeName(i);
+ if (tempMap.containsKey(key)) {
+ int index = tempMap.get(key);
+ tempMap.remove(key);
+
+ if (index < compulsoryAttributes.length) {
+ numberOfCompulsoryAttributes++;
+ }
+ switch (index) {
+ case THEME_PACKAGE_INDEX:
+ // theme name
+ name = getResolvedString(res, attrs, i);
+ break;
+
+ case THUMBNAIL_INDEX:
+ // theme thumbprint
+ thumbnail = attrs.getAttributeValue(i);
+ break;
+
+ case AUTHOR_INDEX:
+ // theme author
+ author = getResolvedString(res, attrs, i);
+ break;
+
+ case THEME_INDEX:
+ // androidUiStyle attribute
+ themeId = attrs.getAttributeValue(i);
+ break;
+
+ case THEME_STYLE_NAME_INDEX:
+ themeStyleName = getResolvedString(res, attrs, i);
+ break;
+
+ case RINGTONE_FILE_NAME_INDEX:
+ // ringtone
+ ringtoneFileName = attrs.getAttributeValue(i);
+ changeDrmFlagIfNeeded(ringtoneFileName);
+ break;
+
+ case NOTIFICATION_RINGTONE_FILE_NAME_INDEX:
+ // notification ringtone
+ notificationRingtoneFileName = attrs.getAttributeValue(i);
+ changeDrmFlagIfNeeded(notificationRingtoneFileName);
+ break;
+
+ case FAVES_IMAGE_NAME_INDEX:
+ // faves background
+ favesImageName = attrs.getAttributeValue(i);
+ changeDrmFlagIfNeeded(favesImageName);
+ break;
+
+ case FAVES_APP_IMAGE_NAME_INDEX:
+ // favesAppBackground attribute
+ favesAppImageName = attrs.getAttributeValue(i);
+ changeDrmFlagIfNeeded(favesAppImageName);
+ break;
+
+ case WALLPAPER_IMAGE_NAME_INDEX:
+ // wallpaperImage attribute
+ wallpaperImageName = attrs.getAttributeValue(i);
+ changeDrmFlagIfNeeded(wallpaperImageName);
+ break;
+
+ case COPYRIGHT_INDEX:
+ // themeCopyright attribute
+ copyright = getResolvedString(res, attrs, i);
+ break;
+
+ case RINGTONE_NAME_INDEX:
+ // ringtone UI name
+ ringtoneName = attrs.getAttributeValue(i);
+ break;
+
+ case NOTIFICATION_RINGTONE_NAME_INDEX:
+ // notification ringtone UI name
+ notificationRingtoneName = attrs.getAttributeValue(i);
+ break;
+
+ case SOUNDPACK_NAME_INDEX:
+ soundPackName = attrs.getAttributeValue(i);
+ break;
+
+ case STYLE_INDEX:
+ styleResourceId = attrs.getAttributeResourceValue(i, -1);
+ break;
+
+ case PREVIEW_INDEX:
+ // theme thumbprint
+ preview = attrs.getAttributeValue(i);
+ break;
+ }
+ }
+ }
+ if (numberOfCompulsoryAttributes < compulsoryAttributes.length) {
+ throw new XmlPullParserException("Not all compulsory attributes are specified in <theme>");
+ }
+ }
+
+ /*
+ * Flatten this object in to a Parcel.
+ *
+ * @param dest The Parcel in which the object should be written.
+ * @param flags Additional flags about how the object should be written.
+ * May be 0 or {@link #PARCELABLE_WRITE_RETURN_VALUE}.
+ *
+ * @see android.os.Parcelable#writeToParcel(android.os.Parcel, int)
+ */
+ public void writeToParcel(Parcel dest, int flags) {
+ super.writeToParcel(dest, flags);
+ }
+
+ public static final Parcelable.Creator<ThemeInfo> CREATOR
+ = new Parcelable.Creator<ThemeInfo>() {
+ public ThemeInfo createFromParcel(Parcel source) {
+ return new ThemeInfo(source);
+ }
+
+ public ThemeInfo[] newArray(int size) {
+ return new ThemeInfo[size];
+ }
+ };
+
+ private ThemeInfo(Parcel source) {
+ super(source);
+ }
+
+}
diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java
index 0d43b2a..a4c8ac5 100644
--- a/core/java/android/content/res/AssetManager.java
+++ b/core/java/android/content/res/AssetManager.java
@@ -74,6 +74,9 @@ public final class AssetManager {
private String mAssetDir;
private String mAppName;
+ private boolean mThemeSupport;
+ private String mThemePackageName;
+
/**
* Create a new AssetManager containing only the basic system assets.
* Applications will not generally use this method, instead retrieving the
@@ -237,6 +240,12 @@ public final class AssetManager {
}
}
+ /*package*/ final void recreateStringBlocks() {
+ synchronized (mSync) {
+ makeStringBlocks(true);
+ }
+ }
+
private final void makeStringBlocks(boolean copyFromSystem) {
final int sysNum = copyFromSystem ? mSystem.mStringBlocks.length : 0;
final int num = getStringBlockCount();
@@ -443,6 +452,18 @@ public final class AssetManager {
/**
* {@hide}
+ * Split a theme package with DRM-protected resources into two files.
+ *
+ * @param packageFileName Original theme package file name.
+ * @param lockedFileName Name of the new "locked" file with DRM resources.
+ * @param drmProtectedresources Array of names of DRM-protected assets.
+ */
+ public final int splitDrmProtectedThemePackage(String packageFileName, String lockedFileName, String [] drmProtectedresources) {
+ return splitThemePackage(packageFileName, lockedFileName, drmProtectedresources);
+ }
+
+ /**
+ * {@hide}
* Retrieve a non-asset as a compiled XML file. Not for use by
* applications.
*
@@ -573,6 +594,68 @@ public final class AssetManager {
public native final int addAssetPath(String path);
/**
+ * Delete a set of assets from the asset manager. This can be
+ * either a directory or ZIP file. Not for use by applications. Returns
+ * true if succeeded or false on failure.
+ * {@hide}
+ */
+ public native final boolean removeAssetPath(String packageName, String path);
+
+ /**
+ * Add an additional set of assets to the asset manager. This can be
+ * either a directory or ZIP file. Force updating of ResTable object.
+ * Not for use by applications.
+ * Returnsthe cookie of the added asset, or 0 on failure.
+ * {@hide}
+ */
+ public native final int updateResourcesWithAssetPath(String path);
+
+ /**
+ * Delete a set of assets from the asset manager. This can be
+ * either a directory or ZIP file. Not for use by applications. Returns
+ * true if succeeded or false on failure.
+ * {@hide}
+ */
+ public native final void dumpResources();
+
+ /**
+ * Sets a flag indicating that this AssetManager should have themes
+ * attached, according to the initial request to create it by the
+ * ApplicationContext.
+ *
+ * {@hide}
+ */
+ public final void setThemeSupport(boolean themeSupport) {
+ mThemeSupport = themeSupport;
+ }
+
+ /**
+ * Should this AssetManager have themes attached, according to the initial
+ * request to create it by the ApplicationContext?
+ *
+ * {@hide}
+ */
+ public final boolean hasThemeSupport() {
+ return mThemeSupport;
+ }
+
+ /**
+ * Get package name of current theme (may return null).
+ * {@hide}
+ */
+ public final String getThemePackageName() {
+ return mThemePackageName;
+ }
+
+ /**
+ * Sets package name for current theme (null is allowed).
+ * {@hide}
+ */
+ public final void setThemePackageName(String packageName) {
+ mThemePackageName = packageName;
+ }
+
+ /**
* Determine whether the state in this asset manager is up-to-date with
* the files on the filesystem. If false is returned, you need to
* instantiate a new AssetManager class to see the new data.
@@ -676,6 +759,7 @@ public final class AssetManager {
private native final int newTheme();
private native final void deleteTheme(int theme);
/*package*/ native static final void applyThemeStyle(int theme, int styleRes, boolean force);
+ /*package*/ native static final void setAttributeValue(int theme, int attr, int color);
/*package*/ native static final void copyTheme(int dest, int source);
/*package*/ native static final int loadThemeAttributeValue(int theme, int ident,
TypedValue outValue,
@@ -688,6 +772,8 @@ public final class AssetManager {
private native final int[] getArrayStringInfo(int arrayRes);
/*package*/ native final int[] getArrayIntResource(int arrayRes);
+ private native final int splitThemePackage(String srcFileName, String dstFileName, String [] drmProtectedAssetNames);
+
private native final void init();
private native final void destroy();
diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java
index 1fe34b5..d8f44af 100644
--- a/core/java/android/content/res/Configuration.java
+++ b/core/java/android/content/res/Configuration.java
@@ -3,6 +3,8 @@ package android.content.res;
import android.content.pm.ActivityInfo;
import android.os.Parcel;
import android.os.Parcelable;
+import android.os.SystemProperties;
+import android.text.TextUtils;
import java.util.Locale;
@@ -35,6 +37,11 @@ public final class Configuration implements Parcelable, Comparable<Configuration
public Locale locale;
/**
+ * @hide
+ */
+ public CustomTheme customTheme;
+
+ /**
* Locale should persist on setting. This is hidden because it is really
* questionable whether this is the right way to expose the functionality.
* @hide
@@ -154,7 +161,22 @@ public final class Configuration implements Parcelable, Comparable<Configuration
public static final int ORIENTATION_PORTRAIT = 1;
public static final int ORIENTATION_LANDSCAPE = 2;
public static final int ORIENTATION_SQUARE = 3;
-
+
+ /**
+ * @hide
+ */
+ public static final int THEME_UNDEFINED = 0;
+
+ /**
+ * @hide
+ */
+ public static final String THEME_ID_PERSISTENCE_PROPERTY = "persist.sys.themeId";
+
+ /**
+ * @hide
+ */
+ public static final String THEME_PACKAGE_NAME_PERSISTENCE_PROPERTY = "persist.sys.themePackageName";
+
/**
* Overall orientation of the screen. May be one of
* {@link #ORIENTATION_LANDSCAPE}, {@link #ORIENTATION_PORTRAIT},
@@ -189,6 +211,11 @@ public final class Configuration implements Parcelable, Comparable<Configuration
navigationHidden = o.navigationHidden;
orientation = o.orientation;
screenLayout = o.screenLayout;
+ if (o.customTheme != null) {
+ customTheme = (CustomTheme) o.customTheme.clone();
+ } else {
+ customTheme = CustomTheme.getDefault();
+ }
}
public String toString() {
@@ -217,6 +244,8 @@ public final class Configuration implements Parcelable, Comparable<Configuration
sb.append(orientation);
sb.append(" layout=");
sb.append(screenLayout);
+ sb.append(" themeResource=");
+ sb.append(customTheme);
sb.append('}');
return sb.toString();
}
@@ -237,6 +266,14 @@ public final class Configuration implements Parcelable, Comparable<Configuration
navigationHidden = NAVIGATIONHIDDEN_UNDEFINED;
orientation = ORIENTATION_UNDEFINED;
screenLayout = SCREENLAYOUT_SIZE_UNDEFINED;
+
+ String themeResource = SystemProperties.get(THEME_ID_PERSISTENCE_PROPERTY, null);
+ String themePackageName = SystemProperties.get(THEME_PACKAGE_NAME_PERSISTENCE_PROPERTY, "");
+ if (!TextUtils.isEmpty(themeResource) && !TextUtils.isEmpty(themePackageName)) {
+ customTheme = new CustomTheme(themeResource, themePackageName);
+ } else {
+ customTheme = CustomTheme.getDefault();
+ }
}
/** {@hide} */
@@ -317,7 +354,14 @@ public final class Configuration implements Parcelable, Comparable<Configuration
changed |= ActivityInfo.CONFIG_SCREEN_LAYOUT;
screenLayout = delta.screenLayout;
}
-
+ if (delta.customTheme != null
+ && (customTheme == null || !customTheme.equals(delta.customTheme))) {
+ changed |= ActivityInfo.CONFIG_THEME_RESOURCE;
+ customTheme = (CustomTheme) delta.customTheme.clone();
+ } else if (delta.customTheme == null && customTheme != null) {
+ changed |= ActivityInfo.CONFIG_THEME_RESOURCE;
+ customTheme = CustomTheme.getDefault();
+ }
return changed;
}
@@ -393,6 +437,12 @@ public final class Configuration implements Parcelable, Comparable<Configuration
&& screenLayout != delta.screenLayout) {
changed |= ActivityInfo.CONFIG_SCREEN_LAYOUT;
}
+ if (delta.customTheme != null
+ && (customTheme == null || !customTheme.equals(delta.customTheme))) {
+ changed |= ActivityInfo.CONFIG_THEME_RESOURCE;
+ } else if (delta.customTheme == null && customTheme != null) {
+ changed |= ActivityInfo.CONFIG_THEME_RESOURCE;
+ }
return changed;
}
@@ -444,6 +494,14 @@ public final class Configuration implements Parcelable, Comparable<Configuration
dest.writeInt(navigationHidden);
dest.writeInt(orientation);
dest.writeInt(screenLayout);
+
+ if (customTheme == null) {
+ dest.writeInt(0);
+ } else {
+ dest.writeInt(1);
+ dest.writeString(customTheme.getThemeId());
+ dest.writeString(customTheme.getThemePackageName());
+ }
}
public static final Parcelable.Creator<Configuration> CREATOR
@@ -477,6 +535,12 @@ public final class Configuration implements Parcelable, Comparable<Configuration
navigationHidden = source.readInt();
orientation = source.readInt();
screenLayout = source.readInt();
+
+ if (source.readInt() != 0) {
+ String themeId = source.readString();
+ String themePackage = source.readString();
+ customTheme = new CustomTheme(themeId, themePackage);
+ }
}
public int compareTo(Configuration that) {
@@ -511,6 +575,10 @@ public final class Configuration implements Parcelable, Comparable<Configuration
if (n != 0) return n;
n = this.screenLayout - that.screenLayout;
//if (n != 0) return n;
+ n = this.customTheme.getThemeId().compareTo(that.customTheme.getThemeId());
+ if (n != 0) return n;
+ n = this.customTheme.getThemePackageName().compareTo(that.customTheme.getThemePackageName());
+
return n;
}
@@ -533,6 +601,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration
+ this.locale.hashCode() + this.touchscreen
+ this.keyboard + this.keyboardHidden + this.hardKeyboardHidden
+ this.navigation + this.navigationHidden
- + this.orientation + this.screenLayout;
+ + this.orientation + this.screenLayout
+ + this.customTheme.hashCode();
}
}
diff --git a/core/java/android/content/res/CustomTheme.java b/core/java/android/content/res/CustomTheme.java
new file mode 100644
index 0000000..6adc57b
--- /dev/null
+++ b/core/java/android/content/res/CustomTheme.java
@@ -0,0 +1,114 @@
+package android.content.res;
+
+import android.os.*;
+import android.content.Context;
+import android.content.pm.*;
+import android.util.Log;
+import android.util.DisplayMetrics;
+import android.R;
+import android.app.ActivityManager;
+import android.view.WindowManager;
+import android.text.TextUtils;
+
+/**
+ * @hide
+ */
+public final class CustomTheme implements Cloneable {
+
+ private String mThemeId;
+ private String mThemePackageName;
+
+ private static final CustomTheme sDefaultTheme = new CustomTheme();
+
+ private CustomTheme() {
+ mThemeId = SystemProperties.get("default_theme.style_id");
+ mThemePackageName = SystemProperties.get("default_theme.package_name");
+ }
+
+ public CustomTheme(String themeId, String packageName) {
+ mThemeId = themeId;
+ mThemePackageName = packageName;
+ }
+
+ @Override
+ public Object clone() {
+ try {
+ return super.clone();
+ } catch (CloneNotSupportedException e) {
+ return null;
+ }
+ }
+
+ @Override
+ public boolean equals(Object object) {
+ if (object == this) {
+ return true;
+ }
+ if (object instanceof CustomTheme) {
+ CustomTheme o = (CustomTheme) object;
+ if (!mThemeId.equals(o.mThemeId)) {
+ return false;
+ }
+ String currentPackageName = (mThemePackageName == null)? "" : mThemePackageName;
+ String newPackageName = (o.mThemePackageName == null)? "" : o.mThemePackageName;
+ String currentThemeId = (mThemeId == null)? "" : mThemeId;
+ String newThemeId = (o.mThemeId == null)? "" : o.mThemeId;
+ return (currentPackageName.trim().equalsIgnoreCase(newPackageName.trim())) &&
+ (currentThemeId.trim().equalsIgnoreCase(newThemeId.trim()));
+ }
+ return false;
+ }
+
+ @Override
+ public final String toString() {
+ StringBuilder result = new StringBuilder();
+ result.append(mThemeId);
+ result.append("_");
+ if (mThemePackageName != null && mThemePackageName.length() > 0){
+ result.append(mThemePackageName);
+ }
+
+ return result.toString();
+ }
+
+ @Override
+ public synchronized int hashCode() {
+ return mThemeId.hashCode() + mThemePackageName.hashCode();
+ }
+
+ public String getThemeId() {
+ return mThemeId;
+ }
+
+ public String getThemePackageName() {
+ return mThemePackageName;
+ }
+
+ public void setThemePackageName(String themePackageName) {
+ mThemePackageName = themePackageName;
+ }
+
+ public static CustomTheme getDefault() {
+ return sDefaultTheme;
+ }
+
+ public static int getStyleId(Context context, String packageName, String styleName) {
+ if (TextUtils.isEmpty(packageName) || TextUtils.isEmpty(styleName)) {
+ return R.style.Theme;
+ }
+ try {
+ PackageInfo pi = context.getPackageManager().getPackageInfo(packageName, 0);
+ ThemeInfo[] infos = pi.themeInfos;
+ if (infos != null) {
+ for (ThemeInfo ti : infos) {
+ if (ti.themeId.equals(styleName)) {
+ return ti.styleResourceId;
+ }
+ }
+ }
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.e("CustomTheme", "Unable to get style resource id", e);
+ }
+ return -1;
+ }
+}
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index 1c0ed36..9ebd8e1 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -35,6 +35,7 @@ import android.util.SparseArray;
import android.util.TypedValue;
import android.util.LongSparseArray;
import android.view.Display;
+import android.content.Context;
import java.io.IOException;
import java.io.InputStream;
@@ -106,6 +107,8 @@ public class Resources {
return (LongSparseArray<T>) EMPTY_ARRAY;
}
+ private Context mContext;
+
/**
* This exception is thrown by the resource APIs when a requested resource
* can not be found.
@@ -580,7 +583,7 @@ public class Resources {
return loadDrawable(value, id);
}
}
-
+
/**
* Return a movie object associated with the particular resource ID.
* @param id The desired resource identifier, as generated by the aapt
@@ -921,6 +924,14 @@ public class Resources {
}
throw new NotFoundException("String resource name " + name);
}
+
+ Context getContext() {
+ return mContext;
+ }
+
+ void setContext(Context context) {
+ mContext = context;
+ }
/**
* This class holds the current attribute values for a particular theme.
@@ -959,6 +970,11 @@ public class Resources {
AssetManager.applyThemeStyle(mTheme, resid, force);
}
+ /** @hide */
+ public void setAttributeValue(int attr, int color) {
+ AssetManager.setAttributeValue(mTheme, attr, color);
+ }
+
/**
* Set this theme to hold the same contents as the theme
* <var>other</var>. If both of these themes are from the same
@@ -1123,33 +1139,40 @@ public class Resources {
array.mRsrcs = attrs;
array.mXml = parser;
- if (false) {
+ boolean foo = false;
+ if (foo) {
int[] data = array.mData;
System.out.println("Attributes:");
String s = " Attrs:";
int i;
- for (i=0; i<set.getAttributeCount(); i++) {
- s = s + " " + set.getAttributeName(i);
- int id = set.getAttributeNameResource(i);
- if (id != 0) {
- s = s + "(0x" + Integer.toHexString(id) + ")";
+ if(set != null){
+ for (i=0; i<set.getAttributeCount(); i++) {
+ s = s + " " + set.getAttributeName(i);
+ int id = set.getAttributeNameResource(i);
+ if (id != 0) {
+ s = s + "(0x" + Integer.toHexString(id) + ")";
+ }
+ s = s + "=" + set.getAttributeValue(i);
}
- s = s + "=" + set.getAttributeValue(i);
}
+
System.out.println(s);
- s = " Found:";
- TypedValue value = new TypedValue();
- for (i=0; i<attrs.length; i++) {
- int d = i*AssetManager.STYLE_NUM_ENTRIES;
- value.type = data[d+AssetManager.STYLE_TYPE];
- value.data = data[d+AssetManager.STYLE_DATA];
- value.assetCookie = data[d+AssetManager.STYLE_ASSET_COOKIE];
- value.resourceId = data[d+AssetManager.STYLE_RESOURCE_ID];
- s = s + " 0x" + Integer.toHexString(attrs[i])
- + "=" + value;
+
+ if(true){
+ s = " Found:";
+ TypedValue value = new TypedValue();
+ for (i=0; i<attrs.length; i++) {
+ int d = i*AssetManager.STYLE_NUM_ENTRIES;
+ value.type = data[d+AssetManager.STYLE_TYPE];
+ value.data = data[d+AssetManager.STYLE_DATA];
+ value.assetCookie = data[d+AssetManager.STYLE_ASSET_COOKIE];
+ value.resourceId = data[d+AssetManager.STYLE_RESOURCE_ID];
+ s = s + " 0x" + Integer.toHexString(attrs[i])
+ + "=" + value;
+ }
+ System.out.println(s);
}
- System.out.println(s);
}
return array;
@@ -1246,6 +1269,7 @@ public class Resources {
array.mRsrcs = attrs;
array.mXml = parser;
+
return array;
}
@@ -1644,7 +1668,16 @@ public class Resources {
flushLayoutCache();
}
}
-
+
+ /**
+ * {@hide}
+ */
+ public final void updateStringCache() {
+ synchronized (mTmpValue) {
+ mAssets.recreateStringBlocks();
+ }
+ }
+
/*package*/ Drawable loadDrawable(TypedValue value, int id)
throws NotFoundException {
diff --git a/core/java/android/content/res/TypedArray.java b/core/java/android/content/res/TypedArray.java
index 016ee7f..72fef32 100644
--- a/core/java/android/content/res/TypedArray.java
+++ b/core/java/android/content/res/TypedArray.java
@@ -5,6 +5,9 @@ import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.TypedValue;
+import android.content.Context;
+import android.content.res.Resources.NotFoundException;
+
import com.android.internal.util.XmlUtils;
import java.util.Arrays;
@@ -268,6 +271,9 @@ public class TypedArray {
return csl.getDefaultColor();
}
return defValue;
+ } else if (type == TypedValue.TYPE_ATTRIBUTE && mResources.getContext() != null) {
+ mResources.getContext().getTheme().resolveAttribute(data[index+AssetManager.STYLE_DATA], mValue, true);
+ return mValue.data;
}
throw new UnsupportedOperationException("Can't convert to color: type=0x"
@@ -528,9 +534,9 @@ public class TypedArray {
* gets the resource ID of the selected attribute, and uses
* {@link Resources#getDrawable Resources.getDrawable} of the owning
* Resources object to retrieve its Drawable.
- *
+ *
* @param index Index of attribute to retrieve.
- *
+ *
* @return Drawable for the attribute, or null if not defined.
*/
public Drawable getDrawable(int index) {
@@ -551,6 +557,22 @@ public class TypedArray {
}
/**
+ * Very crude hack to allow {@link #getColor} to succeed in looking up
+ * values from the current theme. This method is necessary as we use
+ * LayerDrawables which use color attribute references.
+ *
+ * @hide
+ */
+ public Drawable getDrawableWithContext(Context context, int id) throws NotFoundException {
+ mResources.setContext(context);
+ try {
+ return getDrawable(id);
+ } finally {
+ mResources.setContext(null);
+ }
+ }
+
+ /**
* Retrieve the CharSequence[] for the attribute at <var>index</var>.
* This gets the resource ID of the selected attribute, and uses
* {@link Resources#getTextArray Resources.getTextArray} of the owning
@@ -675,6 +697,11 @@ public class TypedArray {
return mResources.mAssets.getPooledString(
cookie, data[index+AssetManager.STYLE_DATA]);
}
+
+ /* Hack to allow TypedArrayComposite to instantiate a simple wrapper. */
+ TypedArray() {
+ mResources = null;
+ }
/*package*/ TypedArray(Resources resources, int[] data, int[] indices, int len) {
mResources = resources;
@@ -686,4 +713,25 @@ public class TypedArray {
public String toString() {
return Arrays.toString(mData);
}
-} \ No newline at end of file
+
+ /**
+ * @hide
+ */
+ void dump() {
+ int attrCount = getIndexCount();
+ int[] data = mData;
+ String s = " Found:";
+ TypedValue value = new TypedValue();
+ for (int i=0; i<attrCount; i++) {
+ int attr = getIndex(i);
+ int d = i*AssetManager.STYLE_NUM_ENTRIES;
+ value.type = data[d+AssetManager.STYLE_TYPE];
+ value.data = data[d+AssetManager.STYLE_DATA];
+ value.assetCookie = data[d+AssetManager.STYLE_ASSET_COOKIE];
+ value.resourceId = data[d+AssetManager.STYLE_RESOURCE_ID];
+ s = s + " 0x" + Integer.toHexString(attr)
+ + "=" + value;
+ }
+ System.out.println(s);
+ }
+}
diff --git a/core/java/android/content/res/XmlBlock.java b/core/java/android/content/res/XmlBlock.java
index 6336678..cd7db85 100644
--- a/core/java/android/content/res/XmlBlock.java
+++ b/core/java/android/content/res/XmlBlock.java
@@ -196,6 +196,10 @@ final class XmlBlock {
public int getAttributeCount() {
return mEventType == START_TAG ? nativeGetAttributeCount(mParseState) : -1;
}
+ /** @hide */
+ public int getAttributeDataType(int index) {
+ return nativeGetAttributeDataType(mParseState, index);
+ }
public String getAttributeValue(int index) {
int id = nativeGetAttributeStringValue(mParseState, index);
if (DEBUG) System.out.println("getAttributeValue of " + index + " = " + id);
diff --git a/core/java/android/os/SystemProperties.java b/core/java/android/os/SystemProperties.java
index 4a036ec..9ff014b 100644
--- a/core/java/android/os/SystemProperties.java
+++ b/core/java/android/os/SystemProperties.java
@@ -124,4 +124,49 @@ public class SystemProperties
}
native_set(key, val);
}
-}
+
+ /**
+ * Get the value for the given key.
+ * @return def string if the key isn't found
+ */
+ public static String getLongString(String key, String def) {
+ if (key.length() + 1 > PROP_NAME_MAX) {
+ throw new IllegalArgumentException("key.length > " + PROP_NAME_MAX);
+ }
+ int chunks = getInt(key + '0', 0);
+ if (chunks == 0) {
+ return def;
+ }
+ StringBuffer sb = new StringBuffer();
+ for (int i = 1; i <= chunks; i++) {
+ sb.append(native_get(key + Integer.toString(i)));
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Set the value for the given key.
+ * @throws IllegalArgumentException if the key exceeds 32 characters
+ */
+ public static void setLongString(String key, String val) {
+ if (key.length() + 1 > PROP_NAME_MAX) {
+ throw new IllegalArgumentException("key.length > " + PROP_NAME_MAX);
+ }
+ int chunks = 0;
+ if (val != null && val.length() > 0) {
+ chunks = 1 + val.length() / (PROP_VALUE_MAX + 1);
+ }
+ native_set(key + '0', Integer.toString(chunks));
+ if (chunks > 0) {
+ for (int i = 1, start = 0; i <= chunks; i++) {
+ int end = start + PROP_VALUE_MAX;
+ if (end > val.length()) {
+ end = val.length();
+ }
+ native_set(key + Integer.toString(i), val.substring(start, end));
+ start = end;
+ }
+ }
+ }
+
+} \ No newline at end of file
diff --git a/core/java/android/text/method/CharacterPickerDialog.java b/core/java/android/text/method/CharacterPickerDialog.java
index 880e46d..28564b4 100644
--- a/core/java/android/text/method/CharacterPickerDialog.java
+++ b/core/java/android/text/method/CharacterPickerDialog.java
@@ -60,7 +60,7 @@ public class CharacterPickerDialog extends Dialog
mText = text;
mOptions = options;
mInsert = insert;
- mInflater = LayoutInflater.from(context);
+ mInflater = LayoutInflater.from(getContext());
}
@Override
diff --git a/core/java/android/util/AttributeSet.java b/core/java/android/util/AttributeSet.java
index 82592b9..5dac1af 100644
--- a/core/java/android/util/AttributeSet.java
+++ b/core/java/android/util/AttributeSet.java
@@ -57,6 +57,8 @@ package android.util;
*/
public interface AttributeSet {
public int getAttributeCount();
+ /** @hide */
+ public int getAttributeDataType(int index);
public String getAttributeName(int index);
public String getAttributeValue(int index);
public String getAttributeValue(String namespace, String name);
diff --git a/core/java/android/util/XmlPullAttributes.java b/core/java/android/util/XmlPullAttributes.java
index 12d6dd9..5de7e5f 100644
--- a/core/java/android/util/XmlPullAttributes.java
+++ b/core/java/android/util/XmlPullAttributes.java
@@ -32,6 +32,11 @@ class XmlPullAttributes implements AttributeSet {
public int getAttributeCount() {
return mParser.getAttributeCount();
}
+
+ /** @hide */
+ public int getAttributeDataType(int index) {
+ throw new UnsupportedOperationException();
+ }
public String getAttributeName(int index) {
return mParser.getAttributeName(index);
diff --git a/core/java/android/view/ContextThemeWrapper.java b/core/java/android/view/ContextThemeWrapper.java
index 2045a98..4e1e833 100644
--- a/core/java/android/view/ContextThemeWrapper.java
+++ b/core/java/android/view/ContextThemeWrapper.java
@@ -16,9 +16,16 @@
package android.view;
+import android.app.ActivityManager;
import android.content.Context;
import android.content.ContextWrapper;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.res.AssetManager;
+import android.content.res.Configuration;
import android.content.res.Resources;
+import android.text.TextUtils;
+import android.util.DisplayMetrics;
/**
* A ContextWrapper that allows you to modify the theme from what is in the
@@ -29,6 +36,11 @@ public class ContextThemeWrapper extends ContextWrapper {
private int mThemeResource;
private Resources.Theme mTheme;
private LayoutInflater mInflater;
+
+ /* XXX: Hack to allow themes to be applied on a per-activity basis. Used
+ * by ThemeManager for real-time theme preview. */
+ private boolean mUseThemedResources = false;
+ private Resources mThemedResources = null;
public ContextThemeWrapper() {
super(null);
@@ -44,26 +56,82 @@ public class ContextThemeWrapper extends ContextWrapper {
super.attachBaseContext(newBase);
mBase = newBase;
}
+
+ @Override
+ public AssetManager getAssets() {
+ return getResources().getAssets();
+ }
+
+ @Override
+ public Resources getResources() {
+ if (mUseThemedResources == true) {
+ return mThemedResources;
+ } else {
+ return mBase.getResources();
+ }
+ }
+
+ private String getPackageResDir(String packageName) {
+ PackageInfo pi;
+ try {
+ pi = getPackageManager().getPackageInfo(packageName, 0);
+ if (pi == null || pi.applicationInfo == null)
+ return null;
+ return pi.applicationInfo.publicSourceDir;
+ } catch (NameNotFoundException e) {
+ return null;
+ }
+ }
+
+ /**
+ * {@hide}
+ * XXX: Hack to support theme preview by temporarily overriding the ApplicationContext's
+ * Resources on a per-activity basis. Very ugly.
+ */
+ public void useThemedResources(String themePackage) {
+ if (TextUtils.isEmpty(themePackage)) {
+ mThemedResources = null;
+ mUseThemedResources = false;
+ mTheme = null;
+ } else {
+ AssetManager assets = new AssetManager();
+ assets.addAssetPath(getPackageResDir(getPackageName()));
+ assets.addAssetPath(getPackageResDir(themePackage));
+ assets.setThemeSupport(true);
+ assets.setThemePackageName(themePackage);
+
+ DisplayMetrics metrics = new DisplayMetrics();
+ WindowManager wm = (WindowManager)getSystemService(WINDOW_SERVICE);
+ wm.getDefaultDisplay().getMetrics(metrics);
+
+ ActivityManager am = (ActivityManager)getSystemService(ACTIVITY_SERVICE);
+ Configuration config = am.getConfiguration();
+ mThemedResources = new Resources(assets, metrics, config);
+ mUseThemedResources = true;
+ mTheme = null;
+ }
+ }
@Override public void setTheme(int resid) {
mThemeResource = resid;
initializeTheme();
}
-
+
@Override public Resources.Theme getTheme() {
if (mTheme != null) {
return mTheme;
}
if (mThemeResource == 0) {
- mThemeResource = com.android.internal.R.style.Theme;
+ return mBase.getTheme();
+ } else {
+ initializeTheme();
+ return mTheme;
}
- initializeTheme();
-
- return mTheme;
}
- @Override public Object getSystemService(String name) {
+ @Override
+ public Object getSystemService(String name) {
if (LAYOUT_INFLATER_SERVICE.equals(name)) {
if (mInflater == null) {
mInflater = LayoutInflater.from(mBase).cloneInContext(this);
@@ -89,7 +157,7 @@ public class ContextThemeWrapper extends ContextWrapper {
}
private void initializeTheme() {
- final boolean first = mTheme == null;
+ final boolean first = (mTheme == null);
if (first) {
mTheme = getResources().newTheme();
Resources.Theme theme = mBase.getTheme();
@@ -97,7 +165,7 @@ public class ContextThemeWrapper extends ContextWrapper {
mTheme.setTo(theme);
}
}
+
onApplyThemeResource(mTheme, mThemeResource, first);
}
}
-
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 0b87536..b82cdac 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -1847,7 +1847,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
int attr = a.getIndex(i);
switch (attr) {
case com.android.internal.R.styleable.View_background:
- background = a.getDrawable(attr);
+ background = a.getDrawableWithContext(context, attr);
break;
case com.android.internal.R.styleable.View_padding:
padding = a.getDimensionPixelSize(attr, -1);
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 271989a..7b6a463 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -511,7 +511,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
TypedArray a = context.obtainStyledAttributes(attrs,
com.android.internal.R.styleable.AbsListView, defStyle, 0);
- Drawable d = a.getDrawable(com.android.internal.R.styleable.AbsListView_listSelector);
+ Drawable d = a.getDrawableWithContext(context, com.android.internal.R.styleable.AbsListView_listSelector);
if (d != null) {
setSelector(d);
}
diff --git a/core/java/android/widget/CheckedTextView.java b/core/java/android/widget/CheckedTextView.java
index fd590ed..0dd67a2 100644
--- a/core/java/android/widget/CheckedTextView.java
+++ b/core/java/android/widget/CheckedTextView.java
@@ -59,7 +59,7 @@ public class CheckedTextView extends TextView implements Checkable {
TypedArray a = context.obtainStyledAttributes(attrs,
R.styleable.CheckedTextView, defStyle, 0);
- Drawable d = a.getDrawable(R.styleable.CheckedTextView_checkMark);
+ Drawable d = a.getDrawableWithContext(context, R.styleable.CheckedTextView_checkMark);
if (d != null) {
setCheckMarkDrawable(d);
}
diff --git a/core/java/android/widget/CompoundButton.java b/core/java/android/widget/CompoundButton.java
index 98b0976..d24ee5b 100644
--- a/core/java/android/widget/CompoundButton.java
+++ b/core/java/android/widget/CompoundButton.java
@@ -69,7 +69,7 @@ public abstract class CompoundButton extends Button implements Checkable {
context.obtainStyledAttributes(
attrs, com.android.internal.R.styleable.CompoundButton, defStyle, 0);
- Drawable d = a.getDrawable(com.android.internal.R.styleable.CompoundButton_button);
+ Drawable d = a.getDrawableWithContext(context, com.android.internal.R.styleable.CompoundButton_button);
if (d != null) {
setButtonDrawable(d);
}
diff --git a/core/java/android/widget/LinearLayout.java b/core/java/android/widget/LinearLayout.java
index 6cc794b..130cf56 100644
--- a/core/java/android/widget/LinearLayout.java
+++ b/core/java/android/widget/LinearLayout.java
@@ -89,10 +89,14 @@ public class LinearLayout extends ViewGroup {
}
public LinearLayout(Context context, AttributeSet attrs) {
- super(context, attrs);
+ this(context, attrs, 0);
+ }
+
+ public LinearLayout(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
TypedArray a =
- context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.LinearLayout);
+ context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.LinearLayout, defStyle, 0);
int index = a.getInt(com.android.internal.R.styleable.LinearLayout_orientation, -1);
if (index >= 0) {
diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java
index 7c8151e..32ba54e 100644
--- a/core/java/android/widget/ListView.java
+++ b/core/java/android/widget/ListView.java
@@ -123,6 +123,8 @@ public class ListView extends AbsListView {
private boolean mHeaderDividersEnabled;
private boolean mFooterDividersEnabled;
+
+ private Drawable.ConstantState mDefaultItemBackground;
private boolean mAreAllItemsSelectable = true;
@@ -178,6 +180,11 @@ public class ListView extends AbsListView {
mHeaderDividersEnabled = a.getBoolean(R.styleable.ListView_headerDividersEnabled, true);
mFooterDividersEnabled = a.getBoolean(R.styleable.ListView_footerDividersEnabled, true);
+
+ Drawable defaultItemBackground = a.getDrawable(com.android.internal.R.styleable.ListView_listItemBackground);
+ if (defaultItemBackground != null) {
+ mDefaultItemBackground = defaultItemBackground.getConstantState();
+ }
a.recycle();
}
@@ -1662,11 +1669,16 @@ public class ListView extends AbsListView {
return child;
}
- }
+ }
// Make a new view for this position, or convert an unused view if possible
child = obtainView(position);
-
+ if (child.getBackground() == null && mDefaultItemBackground != null) {
+ if (mAdapter.getItemViewType(position) != Adapter.IGNORE_ITEM_VIEW_TYPE) {
+ child.setBackgroundDrawable(mDefaultItemBackground.newDrawable());
+ }
+ }
+
// This needs to be positioned and measured
setupChild(child, position, y, flow, childrenLeft, selected, false);
@@ -1762,7 +1774,7 @@ public class ListView extends AbsListView {
child.setDrawingCacheEnabled(true);
}
}
-
+
@Override
protected boolean canAnimate() {
return super.canAnimate() && mItemCount > 0;
@@ -2824,6 +2836,10 @@ public class ListView extends AbsListView {
private View addViewAbove(View theView, int position) {
int abovePosition = position - 1;
View view = obtainView(abovePosition);
+ if (view.getBackground() == null && mDefaultItemBackground != null) {
+ if (mAdapter.getItemViewType(position) != Adapter.IGNORE_ITEM_VIEW_TYPE)
+ view.setBackgroundDrawable(mDefaultItemBackground.newDrawable());
+ }
int edgeOfNewChild = theView.getTop() - mDividerHeight;
setupChild(view, abovePosition, edgeOfNewChild, false, mListPadding.left, false, false);
return view;
@@ -2832,6 +2848,10 @@ public class ListView extends AbsListView {
private View addViewBelow(View theView, int position) {
int belowPosition = position + 1;
View view = obtainView(belowPosition);
+ if (view.getBackground() == null && mDefaultItemBackground != null) {
+ if (mAdapter.getItemViewType(position) != Adapter.IGNORE_ITEM_VIEW_TYPE)
+ view.setBackgroundDrawable(mDefaultItemBackground.newDrawable());
+ }
int edgeOfNewChild = theView.getBottom() + mDividerHeight;
setupChild(view, belowPosition, edgeOfNewChild, true, mListPadding.left, false, false);
return view;
diff --git a/core/java/android/widget/ProgressBar.java b/core/java/android/widget/ProgressBar.java
index 2f28d9f..6693fc9 100644
--- a/core/java/android/widget/ProgressBar.java
+++ b/core/java/android/widget/ProgressBar.java
@@ -174,7 +174,7 @@ public class ProgressBar extends View {
mNoInvalidate = true;
- Drawable drawable = a.getDrawable(R.styleable.ProgressBar_progressDrawable);
+ Drawable drawable = a.getDrawableWithContext(context, R.styleable.ProgressBar_progressDrawable);
if (drawable != null) {
drawable = tileify(drawable, false);
setProgressDrawable(drawable);
@@ -204,7 +204,7 @@ public class ProgressBar extends View {
setSecondaryProgress(
a.getInt(R.styleable.ProgressBar_secondaryProgress, mSecondaryProgress));
- drawable = a.getDrawable(R.styleable.ProgressBar_indeterminateDrawable);
+ drawable = a.getDrawableWithContext(context, R.styleable.ProgressBar_indeterminateDrawable);
if (drawable != null) {
drawable = tileifyIndeterminate(drawable);
setIndeterminateDrawable(drawable);
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 6771711..683a427 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -17,22 +17,24 @@
package android.widget;
import android.app.PendingIntent;
+import android.app.ActivityManagerNative;
+import android.app.PendingIntent.CanceledException;
import android.content.Context;
import android.content.Intent;
import android.content.IntentSender;
import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.res.Resources;
+import android.content.res.CustomTheme;
import android.graphics.Bitmap;
import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Parcel;
import android.os.Parcelable;
+import android.os.RemoteException;
import android.text.TextUtils;
import android.util.Log;
-import android.view.LayoutInflater;
-import android.view.RemotableViewMethod;
-import android.view.View;
-import android.view.ViewGroup;
+import android.view.*;
import android.view.LayoutInflater.Filter;
import android.view.View.OnClickListener;
@@ -861,9 +863,17 @@ public class RemoteViews implements Parcelable, Filter {
if (packageName != null) {
try {
c = context.createPackageContext(packageName, Context.CONTEXT_RESTRICTED);
+ CustomTheme theme = ActivityManagerNative.getDefault().getConfiguration().customTheme;
+ int styleId = CustomTheme.getStyleId(c, theme.getThemePackageName(), theme.getThemeId());
+ ContextThemeWrapper themeContext = new ContextThemeWrapper(c, styleId);
+ themeContext.useThemedResources(theme.getThemePackageName());
+ c = themeContext;
} catch (NameNotFoundException e) {
Log.e(LOG_TAG, "Package name " + packageName + " not found");
c = context;
+ } catch (RemoteException e) {
+ Log.e(LOG_TAG, "Failed to get current theme", e);
+ c = context;
}
} else {
c = context;
diff --git a/core/java/android/widget/TabWidget.java b/core/java/android/widget/TabWidget.java
index 2ba6268..b813088 100644
--- a/core/java/android/widget/TabWidget.java
+++ b/core/java/android/widget/TabWidget.java
@@ -27,6 +27,7 @@ import android.graphics.drawable.Drawable;
import android.os.Build;
import android.util.AttributeSet;
import android.util.Log;
+import android.util.TypedValue;
import android.view.View;
import android.view.ViewGroup;
import android.view.View.OnFocusChangeListener;
@@ -65,19 +66,26 @@ public class TabWidget extends LinearLayout implements OnFocusChangeListener {
}
public TabWidget(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs);
+ super(context, attrs, defStyle);
initTabWidget();
TypedArray a =
context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.TabWidget,
defStyle, 0);
-
+
+ mBottomLeftStrip = a.getDrawableWithContext(context,
+ com.android.internal.R.styleable.TabWidget_bottomLeftStrip);
+ mBottomRightStrip = a.getDrawableWithContext(context,
+ com.android.internal.R.styleable.TabWidget_bottomRightStrip);
+
a.recycle();
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
- mStripMoved = true;
+ if (mBottomLeftStrip != null || mBottomRightStrip != null) {
+ mStripMoved = true;
+ }
super.onSizeChanged(w, h, oldw, oldh);
}
@@ -101,21 +109,22 @@ public class TabWidget extends LinearLayout implements OnFocusChangeListener {
final Context context = mContext;
final Resources resources = context.getResources();
- if (context.getApplicationInfo().targetSdkVersion <= Build.VERSION_CODES.DONUT) {
- // Donut apps get old color scheme
- mBottomLeftStrip = resources.getDrawable(
- com.android.internal.R.drawable.tab_bottom_left_v4);
- mBottomRightStrip = resources.getDrawable(
- com.android.internal.R.drawable.tab_bottom_right_v4);
- } else {
- // Use modern color scheme for Eclair and beyond
- mBottomLeftStrip = resources.getDrawable(
- com.android.internal.R.drawable.tab_bottom_left);
- mBottomRightStrip = resources.getDrawable(
- com.android.internal.R.drawable.tab_bottom_right);
+ if (mBottomLeftStrip == null || mBottomRightStrip == null) {
+ if (context.getApplicationInfo().targetSdkVersion <= Build.VERSION_CODES.DONUT) {
+ // Donut apps get old color scheme
+ mBottomLeftStrip = resources.getDrawable(
+ com.android.internal.R.drawable.tab_bottom_left_v4);
+ mBottomRightStrip = resources.getDrawable(
+ com.android.internal.R.drawable.tab_bottom_right_v4);
+ } else {
+ // Use modern color scheme for Eclair and beyond
+ mBottomLeftStrip = resources.getDrawable(
+ com.android.internal.R.drawable.tab_bottom_left);
+ mBottomRightStrip = resources.getDrawable(
+ com.android.internal.R.drawable.tab_bottom_right);
+ }
}
-
// Deal with focus, as we don't want the focus to go by default
// to a tab other than the current tab
setFocusable(true);
@@ -203,31 +212,43 @@ public class TabWidget extends LinearLayout implements OnFocusChangeListener {
View selectedChild = getChildTabViewAt(mSelectedTab);
- mBottomLeftStrip.setState(selectedChild.getDrawableState());
- mBottomRightStrip.setState(selectedChild.getDrawableState());
+ if (mBottomLeftStrip != null) {
+ mBottomLeftStrip.setState(selectedChild.getDrawableState());
+ }
+ if (mBottomRightStrip != null) {
+ mBottomRightStrip.setState(selectedChild.getDrawableState());
+ }
if (mStripMoved) {
Rect selBounds = new Rect(); // Bounds of the selected tab indicator
selBounds.left = selectedChild.getLeft();
selBounds.right = selectedChild.getRight();
final int myHeight = getHeight();
- mBottomLeftStrip.setBounds(
- Math.min(0, selBounds.left
- - mBottomLeftStrip.getIntrinsicWidth()),
- myHeight - mBottomLeftStrip.getIntrinsicHeight(),
- selBounds.left,
- getHeight());
- mBottomRightStrip.setBounds(
- selBounds.right,
- myHeight - mBottomRightStrip.getIntrinsicHeight(),
- Math.max(getWidth(),
- selBounds.right + mBottomRightStrip.getIntrinsicWidth()),
- myHeight);
+ if (mBottomLeftStrip != null) {
+ mBottomLeftStrip.setBounds(
+ Math.min(0, selBounds.left
+ - mBottomLeftStrip.getIntrinsicWidth()),
+ myHeight - mBottomLeftStrip.getIntrinsicHeight(),
+ selBounds.left,
+ getHeight());
+ }
+ if (mBottomRightStrip != null) {
+ mBottomRightStrip.setBounds(
+ selBounds.right,
+ myHeight - mBottomRightStrip.getIntrinsicHeight(),
+ Math.max(getWidth(),
+ selBounds.right + mBottomRightStrip.getIntrinsicWidth()),
+ myHeight);
+ }
mStripMoved = false;
}
- mBottomLeftStrip.draw(canvas);
- mBottomRightStrip.draw(canvas);
+ if (mBottomLeftStrip != null) {
+ mBottomLeftStrip.draw(canvas);
+ }
+ if (mBottomRightStrip != null) {
+ mBottomRightStrip.draw(canvas);
+ }
}
/**
@@ -265,7 +286,9 @@ public class TabWidget extends LinearLayout implements OnFocusChangeListener {
getChildTabViewAt(mSelectedTab).setSelected(false);
mSelectedTab = index;
getChildTabViewAt(mSelectedTab).setSelected(true);
- mStripMoved = true;
+ if (mBottomLeftStrip != null || mBottomRightStrip != null) {
+ mStripMoved = true;
+ }
}
/**
diff --git a/core/java/com/android/internal/app/AlertActivity.java b/core/java/com/android/internal/app/AlertActivity.java
index 7251256..a628e3d 100644
--- a/core/java/com/android/internal/app/AlertActivity.java
+++ b/core/java/com/android/internal/app/AlertActivity.java
@@ -47,7 +47,7 @@ public abstract class AlertActivity extends Activity implements DialogInterface
super.onCreate(savedInstanceState);
mAlert = new AlertController(this, this, getWindow());
- mAlertParams = new AlertController.AlertParams(this);
+ mAlertParams = new AlertController.AlertParams();
}
public void cancel() {
diff --git a/core/java/com/android/internal/app/AlertController.java b/core/java/com/android/internal/app/AlertController.java
index 57dbb44..5434b61 100644
--- a/core/java/com/android/internal/app/AlertController.java
+++ b/core/java/com/android/internal/app/AlertController.java
@@ -59,6 +59,7 @@ public class AlertController {
private final Context mContext;
private final DialogInterface mDialogInterface;
private final Window mWindow;
+ private final LayoutInflater mInflater;
private CharSequence mTitle;
@@ -166,6 +167,7 @@ public class AlertController {
public AlertController(Context context, DialogInterface di, Window window) {
mContext = context;
+ mInflater = LayoutInflater.from(context);
mDialogInterface = di;
mWindow = window;
mHandler = new ButtonHandler(di);
@@ -695,9 +697,6 @@ public class AlertController {
}
public static class AlertParams {
- public final Context mContext;
- public final LayoutInflater mInflater;
-
public int mIconId = -1;
public Drawable mIcon;
public CharSequence mTitle;
@@ -747,10 +746,8 @@ public class AlertController {
void onPrepareListView(ListView listView);
}
- public AlertParams(Context context) {
- mContext = context;
+ public AlertParams() {
mCancelable = true;
- mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
public void apply(AlertController dialog) {
@@ -810,13 +807,13 @@ public class AlertController {
private void createListView(final AlertController dialog) {
final RecycleListView listView = (RecycleListView)
- mInflater.inflate(R.layout.select_dialog, null);
+ dialog.mInflater.inflate(R.layout.select_dialog, null);
ListAdapter adapter;
if (mIsMultiChoice) {
if (mCursor == null) {
adapter = new ArrayAdapter<CharSequence>(
- mContext, R.layout.select_dialog_multichoice, R.id.text1, mItems) {
+ dialog.mContext, R.layout.select_dialog_multichoice, R.id.text1, mItems) {
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = super.getView(position, convertView, parent);
@@ -830,7 +827,7 @@ public class AlertController {
}
};
} else {
- adapter = new CursorAdapter(mContext, mCursor, false) {
+ adapter = new CursorAdapter(dialog.mContext, mCursor, false) {
private final int mLabelIndex;
private final int mIsCheckedIndex;
@@ -850,7 +847,7 @@ public class AlertController {
@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
- return mInflater.inflate(R.layout.select_dialog_multichoice,
+ return dialog.mInflater.inflate(R.layout.select_dialog_multichoice,
parent, false);
}
@@ -861,9 +858,10 @@ public class AlertController {
? R.layout.select_dialog_singlechoice : R.layout.select_dialog_item;
if (mCursor == null) {
adapter = (mAdapter != null) ? mAdapter
- : new ArrayAdapter<CharSequence>(mContext, layout, R.id.text1, mItems);
+ : new ArrayAdapter<CharSequence>(dialog.mContext,
+ layout, R.id.text1, mItems);
} else {
- adapter = new SimpleCursorAdapter(mContext, layout,
+ adapter = new SimpleCursorAdapter(dialog.mContext, layout,
mCursor, new String[]{mLabelColumn}, new int[]{R.id.text1});
}
}
diff --git a/core/java/com/android/internal/app/RingtonePickerActivity.java b/core/java/com/android/internal/app/RingtonePickerActivity.java
index 5a0fea3..33e7d6f 100644
--- a/core/java/com/android/internal/app/RingtonePickerActivity.java
+++ b/core/java/com/android/internal/app/RingtonePickerActivity.java
@@ -59,6 +59,9 @@ public final class RingtonePickerActivity extends AlertActivity implements
/** The position in the list of the 'Default' item. */
private int mDefaultRingtonePos = -1;
+ /** The position in the list of the 'Buy ringtone' item (should be 0). */
+ private int mBuyPos = -1;
+
/** The position in the list of the last clicked item. */
private int mClickedPos = -1;
@@ -67,7 +70,10 @@ public final class RingtonePickerActivity extends AlertActivity implements
/** Whether this list has the 'Silent' item. */
private boolean mHasSilentItem;
-
+
+ /** Whether this list has the 'Buy ringtone' item. */
+ private boolean mHasBuyItem;
+
/** The Uri to place a checkmark next to. */
private Uri mExistingUri;
@@ -94,13 +100,19 @@ public final class RingtonePickerActivity extends AlertActivity implements
* On item clicked
*/
public void onClick(DialogInterface dialog, int which) {
+ if (which == mBuyPos) {
+ startActivity(new Intent(Intent.ACTION_VIEW,
+ Uri.parse("http://wap.t-zones.com")));
+ finish();
+ }
+
// Save the position of most recently clicked item
mClickedPos = which;
-
+
// Play clip
playRingtone(which, 0);
}
-
+
};
@Override
@@ -120,10 +132,13 @@ public final class RingtonePickerActivity extends AlertActivity implements
if (mUriForDefaultItem == null) {
mUriForDefaultItem = Settings.System.DEFAULT_RINGTONE_URI;
}
-
+
// Get whether to show the 'Silent' item
mHasSilentItem = intent.getBooleanExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_SILENT, true);
-
+
+ // Get whether to show the 'Buy ringtones' item
+ mHasBuyItem = intent.getBooleanExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_BUY, false);
+
// Give the Activity so it can do managed queries
mRingtoneManager = new RingtoneManager(this);
@@ -168,7 +183,11 @@ public final class RingtonePickerActivity extends AlertActivity implements
}
public void onPrepareListView(ListView listView) {
-
+
+ if (mHasBuyItem) {
+ mBuyPos = addBuyItem(listView);
+ }
+
if (mHasDefaultItem) {
mDefaultRingtonePos = addDefaultRingtoneItem(listView);
@@ -202,29 +221,38 @@ public final class RingtonePickerActivity extends AlertActivity implements
* @param textResId The resource ID of the text for the item.
* @return The position of the inserted item.
*/
- private int addStaticItem(ListView listView, int textResId) {
- TextView textView = (TextView) getLayoutInflater().inflate(
- com.android.internal.R.layout.select_dialog_singlechoice, listView, false);
+ private int addStaticItem(ListView listView, int resId, int textResId) {
+ TextView textView = (TextView) getLayoutInflater().inflate(resId, listView, false);
textView.setText(textResId);
listView.addHeaderView(textView);
mStaticItemCount++;
return listView.getHeaderViewsCount() - 1;
}
-
+
+ private int addBuyItem(ListView listView) {
+ return addStaticItem(listView,
+ com.android.internal.R.layout.simple_list_item_1,
+ com.android.internal.R.string.buy_ringtones);
+ }
+
private int addDefaultRingtoneItem(ListView listView) {
- return addStaticItem(listView, com.android.internal.R.string.ringtone_default);
+ return addStaticItem(listView,
+ com.android.internal.R.layout.select_dialog_singlechoice,
+ com.android.internal.R.string.ringtone_default);
}
private int addSilentItem(ListView listView) {
- return addStaticItem(listView, com.android.internal.R.string.ringtone_silent);
+ return addStaticItem(listView,
+ com.android.internal.R.layout.select_dialog_singlechoice,
+ com.android.internal.R.string.ringtone_silent);
}
/*
* On click of Ok/Cancel buttons
*/
public void onClick(DialogInterface dialog, int which) {
- boolean positiveResult = which == BUTTON1;
-
+ boolean positiveResult = which == BUTTON1 && mClickedPos != mBuyPos;
+
// Stop playing the previous ringtone
mRingtoneManager.stopPreviousRingtone();
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index 404c513..b4b90b6 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -533,7 +533,7 @@ public class ZygoteInit {
String args[] = {
"--setuid=1000",
"--setgid=1000",
- "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,3001,3002,3003",
+ "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1300,3001,3002,3003",
"--capabilities=130104352,130104352",
"--runtime-init",
"--nice-name=system_server",
diff --git a/core/java/com/android/internal/view/menu/ContextMenuBuilder.java b/core/java/com/android/internal/view/menu/ContextMenuBuilder.java
index bf44d51..3326c67 100644
--- a/core/java/com/android/internal/view/menu/ContextMenuBuilder.java
+++ b/core/java/com/android/internal/view/menu/ContextMenuBuilder.java
@@ -16,6 +16,7 @@
package com.android.internal.view.menu;
+import android.app.Dialog;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.os.IBinder;
@@ -38,6 +39,7 @@ import android.view.View;
* with a view's context menu items and show the context menu.
*/
public class ContextMenuBuilder extends MenuBuilder implements ContextMenu {
+ private Context mContext;
public ContextMenuBuilder(Context context) {
super(context);
@@ -85,12 +87,27 @@ public class ContextMenuBuilder extends MenuBuilder implements ContextMenu {
EventLog.writeEvent(50001, 1);
MenuDialogHelper helper = new MenuDialogHelper(this);
- helper.show(token);
+ Dialog d = helper.create(token);
+ mContext = d.getContext();
+ d.show();
return helper;
}
return null;
}
-
+
+ /**
+ * The dialog holding this context menu can be themed separately from the
+ * Context that created it. This is here to ensure that the right context
+ * is used during inflation.
+ */
+ @Override
+ public Context getContext() {
+ if (mContext != null) {
+ return mContext;
+ } else {
+ return super.getContext();
+ }
+ }
}
diff --git a/core/java/com/android/internal/view/menu/MenuBuilder.java b/core/java/com/android/internal/view/menu/MenuBuilder.java
index 228d5d0..e0f66a2 100644
--- a/core/java/com/android/internal/view/menu/MenuBuilder.java
+++ b/core/java/com/android/internal/view/menu/MenuBuilder.java
@@ -24,6 +24,7 @@ import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.res.Configuration;
import android.content.res.Resources;
+import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Parcelable;
@@ -176,8 +177,22 @@ public class MenuBuilder implements Menu {
LayoutInflater getInflater() {
// Create an inflater that uses the given theme for the Views it inflates
if (mInflater == null) {
- Context wrappedContext = new ContextThemeWrapper(mContext,
- THEME_RES_FOR_TYPE[mMenuType]);
+ Context wrappedContext = null;
+ // We theme expanded menu view only for now.
+ if (mMenuType == TYPE_EXPANDED) {
+ wrappedContext = new ContextThemeWrapper(getContext(),
+ resolveDefaultTheme(getContext(), 0,
+ com.android.internal.R.styleable.Theme_expandedMenuTheme,
+ com.android.internal.R.style.Theme_ExpandedMenu));
+ } else if (mMenuType == TYPE_ICON) {
+ wrappedContext = new ContextThemeWrapper(getContext(),
+ resolveDefaultTheme(getContext(), 0,
+ com.android.internal.R.styleable.Theme_iconMenuTheme,
+ com.android.internal.R.style.Theme_IconMenu));
+ } else {
+ wrappedContext = new ContextThemeWrapper(getContext(),
+ THEME_RES_FOR_TYPE[mMenuType]);
+ }
mInflater = (LayoutInflater) wrappedContext
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
@@ -217,6 +232,18 @@ public class MenuBuilder implements Menu {
boolean hasMenuView() {
return mMenuView != null && mMenuView.get() != null;
}
+
+ int resolveDefaultTheme(Context context, int theme, int themeAttrIndex,
+ int defStyle) {
+ if (theme != 0) {
+ return theme;
+ } else {
+ TypedArray a = context.obtainStyledAttributes(android.R.styleable.Theme);
+ int newTheme = a.getResourceId(themeAttrIndex, defStyle);
+ a.recycle();
+ return newTheme;
+ }
+ }
}
/**
diff --git a/core/java/com/android/internal/view/menu/MenuDialogHelper.java b/core/java/com/android/internal/view/menu/MenuDialogHelper.java
index 70f040a..d657f47 100644
--- a/core/java/com/android/internal/view/menu/MenuDialogHelper.java
+++ b/core/java/com/android/internal/view/menu/MenuDialogHelper.java
@@ -21,6 +21,7 @@ import android.app.Dialog;
import android.content.DialogInterface;
import android.os.IBinder;
import android.view.KeyEvent;
+import android.view.LayoutInflater;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
@@ -39,13 +40,13 @@ public class MenuDialogHelper implements DialogInterface.OnKeyListener, DialogIn
public MenuDialogHelper(MenuBuilder menu) {
mMenu = menu;
}
-
+
/**
- * Shows menu as a dialog.
+ * Creates menu as a dialog. Does not show.
*
* @param windowToken Optional token to assign to the window.
*/
- public void show(IBinder windowToken) {
+ public Dialog create(IBinder windowToken) {
// Many references to mMenu, create local reference
final MenuBuilder menu = mMenu;
@@ -81,8 +82,18 @@ public class MenuDialogHelper implements DialogInterface.OnKeyListener, DialogIn
if (windowToken != null) {
lp.token = windowToken;
}
- lp.flags |= WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
+ lp.flags |= WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
+ return mDialog;
+ }
+
+ /**
+ * Shows menu as a dialog.
+ *
+ * @param windowToken Optional token to assign to the window.
+ */
+ public void show(IBinder windowToken) {
+ create(windowToken);
mDialog.show();
}
diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp
index 562cc8f..39a03de 100644
--- a/core/jni/android_util_AssetManager.cpp
+++ b/core/jni/android_util_AssetManager.cpp
@@ -2,16 +2,16 @@
**
** 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
+** 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
+** 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
+** 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.
*/
@@ -29,6 +29,7 @@
#include <utils/Asset.h>
#include <utils/AssetManager.h>
#include <utils/ResourceTypes.h>
+#include <utils/ZipFile.h>
#include <stdio.h>
@@ -159,30 +160,30 @@ static jobject returnParcelFileDescriptor(JNIEnv* env, Asset* a, jlongArray outO
off_t startOffset, length;
int fd = a->openFileDescriptor(&startOffset, &length);
delete a;
-
+
if (fd < 0) {
doThrow(env, "java/io/FileNotFoundException",
"This file can not be opened as a file descriptor; it is probably compressed");
return NULL;
}
-
+
jlong* offsets = (jlong*)env->GetPrimitiveArrayCritical(outOffsets, 0);
if (offsets == NULL) {
close(fd);
return NULL;
}
-
+
offsets[0] = startOffset;
offsets[1] = length;
-
+
env->ReleasePrimitiveArrayCritical(outOffsets, offsets, 0);
-
+
jobject fileDesc = newFileDescriptor(env, fd);
if (fileDesc == NULL) {
close(fd);
return NULL;
}
-
+
return newParcelFileDescriptor(env, fileDesc);
}
@@ -391,7 +392,7 @@ static jint android_content_AssetManager_readAsset(JNIEnv* env, jobject clazz,
if (len == 0) {
return 0;
}
-
+
jsize bLen = env->GetArrayLength(bArray);
if (off < 0 || off >= bLen || len < 0 || len > bLen || (off+len) > bLen) {
doThrow(env, "java/lang/IndexOutOfBoundsException");
@@ -545,9 +546,9 @@ static void android_content_AssetManager_setConfiguration(JNIEnv* env, jobject c
ResTable_config config;
memset(&config, 0, sizeof(config));
-
+
const char* locale8 = locale != NULL ? env->GetStringUTFChars(locale, NULL) : NULL;
-
+
config.mcc = (uint16_t)mcc;
config.mnc = (uint16_t)mnc;
config.orientation = (uint8_t)orientation;
@@ -562,7 +563,7 @@ static void android_content_AssetManager_setConfiguration(JNIEnv* env, jobject c
config.sdkVersion = (uint16_t)sdkVersion;
config.minorVersion = 0;
am->setConfiguration(config, locale8);
-
+
if (locale != NULL) env->ReleaseStringUTFChars(locale, locale8);
}
@@ -613,12 +614,12 @@ static jstring android_content_AssetManager_getResourceName(JNIEnv* env, jobject
if (am == NULL) {
return NULL;
}
-
+
ResTable::resource_name name;
if (!am->getResources().getResourceName(resid, &name)) {
return NULL;
}
-
+
String16 str;
if (name.package != NULL) {
str.setTo(name.package, name.packageLen);
@@ -637,7 +638,7 @@ static jstring android_content_AssetManager_getResourceName(JNIEnv* env, jobject
}
str.append(name.name, name.nameLen);
}
-
+
return env->NewString((const jchar*)str.string(), str.size());
}
@@ -648,16 +649,16 @@ static jstring android_content_AssetManager_getResourcePackageName(JNIEnv* env,
if (am == NULL) {
return NULL;
}
-
+
ResTable::resource_name name;
if (!am->getResources().getResourceName(resid, &name)) {
return NULL;
}
-
+
if (name.package != NULL) {
return env->NewString((const jchar*)name.package, name.packageLen);
}
-
+
return NULL;
}
@@ -668,16 +669,16 @@ static jstring android_content_AssetManager_getResourceTypeName(JNIEnv* env, job
if (am == NULL) {
return NULL;
}
-
+
ResTable::resource_name name;
if (!am->getResources().getResourceName(resid, &name)) {
return NULL;
}
-
+
if (name.type != NULL) {
return env->NewString((const jchar*)name.type, name.typeLen);
}
-
+
return NULL;
}
@@ -688,16 +689,16 @@ static jstring android_content_AssetManager_getResourceEntryName(JNIEnv* env, jo
if (am == NULL) {
return NULL;
}
-
+
ResTable::resource_name name;
if (!am->getResources().getResourceName(resid, &name)) {
return NULL;
}
-
+
if (name.name != NULL) {
return env->NewString((const jchar*)name.name, name.nameLen);
}
-
+
return NULL;
}
@@ -732,10 +733,10 @@ static jint android_content_AssetManager_loadResourceBagValue(JNIEnv* env, jobje
return 0;
}
const ResTable& res(am->getResources());
-
+
// Now lock down the resource object and start pulling stuff from it.
res.lock();
-
+
ssize_t block = -1;
Res_value value;
@@ -756,7 +757,7 @@ static jint android_content_AssetManager_loadResourceBagValue(JNIEnv* env, jobje
if (block < 0) {
return block;
}
-
+
uint32_t ref = ident;
if (resolve) {
block = res.resolveReference(&value, block, &ref, &typeSpecFlags);
@@ -828,6 +829,16 @@ static void android_content_AssetManager_applyThemeStyle(JNIEnv* env, jobject cl
theme->applyStyle(styleRes, force ? true : false);
}
+static void android_content_AssetManager_setAttributeValue(JNIEnv* env, jobject clazz,
+ jint themeInt,
+ jint attribute,
+ jint value)
+{
+ ResTable::Theme* theme = (ResTable::Theme*)themeInt;
+ theme->setAttributeValue(attribute, value);
+}
+
+
static void android_content_AssetManager_copyTheme(JNIEnv* env, jobject clazz,
jint destInt, jint srcInt)
{
@@ -859,21 +870,21 @@ static void android_content_AssetManager_dumpTheme(JNIEnv* env, jobject clazz,
{
ResTable::Theme* theme = (ResTable::Theme*)themeInt;
const ResTable& res(theme->getResTable());
-
+
if (tag == NULL) {
doThrow(env, "java/lang/NullPointerException");
return;
}
-
+
const char* tag8 = env->GetStringUTFChars(tag, NULL);
const char* prefix8 = NULL;
if (prefix != NULL) {
prefix8 = env->GetStringUTFChars(prefix, NULL);
}
-
+
// XXX Need to use params.
theme->dumpToLog();
-
+
if (prefix8 != NULL) {
env->ReleaseStringUTFChars(prefix, prefix8);
}
@@ -1076,12 +1087,12 @@ static jboolean android_content_AssetManager_applyStyle(JNIEnv* env, jobject cla
dest[STYLE_RESOURCE_ID] = resid;
dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags;
dest[STYLE_DENSITY] = config.density;
-
+
if (indices != NULL && value.dataType != Res_value::TYPE_NULL) {
indicesIdx++;
indices[indicesIdx] = ii;
}
-
+
dest += STYLE_NUM_ENTRIES;
}
@@ -1107,7 +1118,7 @@ static jboolean android_content_AssetManager_retrieveAttributes(JNIEnv* env, job
doThrow(env, "java/lang/NullPointerException");
return JNI_FALSE;
}
-
+
AssetManager* am = assetManagerForJavaObject(env, clazz);
if (am == NULL) {
return JNI_FALSE;
@@ -1116,20 +1127,20 @@ static jboolean android_content_AssetManager_retrieveAttributes(JNIEnv* env, job
ResXMLParser* xmlParser = (ResXMLParser*)xmlParserToken;
ResTable_config config;
Res_value value;
-
+
const jsize NI = env->GetArrayLength(attrs);
const jsize NV = env->GetArrayLength(outValues);
if (NV < (NI*STYLE_NUM_ENTRIES)) {
doThrow(env, "java/lang/IndexOutOfBoundsException");
return JNI_FALSE;
}
-
+
jint* src = (jint*)env->GetPrimitiveArrayCritical(attrs, 0);
if (src == NULL) {
doThrow(env, "java/lang/OutOfMemoryError");
return JNI_FALSE;
}
-
+
jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
jint* dest = baseDest;
if (dest == NULL) {
@@ -1137,7 +1148,7 @@ static jboolean android_content_AssetManager_retrieveAttributes(JNIEnv* env, job
doThrow(env, "java/lang/OutOfMemoryError");
return JNI_FALSE;
}
-
+
jint* indices = NULL;
int indicesIdx = 0;
if (outIndices != NULL) {
@@ -1148,27 +1159,27 @@ static jboolean android_content_AssetManager_retrieveAttributes(JNIEnv* env, job
// Now lock down the resource object and start pulling stuff from it.
res.lock();
-
+
// Retrieve the XML attributes, if requested.
const jsize NX = xmlParser->getAttributeCount();
jsize ix=0;
uint32_t curXmlAttr = xmlParser->getAttributeNameResID(ix);
-
+
static const ssize_t kXmlBlock = 0x10000000;
-
+
// Now iterate through all of the attributes that the client has requested,
// filling in each with whatever data we can find.
ssize_t block = 0;
uint32_t typeSetFlags;
for (jsize ii=0; ii<NI; ii++) {
const uint32_t curIdent = (uint32_t)src[ii];
-
+
// Try to find a value for this attribute...
value.dataType = Res_value::TYPE_NULL;
value.data = 0;
typeSetFlags = 0;
config.density = 0;
-
+
// Skip through XML attributes until the end or the next possible match.
while (ix < NX && curIdent > curXmlAttr) {
ix++;
@@ -1181,7 +1192,7 @@ static jboolean android_content_AssetManager_retrieveAttributes(JNIEnv* env, job
ix++;
curXmlAttr = xmlParser->getAttributeNameResID(ix);
}
-
+
//printf("Attribute 0x%08x: type=0x%x, data=0x%08x\n", curIdent, value.dataType, value.data);
uint32_t resid = 0;
if (value.dataType != Res_value::TYPE_NULL) {
@@ -1191,14 +1202,14 @@ static jboolean android_content_AssetManager_retrieveAttributes(JNIEnv* env, job
&typeSetFlags, &config);
if (newBlock >= 0) block = newBlock;
}
-
+
// Deal with the special @null value -- it turns back to TYPE_NULL.
if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
value.dataType = Res_value::TYPE_NULL;
}
-
+
//printf("Attribute 0x%08x: final type=0x%x, data=0x%08x\n", curIdent, value.dataType, value.data);
-
+
// Write the final value back to Java.
dest[STYLE_TYPE] = value.dataType;
dest[STYLE_DATA] = value.data;
@@ -1207,25 +1218,25 @@ static jboolean android_content_AssetManager_retrieveAttributes(JNIEnv* env, job
dest[STYLE_RESOURCE_ID] = resid;
dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags;
dest[STYLE_DENSITY] = config.density;
-
+
if (indices != NULL && value.dataType != Res_value::TYPE_NULL) {
indicesIdx++;
indices[indicesIdx] = ii;
}
-
+
dest += STYLE_NUM_ENTRIES;
}
-
+
res.unlock();
-
+
if (indices != NULL) {
indices[0] = indicesIdx;
env->ReleasePrimitiveArrayCritical(outIndices, indices, 0);
}
-
+
env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
env->ReleasePrimitiveArrayCritical(attrs, src, 0);
-
+
return JNI_TRUE;
}
@@ -1237,12 +1248,12 @@ static jint android_content_AssetManager_getArraySize(JNIEnv* env, jobject clazz
return NULL;
}
const ResTable& res(am->getResources());
-
+
res.lock();
const ResTable::bag_entry* defStyleEnt = NULL;
ssize_t bagOff = res.getBagLocked(id, &defStyleEnt);
res.unlock();
-
+
return bagOff;
}
@@ -1254,7 +1265,7 @@ static jint android_content_AssetManager_retrieveArray(JNIEnv* env, jobject claz
doThrow(env, "java/lang/NullPointerException");
return JNI_FALSE;
}
-
+
AssetManager* am = assetManagerForJavaObject(env, clazz);
if (am == NULL) {
return JNI_FALSE;
@@ -1263,25 +1274,25 @@ static jint android_content_AssetManager_retrieveArray(JNIEnv* env, jobject claz
ResTable_config config;
Res_value value;
ssize_t block;
-
+
const jsize NV = env->GetArrayLength(outValues);
-
+
jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
jint* dest = baseDest;
if (dest == NULL) {
doThrow(env, "java/lang/OutOfMemoryError");
return JNI_FALSE;
}
-
+
// Now lock down the resource object and start pulling stuff from it.
res.lock();
-
+
const ResTable::bag_entry* arrayEnt = NULL;
uint32_t arrayTypeSetFlags = 0;
ssize_t bagOff = res.getBagLocked(id, &arrayEnt, &arrayTypeSetFlags);
const ResTable::bag_entry* endArrayEnt = arrayEnt +
(bagOff >= 0 ? bagOff : 0);
-
+
int i = 0;
uint32_t typeSetFlags;
while (i < NV && arrayEnt < endArrayEnt) {
@@ -1289,7 +1300,7 @@ static jint android_content_AssetManager_retrieveArray(JNIEnv* env, jobject claz
typeSetFlags = arrayTypeSetFlags;
config.density = 0;
value = arrayEnt->map.value;
-
+
uint32_t resid = 0;
if (value.dataType != Res_value::TYPE_NULL) {
// Take care of resolving the found resource to its final value.
@@ -1317,13 +1328,13 @@ static jint android_content_AssetManager_retrieveArray(JNIEnv* env, jobject claz
i+= STYLE_NUM_ENTRIES;
arrayEnt++;
}
-
+
i /= STYLE_NUM_ENTRIES;
-
+
res.unlock();
-
+
env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
-
+
return i;
}
@@ -1396,13 +1407,13 @@ static jintArray android_content_AssetManager_getArrayStringInfo(JNIEnv* env, jo
jint stringIndex = -1;
jint stringBlock = 0;
value = bag->map.value;
-
+
// Take care of resolving the found resource to its final value.
stringBlock = res.resolveReference(&value, bag->stringBlock, NULL);
if (value.dataType == Res_value::TYPE_STRING) {
stringIndex = value.data;
}
-
+
//todo: It might be faster to allocate a C array to contain
// the blocknums and indices, put them in there and then
// do just one SetIntArrayRegion()
@@ -1448,7 +1459,7 @@ static jobjectArray android_content_AssetManager_getArrayStringResource(JNIEnv*
for (size_t i=0; ((ssize_t)i)<N; i++, bag++) {
value = bag->map.value;
jstring str = NULL;
-
+
// Take care of resolving the found resource to its final value.
ssize_t block = res.resolveReference(&value, bag->stringBlock, NULL);
if (value.dataType == Res_value::TYPE_STRING) {
@@ -1460,7 +1471,7 @@ static jobjectArray android_content_AssetManager_getArrayStringResource(JNIEnv*
return NULL;
}
}
-
+
env->SetObjectArrayElement(array, i, str);
}
res.unlockBag(startOfBag);
@@ -1493,7 +1504,7 @@ static jintArray android_content_AssetManager_getArrayIntResource(JNIEnv* env, j
const ResTable::bag_entry* bag = startOfBag;
for (size_t i=0; ((ssize_t)i)<N; i++, bag++) {
value = bag->map.value;
-
+
// Take care of resolving the found resource to its final value.
ssize_t block = res.resolveReference(&value, bag->stringBlock, NULL);
if (value.dataType >= Res_value::TYPE_FIRST_INT
@@ -1506,6 +1517,84 @@ static jintArray android_content_AssetManager_getArrayIntResource(JNIEnv* env, j
return array;
}
+static jint android_content_AssetManager_splitThemePackage(JNIEnv* env, jobject clazz,
+ jstring srcFileName, jstring dstFileName, jobjectArray drmProtectedAssetNames)
+{
+ AssetManager* am = assetManagerForJavaObject(env, clazz);
+ if (am == NULL) {
+ return -1;
+ }
+
+ LOGV("splitThemePackage in %p (Java object %p)\n", am, clazz);
+
+ if (srcFileName == NULL || dstFileName == NULL) {
+ doThrow(env, "java/lang/NullPointerException");
+ return -2;
+ }
+
+ jsize size = env->GetArrayLength(drmProtectedAssetNames);
+ if (size == 0) {
+ doThrow(env, "java/lang/IllegalArgumentException");
+ return -3;
+ }
+
+ const char* srcFileName8 = env->GetStringUTFChars(srcFileName, NULL);
+ ZipFile* srcZip = new ZipFile;
+ status_t err = srcZip->open(srcFileName8, ZipFile::kOpenReadWrite);
+ if (err != NO_ERROR) {
+ LOGV("error opening zip file %s\n", srcFileName8);
+ delete srcZip;
+ env->ReleaseStringUTFChars(srcFileName, srcFileName8);
+ return -4;
+ }
+
+ const char* dstFileName8 = env->GetStringUTFChars(dstFileName, NULL);
+ ZipFile* dstZip = new ZipFile;
+ err = dstZip->open(dstFileName8, ZipFile::kOpenReadWrite | ZipFile::kOpenTruncate | ZipFile::kOpenCreate);
+
+ if (err != NO_ERROR) {
+ LOGV("error opening zip file %s\n", dstFileName8);
+ delete srcZip;
+ delete dstZip;
+ env->ReleaseStringUTFChars(srcFileName, srcFileName8);
+ env->ReleaseStringUTFChars(dstFileName, dstFileName8);
+ return -5;
+ }
+
+ int result = 0;
+ for (int i = 0; i < size; i++) {
+ jstring javaString = (jstring)env->GetObjectArrayElement(drmProtectedAssetNames, i);
+ const char* drmProtectedAssetFileName8 = env->GetStringUTFChars(javaString, NULL);
+ ZipEntry *assetEntry = srcZip->getEntryByName(drmProtectedAssetFileName8);
+ if (assetEntry == NULL) {
+ result = 1;
+ LOGV("Invalid asset entry %s\n", drmProtectedAssetFileName8);
+ } else {
+ status_t loc_result = dstZip->add(srcZip, assetEntry, 0, NULL);
+ if (loc_result != NO_ERROR) {
+ LOGV("error copying zip entry %s\n", drmProtectedAssetFileName8);
+ result = result | 2;
+ } else {
+ loc_result = srcZip->remove(assetEntry);
+ if (loc_result != NO_ERROR) {
+ LOGV("error removing zip entry %s\n", drmProtectedAssetFileName8);
+ result = result | 4;
+ }
+ }
+ }
+ env->ReleaseStringUTFChars(javaString, drmProtectedAssetFileName8);
+ }
+ srcZip->flush();
+ dstZip->flush();
+
+ delete srcZip;
+ delete dstZip;
+ env->ReleaseStringUTFChars(srcFileName, srcFileName8);
+ env->ReleaseStringUTFChars(dstFileName, dstFileName8);
+
+ return (jint)result;
+}
+
static void android_content_AssetManager_init(JNIEnv* env, jobject clazz)
{
AssetManager* am = new AssetManager();
@@ -1557,6 +1646,60 @@ static jint android_content_AssetManager_getGlobalAssetManagerCount(JNIEnv* env,
return AssetManager::getGlobalCount();
}
+static jboolean android_content_AssetManager_removeAssetPath(JNIEnv* env, jobject clazz,
+ jstring packageName, jstring path)
+{
+ if (path == NULL) {
+ doThrow(env, "java/lang/NullPointerException");
+ return JNI_FALSE;
+ }
+
+ AssetManager* am = assetManagerForJavaObject(env, clazz);
+ if (am == NULL) {
+ return JNI_FALSE;
+ }
+
+ const char* name8 = env->GetStringUTFChars(packageName, NULL);
+ const char* path8 = env->GetStringUTFChars(path, NULL);
+ bool res = am->removeAssetPath(String8(name8), String8(path8));
+ env->ReleaseStringUTFChars(path, path8);
+ env->ReleaseStringUTFChars(packageName, name8);
+
+ return res;
+}
+
+static jint android_content_AssetManager_updateResourcesWithAssetPath(
+ JNIEnv* env, jobject clazz, jstring path)
+{
+ if (path == NULL) {
+ doThrow(env, "java/lang/NullPointerException");
+ return JNI_FALSE;
+ }
+
+ AssetManager* am = assetManagerForJavaObject(env, clazz);
+ if (am == NULL) {
+ return JNI_FALSE;
+ }
+
+ const char* path8 = env->GetStringUTFChars(path, NULL);
+
+ void* cookie;
+ bool res = am->updateWithAssetPath(String8(path8), &cookie);
+
+ env->ReleaseStringUTFChars(path, path8);
+
+ return (res) ? (jint)cookie : 0;
+}
+
+static void android_content_AssetManager_dumpRes(JNIEnv* env, jobject clazz)
+{
+ AssetManager* am = assetManagerForJavaObject(env, clazz);
+ if (am == NULL) {
+ return;
+ }
+ am->dumpRes();
+}
+
// ----------------------------------------------------------------------------
/*
@@ -1642,6 +1785,8 @@ static JNINativeMethod gAssetManagerMethods[] = {
(void*) android_content_AssetManager_getArraySize },
{ "retrieveArray","(I[I)I",
(void*) android_content_AssetManager_retrieveArray },
+ { "setAttributeValue", "(III)V",
+ (void*) android_content_AssetManager_setAttributeValue },
// XML files.
{ "openXmlAssetNative", "(ILjava/lang/String;)I",
@@ -1666,6 +1811,17 @@ static JNINativeMethod gAssetManagerMethods[] = {
(void*) android_content_AssetManager_getAssetAllocations },
{ "getGlobalAssetManagerCount", "()I",
(void*) android_content_AssetManager_getGlobalAssetCount },
+
+ // Split theme package apk into two.
+ { "splitThemePackage","(Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;)I",
+ (void*) android_content_AssetManager_splitThemePackage },
+
+ { "removeAssetPath", "(Ljava/lang/String;Ljava/lang/String;)Z",
+ (void*) android_content_AssetManager_removeAssetPath },
+ { "updateResourcesWithAssetPath", "(Ljava/lang/String;)I",
+ (void*) android_content_AssetManager_updateResourcesWithAssetPath },
+ { "dumpResources", "()V",
+ (void*) android_content_AssetManager_dumpRes },
};
int register_android_content_AssetManager(JNIEnv* env)
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 7d6f158..f50cf2b 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -18,6 +18,7 @@
*/
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:pluto="http://www.w3.org/2001/pluto.html"
package="android" android:sharedUserId="android.uid.system"
android:sharedUserLabel="@string/android_system_label">
@@ -1134,7 +1135,8 @@
android:allowClearUserData="false"
android:backupAgent="com.android.server.SystemBackupAgent"
android:killAfterRestore="false"
- android:icon="@drawable/ic_launcher_android">
+ android:icon="@drawable/ic_launcher_android"
+ pluto:isThemeable="true">
<activity android:name="com.android.internal.app.ChooserActivity"
android:theme="@style/Theme.Dialog.Alert"
android:finishOnCloseSystemDialogs="true"
@@ -1210,6 +1212,18 @@
<category android:name="android.intent.category.MASTER_CLEAR" />
</intent-filter>
</receiver>
+
+ <receiver android:name="com.android.server.AppsLaunchFailureReceiver" >
+ <intent-filter>
+ <action android:name="com.tmobile.intent.action.APP_LAUNCH_FAILURE" />
+ <action android:name="com.tmobile.intent.action.APP_LAUNCH_FAILURE_RESET" />
+ <action android:name="android.intent.action.PACKAGE_ADDED" />
+ <action android:name="android.intent.action.PACKAGE_REMOVED" />
+ <action android:name="com.tmobile.intent.action.THEME_PACKAGE_UPDATED" />
+ <category android:name="com.tmobile.intent.category.THEME_PACKAGE_INSTALL_STATE_CHANGE" />
+ <data android:scheme="package" />
+ </intent-filter>
+ </receiver>
</application>
</manifest>
diff --git a/core/res/res/drawable/pluto_mall_icon.png b/core/res/res/drawable/pluto_mall_icon.png
new file mode 100755
index 0000000..8599f48
--- /dev/null
+++ b/core/res/res/drawable/pluto_mall_icon.png
Binary files differ
diff --git a/core/res/res/layout/list_menu_item_layout.xml b/core/res/res/layout/list_menu_item_layout.xml
index df4958f..06e9afd 100644
--- a/core/res/res/layout/list_menu_item_layout.xml
+++ b/core/res/res/layout/list_menu_item_layout.xml
@@ -36,11 +36,12 @@
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
- android:textAppearance="?android:attr/textAppearanceLargeInverse"
+ android:textAppearance="?android:attr/textAppearanceLarge"
android:singleLine="true"
android:duplicateParentState="true"
android:ellipsize="marquee"
- android:fadingEdge="horizontal" />
+ android:fadingEdge="horizontal"
+ style="?android:attr/listItemTextViewStyle" />
<TextView
android:id="@+id/shortcut"
@@ -48,9 +49,10 @@
android:layout_height="wrap_content"
android:layout_below="@id/title"
android:layout_alignParentLeft="true"
- android:textAppearance="?android:attr/textAppearanceSmallInverse"
+ android:textAppearance="?android:attr/textAppearanceSmall"
android:singleLine="true"
- android:duplicateParentState="true" />
+ android:duplicateParentState="true"
+ style="?android:attr/listItemTextViewStyle" />
</RelativeLayout>
diff --git a/core/res/res/layout/number_picker.xml b/core/res/res/layout/number_picker.xml
index bbdb31c..974130a 100644
--- a/core/res/res/layout/number_picker.xml
+++ b/core/res/res/layout/number_picker.xml
@@ -22,21 +22,18 @@
<com.android.internal.widget.NumberPickerButton android:id="@+id/increment"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
- android:background="@drawable/timepicker_up_btn" />
+ style="?android:attr/buttonStyleTimePickerUp" />
<EditText android:id="@+id/timepicker_input"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
- android:gravity="center"
android:singleLine="true"
- style="?android:attr/textAppearanceLargeInverse"
- android:textColor="@android:color/primary_text_light"
- android:textSize="30sp"
- android:background="@drawable/timepicker_input" />
+ style="?android:attr/timePickerInputStyle"
+ />
<com.android.internal.widget.NumberPickerButton android:id="@+id/decrement"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
- android:background="@drawable/timepicker_down_btn" />
+ style="?android:attr/buttonStyleTimePickerDown" />
</merge>
diff --git a/core/res/res/layout/search_dropdown_item_2line.xml b/core/res/res/layout/search_dropdown_item_2line.xml
new file mode 100644
index 0000000..05ca4fb
--- /dev/null
+++ b/core/res/res/layout/search_dropdown_item_2line.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/assets/res/any/layout/simple_spinner_item.xml
+**
+** Copyright 2008, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="?android:attr/listPreferredItemHeight"
+ android:orientation="horizontal"
+ android:gravity="center_vertical"
+ android:baselineAligned="false"
+ >
+
+ <TwoLineListItem
+ android:paddingTop="2dip"
+ android:paddingBottom="2dip"
+ android:layout_width="0dip"
+ android:layout_weight="1"
+ android:layout_height="wrap_content"
+ android:mode="twoLine" >
+
+ <TextView
+ android:id="@android:id/text1"
+ style="?android:attr/dropDownItemStyle"
+ android:textAppearance="?android:attr/textAppearanceMediumInverse"
+ android:textColor="@android:color/primary_text_light"
+ android:singleLine="true"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content" />
+
+ <TextView
+ android:id="@android:id/text2"
+ style="?android:attr/dropDownItemStyle"
+ android:textAppearance="?android:attr/textAppearanceSmallInverse"
+ android:textColor="@android:color/secondary_text_light"
+ android:singleLine="true"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_below="@android:id/text1"
+ android:layout_alignLeft="@android:id/text1" />
+
+ </TwoLineListItem>
+
+</LinearLayout>
diff --git a/core/res/res/layout/select_dialog.xml b/core/res/res/layout/select_dialog.xml
index 249b527..f9ae79a 100644
--- a/core/res/res/layout/select_dialog.xml
+++ b/core/res/res/layout/select_dialog.xml
@@ -29,6 +29,4 @@
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_marginTop="5px"
- android:cacheColorHint="@null"
- android:divider="@android:drawable/divider_horizontal_bright"
android:scrollbars="vertical" />
diff --git a/core/res/res/layout/select_dialog_item.xml b/core/res/res/layout/select_dialog_item.xml
index 60a74a4..977e089 100644
--- a/core/res/res/layout/select_dialog_item.xml
+++ b/core/res/res/layout/select_dialog_item.xml
@@ -29,9 +29,9 @@
android:layout_height="wrap_content"
android:minHeight="?android:attr/listPreferredItemHeight"
android:textAppearance="?android:attr/textAppearanceLarge"
- android:textColor="@android:color/primary_text_light_disable_only"
android:gravity="center_vertical"
android:paddingLeft="14dip"
android:paddingRight="15dip"
android:ellipsize="marquee"
+ style="?android:attr/listItemTextViewStyle"
/>
diff --git a/core/res/res/layout/select_dialog_multichoice.xml b/core/res/res/layout/select_dialog_multichoice.xml
index 55fc39b..5a5f317 100644
--- a/core/res/res/layout/select_dialog_multichoice.xml
+++ b/core/res/res/layout/select_dialog_multichoice.xml
@@ -24,7 +24,8 @@
android:gravity="center_vertical"
android:paddingLeft="12dip"
android:paddingRight="7dip"
- android:checkMark="@android:drawable/btn_check"
+ android:checkMark="?android:attr/listChoiceIndicatorMultiple"
android:ellipsize="marquee"
+ style="?android:attr/listItemTextViewStyle"
/>
diff --git a/core/res/res/layout/select_dialog_singlechoice.xml b/core/res/res/layout/select_dialog_singlechoice.xml
index 220af64..a51774f 100644
--- a/core/res/res/layout/select_dialog_singlechoice.xml
+++ b/core/res/res/layout/select_dialog_singlechoice.xml
@@ -20,10 +20,10 @@
android:layout_height="wrap_content"
android:minHeight="?android:attr/listPreferredItemHeight"
android:textAppearance="?android:attr/textAppearanceLarge"
- android:textColor="@android:color/primary_text_light_disable_only"
android:gravity="center_vertical"
android:paddingLeft="12dip"
android:paddingRight="7dip"
- android:checkMark="@android:drawable/btn_radio"
+ android:checkMark="?android:attr/listChoiceIndicatorSingle"
android:ellipsize="marquee"
+ style="?android:attr/listItemTextViewStyle"
/>
diff --git a/core/res/res/layout/simple_list_item_1.xml b/core/res/res/layout/simple_list_item_1.xml
index fe617ac..d720ce0 100644
--- a/core/res/res/layout/simple_list_item_1.xml
+++ b/core/res/res/layout/simple_list_item_1.xml
@@ -22,4 +22,5 @@
android:gravity="center_vertical"
android:paddingLeft="6dip"
android:minHeight="?android:attr/listPreferredItemHeight"
+ style="?android:attr/listItemTextViewStyle"
/>
diff --git a/core/res/res/layout/simple_list_item_2.xml b/core/res/res/layout/simple_list_item_2.xml
index b5e2385..535fade 100644
--- a/core/res/res/layout/simple_list_item_2.xml
+++ b/core/res/res/layout/simple_list_item_2.xml
@@ -29,6 +29,7 @@
android:layout_marginLeft="6dip"
android:layout_marginTop="6dip"
android:textAppearance="?android:attr/textAppearanceLarge"
+ style="?android:attr/listItemTextViewStyle"
/>
<TextView android:id="@android:id/text2"
@@ -37,6 +38,7 @@
android:layout_below="@android:id/text1"
android:layout_alignLeft="@android:id/text1"
android:textAppearance="?android:attr/textAppearanceSmall"
+ style="?android:attr/listItemTextViewStyle"
/>
</TwoLineListItem>
diff --git a/core/res/res/layout/status_bar_expanded.xml b/core/res/res/layout/status_bar_expanded.xml
index fd9d26e..34bb829 100644
--- a/core/res/res/layout/status_bar_expanded.xml
+++ b/core/res/res/layout/status_bar_expanded.xml
@@ -20,7 +20,6 @@
<com.android.server.status.ExpandedView xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
- android:background="@drawable/status_bar_background"
android:focusable="true"
android:descendantFocusability="afterDescendants">
@@ -67,12 +66,10 @@
android:layout_marginTop="4dp"
android:layout_marginBottom="1dp"
android:textSize="14sp"
- android:textColor="#ff000000"
android:text="@string/status_bar_clear_all_button"
- style="?android:attr/buttonStyle"
+ style="?android:attr/buttonStyleSmall"
android:paddingLeft="15dp"
android:paddingRight="15dp"
- android:background="@drawable/btn_default_small"
/>
</LinearLayout>
diff --git a/core/res/res/layout/status_bar_latest_event.xml b/core/res/res/layout/status_bar_latest_event.xml
index d524bb6..42ad37e 100644
--- a/core/res/res/layout/status_bar_latest_event.xml
+++ b/core/res/res/layout/status_bar_latest_event.xml
@@ -7,7 +7,6 @@
<com.android.server.status.LatestItemView android:id="@+id/content"
android:layout_width="fill_parent"
android:layout_height="64sp"
- android:background="@drawable/status_bar_item_background"
android:focusable="true"
android:clickable="true"
android:paddingRight="6sp"
@@ -16,8 +15,8 @@
<View
android:layout_width="fill_parent"
- android:layout_height="1sp"
- android:background="@drawable/divider_horizontal_bright"
+ android:layout_height="wrap_content"
+ android:background="?android:attr/listDivider"
/>
</LinearLayout>
diff --git a/core/res/res/layout/status_bar_latest_event_content.xml b/core/res/res/layout/status_bar_latest_event_content.xml
index eeb9d9d..d044db3 100644
--- a/core/res/res/layout/status_bar_latest_event_content.xml
+++ b/core/res/res/layout/status_bar_latest_event_content.xml
@@ -25,9 +25,8 @@
android:ellipsize="marquee"
android:fadingEdge="horizontal"
android:textStyle="bold"
- android:textSize="18sp"
android:paddingLeft="4dp"
- android:textColor="#ff000000" />
+ android:textAppearance="@style/TextAppearance.Medium" />
</LinearLayout>
<LinearLayout
android:layout_width="fill_parent"
@@ -38,11 +37,10 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
- android:textColor="#ff000000"
android:singleLine="true"
android:ellipsize="marquee"
android:fadingEdge="horizontal"
- android:textSize="14sp"
+ android:textAppearance="@style/TextAppearance.Small"
android:paddingLeft="4dp"
/>
<TextView android:id="@+id/time"
@@ -50,8 +48,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:singleLine="true"
- android:textSize="14sp"
android:paddingRight="5dp"
- android:textColor="#ff000000" />
+ android:textAppearance="@style/TextAppearance.Small" />
</LinearLayout>
</LinearLayout>
diff --git a/core/res/res/layout/tab_indicator.xml b/core/res/res/layout/tab_indicator.xml
index 71e4001..34f0e3e 100644
--- a/core/res/res/layout/tab_indicator.xml
+++ b/core/res/res/layout/tab_indicator.xml
@@ -15,13 +15,9 @@
-->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="0dip"
- android:layout_height="64dip"
- android:layout_weight="1"
- android:layout_marginLeft="-3dip"
- android:layout_marginRight="-3dip"
android:orientation="vertical"
- android:background="@android:drawable/tab_indicator">
+ style="?android:attr/tabIndicatorStyle"
+ >
<ImageView android:id="@+id/icon"
android:layout_width="wrap_content"
@@ -34,7 +30,9 @@
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
- style="?android:attr/tabWidgetStyle"
+ android:ellipsize="marquee"
+ android:singleLine="true"
+ android:textAppearance="?android:attr/textAppearanceTab"
/>
</RelativeLayout>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 81da739..8ed1780 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -153,8 +153,25 @@
<!-- ToggleButton style. -->
<attr name="buttonStyleToggle" format="reference" />
+
+ <!-- TimePicker Button styles. -->
+ <attr name="buttonStyleTimePickerUp" format="reference" />
+ <attr name="buttonStyleTimePickerDown" format="reference" />
<!-- ============== -->
+ <!-- Tab styles -->
+ <!-- ============== -->
+ <eat-comment />
+
+ <!-- Style for the inflated indicator widget itself, not the text or
+ image views typically contained within. -->
+ <attr name="tabIndicatorStyle" format="reference" />
+
+ <!-- Style for the text label on the default indicator. Previously
+ was lumped with tabWidgetStyle. -->
+ <attr name="textAppearanceTab" format="reference" />
+
+ <!-- ============== -->
<!-- Gallery styles -->
<!-- ============== -->
<eat-comment />
@@ -176,6 +193,8 @@
<attr name="listDivider" format="reference" />
<!-- TextView style for list separators. -->
<attr name="listSeparatorTextViewStyle" format="reference" />
+ <!-- TextView style for regular list items. -->
+ <attr name="listItemTextViewStyle" format="reference" />
<!-- The preferred left padding for an expandable list item (for child-specific layouts,
use expandableListPreferredChildPaddingLeft). This takes into account
the indicator that will be shown to next to the item. -->
@@ -302,6 +321,21 @@
<attr name="windowNoDisplay" format="boolean" />
<!-- ============ -->
+ <!-- General Dialog theme -->
+ <!-- ============ -->
+ <eat-comment />
+ <attr name="dialogTheme" format="reference" />
+ <attr name="alertDialogTheme" format="reference" />
+ <attr name="searchDialogTheme" format="reference" />
+
+ <!-- ============ -->
+ <!-- Menu theme -->
+ <!-- ============ -->
+ <eat-comment />
+ <attr name="iconMenuTheme" format="reference" />
+ <attr name="expandedMenuTheme" format="reference" />
+
+ <!-- ============ -->
<!-- Alert Dialog styles -->
<!-- ============ -->
<eat-comment />
@@ -338,6 +372,8 @@
<attr name="dropDownListViewStyle" format="reference" />
<!-- Default EditText style. -->
<attr name="editTextStyle" format="reference" />
+ <!-- Default TimePicker Input style. -->
+ <attr name="timePickerInputStyle" format="reference" />
<!-- Default ExpandableListView style. -->
<attr name="expandableListViewStyle" format="reference" />
<!-- Default Gallery style. -->
@@ -446,6 +482,17 @@
<attr name="ringtonePreferenceStyle" format="reference" />
<!-- The preference layout that has the child/tabbed effect. -->
<attr name="preferenceLayoutChild" format="reference" />
+
+ <!-- =================== -->
+ <!-- DigitalClock attributes -->
+ <!-- =================== -->
+ <attr name="menuItemBackground" format="reference" />
+
+ <!-- =================== -->
+ <!-- status bar related attributes -->
+ <!-- =================== -->
+ <attr name="com_android_server_status_expandedView" format="reference" />
+ <attr name="com_android_server_status_latestItemView" format="reference" />
</declare-styleable>
@@ -1722,6 +1769,8 @@
<!-- When set to false, the ListView will not draw the divider before each footer view.
The default value is true. -->
<attr name="footerDividersEnabled" format="boolean" />
+ <!-- Drawable used to colorize an item's background in the list. -->
+ <attr name="listItemBackground" format="color|reference" />
</declare-styleable>
<declare-styleable name="MenuView">
<!-- Default appearance of menu item text. -->
@@ -1842,6 +1891,10 @@
<attr name="layout_span" format="integer" />
</declare-styleable>
<declare-styleable name="TabWidget">
+ <!-- Bottom-left tab strip. -->
+ <attr name="bottomLeftStrip" format="reference" />
+ <!-- Bottom-right tab strip. -->
+ <attr name="bottomRightStrip" format="reference" />
</declare-styleable>
<declare-styleable name="TextAppearance">
<!-- Text color. -->
@@ -2330,6 +2383,8 @@
value is false. See
{@link android.graphics.drawable.Drawable#setVisible}. -->
<attr name="visible" format="boolean" />
+ <!-- Set a tinting color -->
+ <attr name="tint" />
</declare-styleable>
<declare-styleable name="StateListDrawable">
@@ -2447,6 +2502,7 @@
<attr name="bottom" />
<attr name="drawable" />
<attr name="id" />
+ <attr name="tint" />
</declare-styleable>
<declare-styleable name="LevelListDrawableItem">
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 5eb1c8e..549f76f 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1205,4 +1205,31 @@
<public type="attr" name="wallpaperAuthor" />
<public type="attr" name="wallpaperDescription" />
+
+<!-- ===============================================================
+ Resources added to support dynamic theming.
+ =============================================================== -->
+ <eat-comment />
+
+ <public type="style" name="Widget.TabIndicator" />
+ <public type="style" name="Widget.EditText.TimePicker" />
+
+ <public type="attr" name="listItemBackground" />
+
+ <public type="attr" name="dialogTheme" />
+ <public type="attr" name="alertDialogTheme" />
+ <public type="attr" name="searchDialogTheme" />
+ <public type="attr" name="listItemTextViewStyle" />
+ <public type="attr" name="bottomLeftStrip" />
+ <public type="attr" name="bottomRightStrip" />
+ <public type="attr" name="tabIndicatorStyle" />
+ <public type="attr" name="textAppearanceTab" />
+
+ <public type="attr" name="timePickerInputStyle" />
+ <public type="attr" name="buttonStyleTimePickerUp" />
+ <public type="attr" name="buttonStyleTimePickerDown" />
+ <public type="attr" name="menuItemBackground" />
+ <public type="attr" name="expandedMenuTheme" />
+ <public type="attr" name="iconMenuTheme" />
+
</resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index de30fe7..2ad1b22 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -2100,4 +2100,9 @@
<string name="l2tp_vpn_description">Layer 2 Tunneling Protocol</string>
<string name="l2tp_ipsec_psk_vpn_description">Pre-shared key based L2TP/IPSec VPN</string>
<string name="l2tp_ipsec_crt_vpn_description">Certificate based L2TP/IPSec VPN</string>
+
+ <string name="ringtone_button_done">Done</string>
+ <string name="ringtone_button_cancel">Cancel</string>
+ <string name="ringtone_header">Select Ringtone</string>
+ <string name="buy_ringtones">Buy Ringtones</string>
</resources>
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index 6e38138..b13a21a 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -192,6 +192,14 @@
<item name="android:textColor">?android:attr/textColorPrimary</item>
</style>
+ <style name="com_android_server_status_ExpandedView">
+ <item name="android:background">@android:drawable/status_bar_background</item>
+ </style>
+
+ <style name="com_android_server_status_LatestItemView">
+ <item name="android:background">@android:drawable/list_selector_background</item>
+ </style>
+
<!-- Widget Styles -->
<style name="Widget">
@@ -378,6 +386,13 @@
<item name="android:background">@android:drawable/light_header_dither</item>
</style>
+ <style name="Widget.TextView.ListItem">
+ </style>
+
+ <style name="Widget.TextView.ListItem.White">
+ <item name="android:textColor">@android:color/primary_text_light</item>
+ </style>
+
<style name="Widget.EditText">
<item name="android:focusable">true</item>
<item name="android:focusableInTouchMode">true</item>
@@ -388,12 +403,29 @@
<item name="android:gravity">center_vertical</item>
</style>
+ <style name="Widget.EditText.TimePicker">
+ <item name="android:background">@android:drawable/timepicker_input</item>
+ <item name="android:textAppearance">?android:attr/textAppearanceLargeInverse</item>
+ <item name="android:gravity">center</item>
+ <item name="android:textSize">30sp</item>
+ </style>
+
<style name="Widget.ExpandableListView" parent="Widget.ListView">
<item name="android:groupIndicator">@android:drawable/expander_group</item>
<item name="android:indicatorLeft">?android:attr/expandableListPreferredItemIndicatorLeft</item>
<item name="android:indicatorRight">?android:attr/expandableListPreferredItemIndicatorRight</item>
<item name="android:childDivider">@android:drawable/divider_horizontal_dark_opaque</item>
</style>
+
+ <style name="Widget.ExpandableListView.White" parent="Widget.ListView.White">
+ <item name="android:groupIndicator">@android:drawable/expander_group</item>
+ <item name="android:indicatorLeft">?android:attr/expandableListPreferredItemIndicatorLeft</item>
+ <item name="android:indicatorRight">?android:attr/expandableListPreferredItemIndicatorRight</item>
+ <item name="android:childDivider">@android:drawable/divider_horizontal_bright</item>
+ </style>
+
+ <style name="Widget.ExpandableListView.Dialog" parent="Widget.ExpandableListView.White">
+ </style>
<style name="Widget.ImageWell">
<item name="android:background">@android:drawable/panel_picture_frame_background</item>
@@ -413,6 +445,7 @@
<item name="android:background">@android:drawable/edit_text</item>
<item name="android:completionHintView">@android:layout/simple_dropdown_hint</item>
<item name="android:textAppearance">?android:attr/textAppearanceMediumInverse</item>
+ <item name="android:textColor">@android:color/primary_text_light</item>
<item name="android:gravity">center_vertical</item>
<item name="android:completionThreshold">2</item>
<item name="android:dropDownSelector">@android:drawable/list_selector_background</item>
@@ -469,6 +502,15 @@
<item name="android:divider">@android:drawable/divider_horizontal_bright_opaque</item>
</style>
+ <style name="Widget.ListView.Dialog" parent="Widget.ListView.White">
+ <item name="textColorPrimary">@android:color/primary_text_light</item>
+ <item name="textColorSecondary">@android:color/secondary_text_light</item>
+ <item name="textColorTertiary">@android:color/tertiary_text_light</item>
+ <item name="textColorPrimaryInverse">@android:color/primary_text_dark</item>
+ <item name="textColorSecondaryInverse">@android:color/secondary_text_dark</item>
+ <item name="textColorTertiaryInverse">@android:color/tertiary_text_dark</item>
+ </style>
+
<style name="Widget.ListView.DropDown">
<item name="android:cacheColorHint">@null</item>
<item name="android:divider">@android:drawable/divider_horizontal_bright_opaque</item>
@@ -493,9 +535,17 @@
</style>
<style name="Widget.TabWidget">
- <item name="android:textAppearance">@style/TextAppearance.Widget.TabWidget</item>
- <item name="ellipsize">marquee</item>
- <item name="singleLine">true</item>
+ <item name="android:bottomLeftStrip">@android:drawable/tab_bottom_left</item>
+ <item name="android:bottomRightStrip">@android:drawable/tab_bottom_right</item>
+ </style>
+
+ <style name="Widget.TabIndicator">
+ <item name="android:layout_width">0px</item>
+ <item name="android:layout_weight">1</item>
+ <item name="android:layout_height">64dp</item>
+ <item name="android:layout_marginLeft">-3dp</item>
+ <item name="android:layout_marginRight">-3dp</item>
+ <item name="android:background">@android:drawable/tab_indicator</item>
</style>
<style name="Widget.Gallery">
@@ -798,4 +848,13 @@
<item name="android:paddingBottom">1dip</item>
<item name="android:background">@android:drawable/bottom_bar</item>
</style>
+
+ <style name="TimePickerUpButton">
+ <item name="android:background">@android:drawable/timepicker_up_btn</item>
+ </style>
+
+ <style name="TimePickerDownButton">
+ <item name="android:background">@android:drawable/timepicker_down_btn</item>
+ </style>
+
</resources>
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index 17ea66a..47f597f 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -26,7 +26,7 @@
of it a dark color.
-->
<style name="Theme">
-
+
<item name="colorForeground">@android:color/bright_foreground_dark</item>
<item name="colorForegroundInverse">@android:color/bright_foreground_dark_inverse</item>
<item name="colorBackground">@android:color/background_dark</item>
@@ -77,6 +77,9 @@
<item name="buttonStyleInset">@android:style/Widget.Button.Inset</item>
<item name="buttonStyleToggle">@android:style/Widget.Button.Toggle</item>
+
+ <item name="buttonStyleTimePickerUp">@android:style/TimePickerUpButton</item>
+ <item name="buttonStyleTimePickerDown">@android:style/TimePickerDownButton</item>
<!-- List attributes -->
<item name="listPreferredItemHeight">64dip</item>
@@ -84,6 +87,7 @@
<item name="searchResultListItemHeight">58dip</item>
<item name="listDivider">@drawable/divider_horizontal_dark</item>
<item name="listSeparatorTextViewStyle">@android:style/Widget.TextView.ListSeparator</item>
+ <item name="listItemTextViewStyle">@android:style/Widget.TextView.ListItem</item>
<item name="listChoiceIndicatorSingle">@android:drawable/btn_radio</item>
<item name="listChoiceIndicatorMultiple">@android:drawable/btn_check</item>
@@ -117,7 +121,14 @@
<item name="android:windowSoftInputMode">stateUnspecified|adjustUnspecified</item>
<!-- Dialog attributes -->
+ <item name="dialogTheme">@android:style/Theme.Dialog</item>
+ <item name="alertDialogTheme">@android:style/Theme.Dialog.Alert</item>
<item name="alertDialogStyle">@android:style/AlertDialog</item>
+ <item name="searchDialogTheme">@android:style/Theme.SearchBar</item>
+
+ <!-- Menu attributes -->
+ <item name="iconMenuTheme">@android:style/Theme.IconMenu</item>
+ <item name="expandedMenuTheme">@android:style/Theme.ExpandedMenu</item>
<!-- Panel attributes -->
<item name="panelBackground">@android:drawable/menu_background</item>
@@ -135,12 +146,20 @@
<item name="scrollbarTrackHorizontal">@null</item>
<item name="scrollbarTrackVertical">@null</item>
+ <!-- DigitalClock attributes -->
+ <item name="menuItemBackground">@android:drawable/menuitem_background</item>
+
+ <!-- status bar related attributes -->
+ <item name="com_android_server_status_expandedView">@style/com_android_server_status_ExpandedView</item>
+ <item name="com_android_server_status_latestItemView">@style/com_android_server_status_LatestItemView</item>
+
<!-- Widget styles -->
<item name="absListViewStyle">@android:style/Widget.AbsListView</item>
<item name="autoCompleteTextViewStyle">@android:style/Widget.AutoCompleteTextView</item>
<item name="checkboxStyle">@android:style/Widget.CompoundButton.CheckBox</item>
<item name="dropDownListViewStyle">@android:style/Widget.ListView.DropDown</item>
<item name="editTextStyle">@android:style/Widget.EditText</item>
+ <item name="timePickerInputStyle">@android:style/Widget.EditText.TimePicker</item>
<item name="expandableListViewStyle">@android:style/Widget.ExpandableListView</item>
<item name="galleryStyle">@android:style/Widget.Gallery</item>
<item name="gestureOverlayViewStyle">@android:style/Widget.GestureOverlayView</item>
@@ -196,6 +215,12 @@
<!-- Search widget styles -->
<item name="searchWidgetCorpusItemBackground">@android:color/search_widget_corpus_item_background</item>
+
+ <!-- Style for the inflated indicator widget itself, not the text or
+ image views typically contained within. -->
+ <item name="tabIndicatorStyle">@android:style/Widget.TabIndicator</item>
+ <item name="textAppearanceTab">@android:style/TextAppearance.Widget.TabWidget</item>
+
</style>
<!-- Variant of the default (dark) theme with no title bar -->
@@ -251,6 +276,7 @@
<item name="progressBarStyleInverse">@android:style/Widget.ProgressBar</item>
<item name="progressBarStyleSmallInverse">@android:style/Widget.ProgressBar.Small</item>
<item name="progressBarStyleLargeInverse">@android:style/Widget.ProgressBar.Large</item>
+
</style>
<!-- Variant of the light theme with no title bar -->
@@ -421,6 +447,19 @@
<item name="windowTitleStyle">@android:style/DialogWindowTitle</item>
<item name="windowIsFloating">true</item>
<item name="windowContentOverlay">@null</item>
+
+ <!-- Use light themes for various components. -->
+ <item name="listViewStyle">@android:style/Widget.ListView.Dialog</item>
+ <item name="expandableListViewStyle">@android:style/Widget.ExpandableListView.Dialog</item>
+ <item name="listDivider">@drawable/divider_horizontal_bright</item>
+ <item name="listSeparatorTextViewStyle">@android:style/Widget.TextView.ListSeparator.White</item>
+ <item name="listItemTextViewStyle">@android:style/Widget.TextView.ListItem.White</item>
+ <item name="colorBackground">@android:color/white</item>
+ <item name="cacheColorHint">@android:color/white</item>
+
+ <item name="android:timePickerInputStyle">@android:style/Widget.EditText.TimePicker</item>
+ <item name="android:buttonStyleTimePickerUp">@android:style/TimePickerUpButton</item>
+ <item name="android:buttonStyleTimePickerDown">@android:style/TimePickerDownButton</item>
</style>
<!-- Default dark theme for panel windows. This removes all extraneous
diff --git a/data/etc/platform.xml b/data/etc/platform.xml
index 7322e6c..5cf2f40 100644
--- a/data/etc/platform.xml
+++ b/data/etc/platform.xml
@@ -72,6 +72,11 @@
<group gid="diag" />
</permission>
+ <!-- Permissions to read DRM-protected theme resources. -->
+ <permission name="com.tmobile.permission.ACCESS_DRM_THEME" >
+ <group gid="theme_manager" />
+ </permission>
+
<!-- ================================================================== -->
<!-- ================================================================== -->
<!-- ================================================================== -->
diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java
index 6a7b2d1..3af7222 100644
--- a/graphics/java/android/graphics/drawable/Drawable.java
+++ b/graphics/java/android/graphics/drawable/Drawable.java
@@ -811,6 +811,11 @@ public abstract class Drawable {
TypedArray a = r.obtainAttributes(attrs, com.android.internal.R.styleable.Drawable);
inflateWithAttributes(r, parser, a, com.android.internal.R.styleable.Drawable_visible);
+ int tint = a.getColor(com.android.internal.R.styleable.Drawable_tint, 0);
+ if (tint != 0) {
+ setColorFilter(tint, PorterDuff.Mode.SRC_ATOP);
+ }
+
a.recycle();
}
diff --git a/graphics/java/android/graphics/drawable/GradientDrawable.java b/graphics/java/android/graphics/drawable/GradientDrawable.java
index 91a2bc1..8f18047 100644
--- a/graphics/java/android/graphics/drawable/GradientDrawable.java
+++ b/graphics/java/android/graphics/drawable/GradientDrawable.java
@@ -783,8 +783,9 @@ public class GradientDrawable extends Drawable {
setCornerRadii(new float[] {
topLeftRadius, topLeftRadius,
topRightRadius, topRightRadius,
- bottomLeftRadius, bottomLeftRadius,
- bottomRightRadius, bottomRightRadius
+ bottomRightRadius, bottomRightRadius,
+ bottomLeftRadius, bottomLeftRadius
+
});
}
a.recycle();
diff --git a/graphics/java/android/graphics/drawable/LayerDrawable.java b/graphics/java/android/graphics/drawable/LayerDrawable.java
index 389fd40..40770d8 100644
--- a/graphics/java/android/graphics/drawable/LayerDrawable.java
+++ b/graphics/java/android/graphics/drawable/LayerDrawable.java
@@ -41,6 +41,7 @@ import java.io.IOException;
* @attr ref android.R.styleable#LayerDrawableItem_bottom
* @attr ref android.R.styleable#LayerDrawableItem_drawable
* @attr ref android.R.styleable#LayerDrawableItem_id
+ * @attr ref android.R.styleable#LayerDrawableItem_tint
*/
public class LayerDrawable extends Drawable implements Drawable.Callback {
LayerState mLayerState;
@@ -136,6 +137,12 @@ public class LayerDrawable extends Drawable implements Drawable.Callback {
com.android.internal.R.styleable.LayerDrawableItem_drawable, 0);
int id = a.getResourceId(com.android.internal.R.styleable.LayerDrawableItem_id,
View.NO_ID);
+ int tint = a.getColor(com.android.internal.R.styleable.LayerDrawableItem_tint, 0);
+ ColorFilter colorFilter = null;
+ if (tint != 0) {
+ colorFilter = new PorterDuffColorFilter(tint, PorterDuff.Mode.SRC_ATOP);
+ android.util.Log.d("Themes", "Setting tint=" + tint + " for drawable res=" + drawableRes + " (colorFilter=" + colorFilter + ")");
+ }
a.recycle();
@@ -152,8 +159,8 @@ public class LayerDrawable extends Drawable implements Drawable.Callback {
}
dr = Drawable.createFromXmlInner(r, parser, attrs);
}
-
- addLayer(dr, id, left, top, right, bottom);
+
+ addLayer(dr, id, left, top, right, bottom, colorFilter);
}
ensurePadding();
@@ -169,8 +176,10 @@ public class LayerDrawable extends Drawable implements Drawable.Callback {
* @param top The top padding of the new layer.
* @param right The right padding of the new layer.
* @param bottom The bottom padding of the new layer.
+ * @param colorFilter Optional color filter for the new layer.
*/
- private void addLayer(Drawable layer, int id, int left, int top, int right, int bottom) {
+ private void addLayer(Drawable layer, int id, int left, int top, int right, int bottom,
+ ColorFilter colorFilter) {
final LayerState st = mLayerState;
int N = st.mChildren != null ? st.mChildren.length : 0;
int i = st.mNum;
@@ -192,6 +201,7 @@ public class LayerDrawable extends Drawable implements Drawable.Callback {
childDrawable.mInsetT = top;
childDrawable.mInsetR = right;
childDrawable.mInsetB = bottom;
+ childDrawable.mColorFilter = colorFilter;
st.mNum++;
layer.setCallback(this);
@@ -317,6 +327,11 @@ public class LayerDrawable extends Drawable implements Drawable.Callback {
final ChildDrawable[] array = mLayerState.mChildren;
final int N = mLayerState.mNum;
for (int i=0; i<N; i++) {
+ if (array[i].mColorFilter != null) {
+ android.util.Log.d("Themes", "Applying colorFilter=" +
+ array[i].mColorFilter + " to " + array[i].mDrawable);
+ array[i].mDrawable.setColorFilter(array[i].mColorFilter);
+ }
array[i].mDrawable.draw(canvas);
}
}
@@ -545,6 +560,7 @@ public class LayerDrawable extends Drawable implements Drawable.Callback {
public Drawable mDrawable;
public int mInsetL, mInsetT, mInsetR, mInsetB;
public int mId;
+ public ColorFilter mColorFilter;
}
static class LayerState extends ConstantState {
@@ -588,6 +604,7 @@ public class LayerDrawable extends Drawable implements Drawable.Callback {
r.mInsetR = or.mInsetR;
r.mInsetB = or.mInsetB;
r.mId = or.mId;
+ r.mColorFilter = or.mColorFilter;
}
mHaveOpacity = orig.mHaveOpacity;
diff --git a/include/utils/AssetManager.h b/include/utils/AssetManager.h
index d8994e0..a609230 100644
--- a/include/utils/AssetManager.h
+++ b/include/utils/AssetManager.h
@@ -61,8 +61,8 @@ public:
virtual ~AssetManager(void);
static int32_t getGlobalCount();
-
- /*
+
+ /*
* Add a new source for assets. This can be called multiple times to
* look in multiple places for assets. It can be either a directory (for
* finding assets as raw files on the disk) or a ZIP file. This newly
@@ -75,13 +75,13 @@ public:
*/
bool addAssetPath(const String8& path, void** cookie);
- /*
+ /*
* Convenience for adding the standard system assets. Uses the
* ANDROID_ROOT environment variable to find them.
*/
bool addDefaultAssets();
- /*
+ /*
* Iterate over the asset paths in this manager. (Previously
* added via addAssetPath() and addDefaultAssets().) On first call,
* 'cookie' must be NULL, resulting in the first cookie being returned.
@@ -90,7 +90,7 @@ public:
*/
void* nextAssetPath(void* cookie) const;
- /*
+ /*
* Return an asset path in the manager. 'which' must be between 0 and
* countAssetPaths().
*/
@@ -172,7 +172,7 @@ public:
*/
FileType getFileType(const char* fileName);
- /*
+ /*
* Return the complete resource table to find things in the package.
*/
const ResTable& getResources(bool required = true) const;
@@ -191,12 +191,23 @@ public:
* the current data.
*/
bool isUpToDate();
-
+
/**
* Get the known locales for this asset manager object.
*/
void getLocales(Vector<String8>* locales) const;
+ /*
+ * Remove existing source for assets. It can be either a directory (for
+ * deleting assets as raw files on the disk) or a ZIP file.
+ * Also, updates the ResTable object to reflect the change.
+ *
+ * Returns "true" on success, "false" on failure.
+ */
+ bool removeAssetPath(const String8 &packageName, const String8 &assetPath);
+ bool updateWithAssetPath(const String8& path, void** cookie);
+ void dumpRes();
+
private:
struct asset_path
{
@@ -204,6 +215,7 @@ private:
FileType type;
};
+ void updateResTableFromAssetPath(ResTable *rt, const asset_path& ap, void *cookie) const;
Asset* openInPathLocked(const char* fileName, AccessMode mode,
const asset_path& path);
Asset* openNonAssetInPathLocked(const char* fileName, AccessMode mode,
@@ -255,7 +267,7 @@ private:
ResTable* setResourceTable(ResTable* res);
bool isUpToDate();
-
+
protected:
~SharedZip();
@@ -302,7 +314,7 @@ private:
static String8 getPathName(const char* path);
bool isUpToDate();
-
+
private:
void closeZip(int idx);
diff --git a/include/utils/ResourceTypes.h b/include/utils/ResourceTypes.h
index 49145e8..a9dddaa 100644
--- a/include/utils/ResourceTypes.h
+++ b/include/utils/ResourceTypes.h
@@ -1733,6 +1733,7 @@ public:
status_t applyStyle(uint32_t resID, bool force=false);
status_t setTo(const Theme& other);
+ void setAttributeValue(uint32_t attribute, uint32_t value);
/**
* Retrieve a value in the theme. If the theme defines this
@@ -1885,9 +1886,12 @@ public:
void getLocales(Vector<String8>* locales) const;
+ void removeAssetsByCookie(const String8 &packageName, void* cookie);
+
#ifndef HAVE_ANDROID_OS
void print(bool inclValues) const;
#endif
+ void dump() const;
private:
struct Header;
diff --git a/include/utils/ZipEntry.h b/include/utils/ZipEntry.h
new file mode 100644
index 0000000..7f721b4
--- /dev/null
+++ b/include/utils/ZipEntry.h
@@ -0,0 +1,345 @@
+/*
+ * 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.
+ */
+
+//
+// Zip archive entries.
+//
+// The ZipEntry class is tightly meshed with the ZipFile class.
+//
+#ifndef __LIBS_ZIPENTRY_H
+#define __LIBS_ZIPENTRY_H
+
+#include <utils/Errors.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+
+namespace android {
+
+class ZipFile;
+
+/*
+ * ZipEntry objects represent a single entry in a Zip archive.
+ *
+ * You can use one of these to get or set information about an entry, but
+ * there are no functions here for accessing the data itself. (We could
+ * tuck a pointer to the ZipFile in here for convenience, but that raises
+ * the likelihood of using ZipEntry objects after discarding the ZipFile.)
+ *
+ * File information is stored in two places: next to the file data (the Local
+ * File Header, and possibly a Data Descriptor), and at the end of the file
+ * (the Central Directory Entry). The two must be kept in sync.
+ */
+class ZipEntry {
+public:
+ friend class ZipFile;
+
+ ZipEntry(void)
+ : mDeleted(false), mMarked(false)
+ {}
+ ~ZipEntry(void) {}
+
+ /*
+ * Returns "true" if the data is compressed.
+ */
+ bool isCompressed(void) const {
+ return mCDE.mCompressionMethod != kCompressStored;
+ }
+ int getCompressionMethod(void) const { return mCDE.mCompressionMethod; }
+
+ /*
+ * Return the uncompressed length.
+ */
+ off_t getUncompressedLen(void) const { return mCDE.mUncompressedSize; }
+
+ /*
+ * Return the compressed length. For uncompressed data, this returns
+ * the same thing as getUncompresesdLen().
+ */
+ off_t getCompressedLen(void) const { return mCDE.mCompressedSize; }
+
+ /*
+ * Return the absolute file offset of the start of the compressed or
+ * uncompressed data.
+ */
+ off_t getFileOffset(void) const {
+ return mCDE.mLocalHeaderRelOffset +
+ LocalFileHeader::kLFHLen +
+ mLFH.mFileNameLength +
+ mLFH.mExtraFieldLength;
+ }
+
+ /*
+ * Return the data CRC.
+ */
+ unsigned long getCRC32(void) const { return mCDE.mCRC32; }
+
+ /*
+ * Return file modification time in UNIX seconds-since-epoch.
+ */
+ time_t getModWhen(void) const;
+
+ /*
+ * Return the archived file name.
+ */
+ const char* getFileName(void) const { return (const char*) mCDE.mFileName; }
+
+ /*
+ * Application-defined "mark". Can be useful when synchronizing the
+ * contents of an archive with contents on disk.
+ */
+ bool getMarked(void) const { return mMarked; }
+ void setMarked(bool val) { mMarked = val; }
+
+ /*
+ * Some basic functions for raw data manipulation. "LE" means
+ * Little Endian.
+ */
+ static inline unsigned short getShortLE(const unsigned char* buf) {
+ return buf[0] | (buf[1] << 8);
+ }
+ static inline unsigned long getLongLE(const unsigned char* buf) {
+ return buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
+ }
+ static inline void putShortLE(unsigned char* buf, short val) {
+ buf[0] = (unsigned char) val;
+ buf[1] = (unsigned char) (val >> 8);
+ }
+ static inline void putLongLE(unsigned char* buf, long val) {
+ buf[0] = (unsigned char) val;
+ buf[1] = (unsigned char) (val >> 8);
+ buf[2] = (unsigned char) (val >> 16);
+ buf[3] = (unsigned char) (val >> 24);
+ }
+
+ /* defined for Zip archives */
+ enum {
+ kCompressStored = 0, // no compression
+ // shrunk = 1,
+ // reduced 1 = 2,
+ // reduced 2 = 3,
+ // reduced 3 = 4,
+ // reduced 4 = 5,
+ // imploded = 6,
+ // tokenized = 7,
+ kCompressDeflated = 8, // standard deflate
+ // Deflate64 = 9,
+ // lib imploded = 10,
+ // reserved = 11,
+ // bzip2 = 12,
+ };
+
+ /*
+ * Deletion flag. If set, the entry will be removed on the next
+ * call to "flush".
+ */
+ bool getDeleted(void) const { return mDeleted; }
+
+protected:
+ /*
+ * Initialize the structure from the file, which is pointing at
+ * our Central Directory entry.
+ */
+ status_t initFromCDE(FILE* fp);
+
+ /*
+ * Initialize the structure for a new file. We need the filename
+ * and comment so that we can properly size the LFH area. The
+ * filename is mandatory, the comment is optional.
+ */
+ void initNew(const char* fileName, const char* comment);
+
+ /*
+ * Initialize the structure with the contents of a ZipEntry from
+ * another file.
+ */
+ status_t initFromExternal(const ZipFile* pZipFile, const ZipEntry* pEntry);
+
+ /*
+ * Add some pad bytes to the LFH. We do this by adding or resizing
+ * the "extra" field.
+ */
+ status_t addPadding(int padding);
+
+ /*
+ * Set information about the data for this entry.
+ */
+ void setDataInfo(long uncompLen, long compLen, unsigned long crc32,
+ int compressionMethod);
+
+ /*
+ * Set the modification date.
+ */
+ void setModWhen(time_t when);
+
+ /*
+ * Return the offset of the local file header.
+ */
+ off_t getLFHOffset(void) const { return mCDE.mLocalHeaderRelOffset; }
+
+ /*
+ * Set the offset of the local file header, relative to the start of
+ * the current file.
+ */
+ void setLFHOffset(off_t offset) {
+ mCDE.mLocalHeaderRelOffset = (long) offset;
+ }
+
+ /* mark for deletion; used by ZipFile::remove() */
+ void setDeleted(void) { mDeleted = true; }
+
+private:
+ /* these are private and not defined */
+ ZipEntry(const ZipEntry& src);
+ ZipEntry& operator=(const ZipEntry& src);
+
+ /* returns "true" if the CDE and the LFH agree */
+ bool compareHeaders(void) const;
+ void copyCDEtoLFH(void);
+
+ bool mDeleted; // set if entry is pending deletion
+ bool mMarked; // app-defined marker
+
+ /*
+ * Every entry in the Zip archive starts off with one of these.
+ */
+ class LocalFileHeader {
+ public:
+ LocalFileHeader(void) :
+ mVersionToExtract(0),
+ mGPBitFlag(0),
+ mCompressionMethod(0),
+ mLastModFileTime(0),
+ mLastModFileDate(0),
+ mCRC32(0),
+ mCompressedSize(0),
+ mUncompressedSize(0),
+ mFileNameLength(0),
+ mExtraFieldLength(0),
+ mFileName(NULL),
+ mExtraField(NULL)
+ {}
+ virtual ~LocalFileHeader(void) {
+ delete[] mFileName;
+ delete[] mExtraField;
+ }
+
+ status_t read(FILE* fp);
+ status_t write(FILE* fp);
+
+ // unsigned long mSignature;
+ unsigned short mVersionToExtract;
+ unsigned short mGPBitFlag;
+ unsigned short mCompressionMethod;
+ unsigned short mLastModFileTime;
+ unsigned short mLastModFileDate;
+ unsigned long mCRC32;
+ unsigned long mCompressedSize;
+ unsigned long mUncompressedSize;
+ unsigned short mFileNameLength;
+ unsigned short mExtraFieldLength;
+ unsigned char* mFileName;
+ unsigned char* mExtraField;
+
+ enum {
+ kSignature = 0x04034b50,
+ kLFHLen = 30, // LocalFileHdr len, excl. var fields
+ };
+
+ void dump(void) const;
+ };
+
+ /*
+ * Every entry in the Zip archive has one of these in the "central
+ * directory" at the end of the file.
+ */
+ class CentralDirEntry {
+ public:
+ CentralDirEntry(void) :
+ mVersionMadeBy(0),
+ mVersionToExtract(0),
+ mGPBitFlag(0),
+ mCompressionMethod(0),
+ mLastModFileTime(0),
+ mLastModFileDate(0),
+ mCRC32(0),
+ mCompressedSize(0),
+ mUncompressedSize(0),
+ mFileNameLength(0),
+ mExtraFieldLength(0),
+ mFileCommentLength(0),
+ mDiskNumberStart(0),
+ mInternalAttrs(0),
+ mExternalAttrs(0),
+ mLocalHeaderRelOffset(0),
+ mFileName(NULL),
+ mExtraField(NULL),
+ mFileComment(NULL)
+ {}
+ virtual ~CentralDirEntry(void) {
+ delete[] mFileName;
+ delete[] mExtraField;
+ delete[] mFileComment;
+ }
+
+ status_t read(FILE* fp);
+ status_t write(FILE* fp);
+
+ // unsigned long mSignature;
+ unsigned short mVersionMadeBy;
+ unsigned short mVersionToExtract;
+ unsigned short mGPBitFlag;
+ unsigned short mCompressionMethod;
+ unsigned short mLastModFileTime;
+ unsigned short mLastModFileDate;
+ unsigned long mCRC32;
+ unsigned long mCompressedSize;
+ unsigned long mUncompressedSize;
+ unsigned short mFileNameLength;
+ unsigned short mExtraFieldLength;
+ unsigned short mFileCommentLength;
+ unsigned short mDiskNumberStart;
+ unsigned short mInternalAttrs;
+ unsigned long mExternalAttrs;
+ unsigned long mLocalHeaderRelOffset;
+ unsigned char* mFileName;
+ unsigned char* mExtraField;
+ unsigned char* mFileComment;
+
+ void dump(void) const;
+
+ enum {
+ kSignature = 0x02014b50,
+ kCDELen = 46, // CentralDirEnt len, excl. var fields
+ };
+ };
+
+ enum {
+ //kDataDescriptorSignature = 0x08074b50, // currently unused
+ kDataDescriptorLen = 16, // four 32-bit fields
+
+ kDefaultVersion = 20, // need deflate, nothing much else
+ kDefaultMadeBy = 0x0317, // 03=UNIX, 17=spec v2.3
+ kUsesDataDescr = 0x0008, // GPBitFlag bit 3
+ };
+
+ LocalFileHeader mLFH;
+ CentralDirEntry mCDE;
+};
+
+}; // namespace android
+
+#endif // __LIBS_ZIPENTRY_H
diff --git a/include/utils/ZipFile.h b/include/utils/ZipFile.h
new file mode 100644
index 0000000..dbbd072
--- /dev/null
+++ b/include/utils/ZipFile.h
@@ -0,0 +1,270 @@
+/*
+ * 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.
+ */
+
+//
+// General-purpose Zip archive access. This class allows both reading and
+// writing to Zip archives, including deletion of existing entries.
+//
+#ifndef __LIBS_ZIPFILE_H
+#define __LIBS_ZIPFILE_H
+
+#include <utils/Vector.h>
+#include <utils/Errors.h>
+#include <stdio.h>
+
+#include "ZipEntry.h"
+
+namespace android {
+
+/*
+ * Manipulate a Zip archive.
+ *
+ * Some changes will not be visible in the until until "flush" is called.
+ *
+ * The correct way to update a file archive is to make all changes to a
+ * copy of the archive in a temporary file, and then unlink/rename over
+ * the original after everything completes. Because we're only interested
+ * in using this for packaging, we don't worry about such things. Crashing
+ * after making changes and before flush() completes could leave us with
+ * an unusable Zip archive.
+ */
+class ZipFile {
+public:
+ ZipFile(void)
+ : mZipFp(NULL), mReadOnly(false), mNeedCDRewrite(false)
+ {}
+ ~ZipFile(void) {
+ if (!mReadOnly)
+ flush();
+ if (mZipFp != NULL)
+ fclose(mZipFp);
+ discardEntries();
+ }
+
+ /*
+ * Open a new or existing archive.
+ */
+ typedef enum {
+ kOpenReadOnly = 0x01,
+ kOpenReadWrite = 0x02,
+ kOpenCreate = 0x04, // create if it doesn't exist
+ kOpenTruncate = 0x08, // if it exists, empty it
+ };
+ status_t open(const char* zipFileName, int flags);
+
+ /*
+ * Add a file to the end of the archive. Specify whether you want the
+ * library to try to store it compressed.
+ *
+ * If "storageName" is specified, the archive will use that instead
+ * of "fileName".
+ *
+ * If there is already an entry with the same name, the call fails.
+ * Existing entries with the same name must be removed first.
+ *
+ * If "ppEntry" is non-NULL, a pointer to the new entry will be returned.
+ */
+ status_t add(const char* fileName, int compressionMethod,
+ ZipEntry** ppEntry)
+ {
+ return add(fileName, fileName, compressionMethod, ppEntry);
+ }
+ status_t add(const char* fileName, const char* storageName,
+ int compressionMethod, ZipEntry** ppEntry)
+ {
+ return addCommon(fileName, NULL, 0, storageName,
+ ZipEntry::kCompressStored,
+ compressionMethod, ppEntry);
+ }
+
+ /*
+ * Add a file that is already compressed with gzip.
+ *
+ * If "ppEntry" is non-NULL, a pointer to the new entry will be returned.
+ */
+ status_t addGzip(const char* fileName, const char* storageName,
+ ZipEntry** ppEntry)
+ {
+ return addCommon(fileName, NULL, 0, storageName,
+ ZipEntry::kCompressDeflated,
+ ZipEntry::kCompressDeflated, ppEntry);
+ }
+
+ /*
+ * Add a file from an in-memory data buffer.
+ *
+ * If "ppEntry" is non-NULL, a pointer to the new entry will be returned.
+ */
+ status_t add(const void* data, size_t size, const char* storageName,
+ int compressionMethod, ZipEntry** ppEntry)
+ {
+ return addCommon(NULL, data, size, storageName,
+ ZipEntry::kCompressStored,
+ compressionMethod, ppEntry);
+ }
+
+ /*
+ * Add an entry by copying it from another zip file. If "padding" is
+ * nonzero, the specified number of bytes will be added to the "extra"
+ * field in the header.
+ *
+ * If "ppEntry" is non-NULL, a pointer to the new entry will be returned.
+ */
+ status_t add(const ZipFile* pSourceZip, const ZipEntry* pSourceEntry,
+ int padding, ZipEntry** ppEntry);
+
+ /*
+ * Mark an entry as having been removed. It is not actually deleted
+ * from the archive or our internal data structures until flush() is
+ * called.
+ */
+ status_t remove(ZipEntry* pEntry);
+
+ /*
+ * Flush changes. If mNeedCDRewrite is set, this writes the central dir.
+ */
+ status_t flush(void);
+
+ /*
+ * Expand the data into the buffer provided. The buffer must hold
+ * at least <uncompressed len> bytes. Variation expands directly
+ * to a file.
+ *
+ * Returns "false" if an error was encountered in the compressed data.
+ */
+ //bool uncompress(const ZipEntry* pEntry, void* buf) const;
+ //bool uncompress(const ZipEntry* pEntry, FILE* fp) const;
+ void* uncompress(const ZipEntry* pEntry);
+
+ /*
+ * Get an entry, by name. Returns NULL if not found.
+ *
+ * Does not return entries pending deletion.
+ */
+ ZipEntry* getEntryByName(const char* fileName) const;
+
+ /*
+ * Get the Nth entry in the archive.
+ *
+ * This will return an entry that is pending deletion.
+ */
+ int getNumEntries(void) const { return mEntries.size(); }
+ ZipEntry* getEntryByIndex(int idx) const;
+
+private:
+ /* these are private and not defined */
+ ZipFile(const ZipFile& src);
+ ZipFile& operator=(const ZipFile& src);
+
+ class EndOfCentralDir {
+ public:
+ EndOfCentralDir(void) :
+ mDiskNumber(0),
+ mDiskWithCentralDir(0),
+ mNumEntries(0),
+ mTotalNumEntries(0),
+ mCentralDirSize(0),
+ mCentralDirOffset(0),
+ mCommentLen(0),
+ mComment(NULL)
+ {}
+ virtual ~EndOfCentralDir(void) {
+ delete[] mComment;
+ }
+
+ status_t readBuf(const unsigned char* buf, int len);
+ status_t write(FILE* fp);
+
+ //unsigned long mSignature;
+ unsigned short mDiskNumber;
+ unsigned short mDiskWithCentralDir;
+ unsigned short mNumEntries;
+ unsigned short mTotalNumEntries;
+ unsigned long mCentralDirSize;
+ unsigned long mCentralDirOffset; // offset from first disk
+ unsigned short mCommentLen;
+ unsigned char* mComment;
+
+ enum {
+ kSignature = 0x06054b50,
+ kEOCDLen = 22, // EndOfCentralDir len, excl. comment
+
+ kMaxCommentLen = 65535, // longest possible in ushort
+ kMaxEOCDSearch = kMaxCommentLen + EndOfCentralDir::kEOCDLen,
+
+ };
+
+ void dump(void) const;
+ };
+
+
+ /* read all entries in the central dir */
+ status_t readCentralDir(void);
+
+ /* crunch deleted entries out */
+ status_t crunchArchive(void);
+
+ /* clean up mEntries */
+ void discardEntries(void);
+
+ /* common handler for all "add" functions */
+ status_t addCommon(const char* fileName, const void* data, size_t size,
+ const char* storageName, int sourceType, int compressionMethod,
+ ZipEntry** ppEntry);
+
+ /* copy all of "srcFp" into "dstFp" */
+ status_t copyFpToFp(FILE* dstFp, FILE* srcFp, unsigned long* pCRC32);
+ /* copy all of "data" into "dstFp" */
+ status_t copyDataToFp(FILE* dstFp,
+ const void* data, size_t size, unsigned long* pCRC32);
+ /* copy some of "srcFp" into "dstFp" */
+ status_t copyPartialFpToFp(FILE* dstFp, FILE* srcFp, long length,
+ unsigned long* pCRC32);
+ /* like memmove(), but on parts of a single file */
+ status_t filemove(FILE* fp, off_t dest, off_t src, size_t n);
+ /* compress all of "srcFp" into "dstFp", using Deflate */
+ status_t compressFpToFp(FILE* dstFp, FILE* srcFp,
+ const void* data, size_t size, unsigned long* pCRC32);
+
+ /* get modification date from a file descriptor */
+ time_t getModTime(int fd);
+
+ /*
+ * We use stdio FILE*, which gives us buffering but makes dealing
+ * with files >2GB awkward. Until we support Zip64, we're fine.
+ */
+ FILE* mZipFp; // Zip file pointer
+
+ /* one of these per file */
+ EndOfCentralDir mEOCD;
+
+ /* did we open this read-only? */
+ bool mReadOnly;
+
+ /* set this when we trash the central dir */
+ bool mNeedCDRewrite;
+
+ /*
+ * One ZipEntry per entry in the zip file. I'm using pointers instead
+ * of objects because it's easier than making operator= work for the
+ * classes and sub-classes.
+ */
+ Vector<ZipEntry*> mEntries;
+};
+
+}; // namespace android
+
+#endif // __LIBS_ZIPFILE_H
diff --git a/libs/utils/Android.mk b/libs/utils/Android.mk
index 59409a2..1e3c190 100644
--- a/libs/utils/Android.mk
+++ b/libs/utils/Android.mk
@@ -41,6 +41,8 @@ commonSources:= \
ZipFileCRO.cpp \
ZipFileRO.cpp \
ZipUtils.cpp \
+ ../../tools/aapt/ZipFile.cpp \
+ ../../tools/aapt/ZipEntry.cpp \
misc.cpp
diff --git a/libs/utils/AssetManager.cpp b/libs/utils/AssetManager.cpp
index 5a05e6a..058c76c 100644
--- a/libs/utils/AssetManager.cpp
+++ b/libs/utils/AssetManager.cpp
@@ -122,7 +122,7 @@ bool AssetManager::addAssetPath(const String8& path, void** cookie)
return true;
}
}
-
+
LOGV("In %p Asset %s path: %s", this,
ap.type == kFileTypeDirectory ? "dir" : "zip", ap.path.string());
@@ -185,7 +185,7 @@ void AssetManager::setLocaleLocked(const char* locale)
delete[] mLocale;
}
mLocale = strdupNew(locale);
-
+
updateResourceParamsLocked();
}
@@ -392,79 +392,87 @@ const ResTable* AssetManager::getResTable(bool required) const
if (mCacheMode != CACHE_OFF && !mCacheValid)
const_cast<AssetManager*>(this)->loadFileNameCacheLocked();
- const size_t N = mAssetPaths.size();
- for (size_t i=0; i<N; i++) {
- Asset* ass = NULL;
- ResTable* sharedRes = NULL;
- bool shared = true;
- const asset_path& ap = mAssetPaths.itemAt(i);
- LOGV("Looking for resource asset in '%s'\n", ap.path.string());
- if (ap.type != kFileTypeDirectory) {
- if (i == 0) {
- // The first item is typically the framework resources,
- // which we want to avoid parsing every time.
- sharedRes = const_cast<AssetManager*>(this)->
- mZipSet.getZipResourceTable(ap.path);
- }
- if (sharedRes == NULL) {
+ mResources = rt = new ResTable();
+
+ if (rt) {
+ const size_t N = mAssetPaths.size();
+ for (size_t i=0; i<N; i++) {
+ const asset_path& ap = mAssetPaths.itemAt(i);
+ updateResTableFromAssetPath(rt, ap, (void*)(i+1));
+ }
+ }
+
+ if (required && !rt) LOGW("Unable to find resources file resources.arsc");
+ if (!rt) {
+ mResources = rt = new ResTable();
+ }
+
+ return rt;
+}
+
+void AssetManager::updateResTableFromAssetPath(ResTable *rt, const asset_path& ap, void *cookie) const
+{
+ Asset* ass = NULL;
+ ResTable* sharedRes = NULL;
+ bool shared = true;
+ size_t cookiePos = (size_t)cookie;
+ LOGV("Looking for resource asset in '%s'\n", ap.path.string());
+ if (ap.type != kFileTypeDirectory) {
+ if (cookiePos == 1) {
+ // The first item is typically the framework resources,
+ // which we want to avoid parsing every time.
+ sharedRes = const_cast<AssetManager*>(this)->
+ mZipSet.getZipResourceTable(ap.path);
+ }
+ if (sharedRes == NULL) {
+ ass = const_cast<AssetManager*>(this)->
+ mZipSet.getZipResourceTableAsset(ap.path);
+ if (ass == NULL) {
+ LOGV("loading resource table %s\n", ap.path.string());
ass = const_cast<AssetManager*>(this)->
- mZipSet.getZipResourceTableAsset(ap.path);
- if (ass == NULL) {
- LOGV("loading resource table %s\n", ap.path.string());
+ openNonAssetInPathLocked("resources.arsc",
+ Asset::ACCESS_BUFFER,
+ ap);
+ if (ass != NULL && ass != kExcludedAsset) {
ass = const_cast<AssetManager*>(this)->
- openNonAssetInPathLocked("resources.arsc",
- Asset::ACCESS_BUFFER,
- ap);
- if (ass != NULL && ass != kExcludedAsset) {
- ass = const_cast<AssetManager*>(this)->
- mZipSet.setZipResourceTableAsset(ap.path, ass);
- }
- }
-
- if (i == 0 && ass != NULL) {
- // If this is the first resource table in the asset
- // manager, then we are going to cache it so that we
- // can quickly copy it out for others.
- LOGV("Creating shared resources for %s", ap.path.string());
- sharedRes = new ResTable();
- sharedRes->add(ass, (void*)(i+1), false);
- sharedRes = const_cast<AssetManager*>(this)->
- mZipSet.setZipResourceTable(ap.path, sharedRes);
+ mZipSet.setZipResourceTableAsset(ap.path, ass);
}
}
- } else {
- LOGV("loading resource table %s\n", ap.path.string());
- Asset* ass = const_cast<AssetManager*>(this)->
- openNonAssetInPathLocked("resources.arsc",
- Asset::ACCESS_BUFFER,
- ap);
- shared = false;
- }
- if ((ass != NULL || sharedRes != NULL) && ass != kExcludedAsset) {
- if (rt == NULL) {
- mResources = rt = new ResTable();
- updateResourceParamsLocked();
- }
- LOGV("Installing resource asset %p in to table %p\n", ass, mResources);
- if (sharedRes != NULL) {
- LOGV("Copying existing resources for %s", ap.path.string());
- rt->add(sharedRes);
- } else {
- LOGV("Parsing resources for %s", ap.path.string());
- rt->add(ass, (void*)(i+1), !shared);
- }
- if (!shared) {
- delete ass;
+ if (cookiePos == 0 && ass != NULL) {
+ // If this is the first resource table in the asset
+ // manager, then we are going to cache it so that we
+ // can quickly copy it out for others.
+ LOGV("Creating shared resources for %s", ap.path.string());
+ sharedRes = new ResTable();
+ sharedRes->add(ass, cookie, false);
+ sharedRes = const_cast<AssetManager*>(this)->
+ mZipSet.setZipResourceTable(ap.path, sharedRes);
}
}
+ } else {
+ LOGV("loading resource table %s\n", ap.path.string());
+ Asset* ass = const_cast<AssetManager*>(this)->
+ openNonAssetInPathLocked("resources.arsc",
+ Asset::ACCESS_BUFFER,
+ ap);
+ shared = false;
}
+ if ((ass != NULL || sharedRes != NULL) && ass != kExcludedAsset) {
+ updateResourceParamsLocked();
+ LOGV("Installing resource asset %p in to table %p\n", ass, mResources);
+ if (sharedRes != NULL) {
+ LOGV("Copying existing resources for %s", ap.path.string());
+ rt->add(sharedRes);
+ } else {
+ LOGV("Parsing resources for %s", ap.path.string());
+ rt->add(ass, cookie, !shared);
+ }
- if (required && !rt) LOGW("Unable to find resources file resources.arsc");
- if (!rt) {
- mResources = rt = new ResTable();
+ if (!shared) {
+ delete ass;
+ }
}
- return rt;
}
void AssetManager::updateResourceParamsLocked() const
@@ -617,7 +625,7 @@ Asset* AssetManager::openInLocaleVendorLocked(const char* fileName, AccessMode m
/* look at the filesystem on disk */
String8 path(createPathNameLocked(ap, locale, vendor));
path.appendPath(fileName);
-
+
String8 excludeName(path);
excludeName.append(kExcludeExtension);
if (::getFileType(excludeName.string()) != kFileTypeNonexistent) {
@@ -625,28 +633,28 @@ Asset* AssetManager::openInLocaleVendorLocked(const char* fileName, AccessMode m
//printf("+++ excluding '%s'\n", (const char*) excludeName);
return kExcludedAsset;
}
-
+
pAsset = openAssetFromFileLocked(path, mode);
-
+
if (pAsset == NULL) {
/* try again, this time with ".gz" */
path.append(".gz");
pAsset = openAssetFromFileLocked(path, mode);
}
-
+
if (pAsset != NULL)
pAsset->setAssetSource(path);
} else {
/* find in cache */
String8 path(createPathNameLocked(ap, locale, vendor));
path.appendPath(fileName);
-
+
AssetDir::FileInfo tmpInfo;
bool found = false;
-
+
String8 excludeName(path);
excludeName.append(kExcludeExtension);
-
+
if (mCache.indexOf(excludeName) != NAME_NOT_FOUND) {
/* go no farther */
//printf("+++ Excluding '%s'\n", (const char*) excludeName);
@@ -1465,7 +1473,7 @@ bool AssetManager::fncScanAndMergeDirLocked(
// XXX This is broken -- the filename cache needs to hold the base
// asset path separately from its filename.
-
+
partialPath = createPathNameLocked(ap, locale, vendor);
if (dirName[0] != '\0') {
partialPath.appendPath(dirName);
@@ -1759,3 +1767,58 @@ int AssetManager::ZipSet::getIndex(const String8& zip) const
return mZipPath.size()-1;
}
+bool AssetManager::updateWithAssetPath(const String8& path, void** cookie)
+{
+ bool res = addAssetPath(path, cookie);
+ ResTable* rt = mResources;
+ if (res && rt != NULL && ((size_t)*cookie == mAssetPaths.size())) {
+ AutoMutex _l(mLock);
+ const asset_path& ap = mAssetPaths.itemAt((size_t)*cookie - 1);
+ updateResTableFromAssetPath(rt, ap, *cookie);
+ }
+ return res;
+}
+
+bool AssetManager::removeAssetPath(const String8 &packageName, const String8 &assetPath)
+{
+ AutoMutex _l(mLock);
+
+ String8 realPath(assetPath);
+ if (kAppZipName) {
+ realPath.appendPath(kAppZipName);
+ }
+
+ // Check if the path exists.
+ size_t cookie = 0;
+ for (size_t i = 0; i < mAssetPaths.size(); i++) {
+ if (strcmp(mAssetPaths[i].path, realPath) == 0) {
+ mAssetPaths.removeAt(i);
+ cookie = i + 1;
+ break;
+ }
+ }
+
+ if (cookie == 0) {
+ return false;
+ }
+
+ ResTable* rt = mResources;
+ if (rt == NULL) {
+ LOGV("ResTable must not be NULL");
+ return false;
+ }
+
+ rt->removeAssetsByCookie(packageName, (void *)cookie);
+
+ return true;
+}
+
+void AssetManager::dumpRes()
+{
+ ResTable* rt = mResources;
+ if (rt == NULL) {
+ fprintf(stderr, "ResTable must not be NULL");
+ return;
+ }
+ rt->dump();
+}
diff --git a/libs/utils/ResourceTypes.cpp b/libs/utils/ResourceTypes.cpp
index 872b2bc..5725ffa 100644
--- a/libs/utils/ResourceTypes.cpp
+++ b/libs/utils/ResourceTypes.cpp
@@ -62,6 +62,8 @@ namespace android {
#endif
#endif
+#define PACKAGE_RESOURCE_ID_TO_DUMP 10
+
static void printToLogFunc(void* cookie, const char* txt)
{
LOGV("%s", txt);
@@ -1304,6 +1306,29 @@ ResTable::Theme::package_info* ResTable::Theme::copy_package(package_info* pi)
return newpi;
}
+void ResTable::Theme::setAttributeValue(uint32_t attrID, uint32_t value)
+{
+ const ssize_t p = mTable.getResourcePackageIndex(attrID);
+ const uint32_t t = Res_GETTYPE(attrID);
+ const uint32_t e = Res_GETENTRY(attrID);
+
+ TABLE_NOISY(LOGV("Looking up attr 0x%08x in theme %p", attrID, this));
+
+ if (p >= 0) {
+ const package_info* const pi = mPackages[p];
+ if (pi != NULL) {
+ if (t < pi->numTypes) {
+ const type_info& ti = pi->types[t];
+ if (e < ti.numEntries) {
+ theme_entry& te = ti.entries[e];
+ te.value.data = value;
+ te.value.dataType = Res_value::TYPE_FIRST_INT;
+ }
+ }
+ }
+ }
+}
+
status_t ResTable::Theme::applyStyle(uint32_t resID, bool force)
{
const bag_entry* bag;
@@ -3889,9 +3914,61 @@ status_t ResTable::parsePackage(const ResTable_package* const pkg,
return NO_ERROR;
}
-#ifndef HAVE_ANDROID_OS
+void ResTable::removeAssetsByCookie(const String8 &packageName, void* cookie)
+{
+ mError = NO_ERROR;
+
+ size_t N = mHeaders.size();
+ for (size_t i = 0; i < N; i++) {
+ Header* header = mHeaders[i];
+ if ((size_t)header->cookie == (size_t)cookie) {
+ if (header->ownedData != NULL) {
+ free(header->ownedData);
+ }
+ mHeaders.removeAt(i);
+ break;
+ }
+ }
+ size_t pgCount = mPackageGroups.size();
+ for (size_t pgIndex = 0; pgIndex < pgCount; pgIndex++) {
+ PackageGroup* pg = mPackageGroups[pgIndex];
+
+ size_t pkgCount = pg->packages.size();
+ size_t index = pkgCount;
+ for (size_t pkgIndex = 0; pkgIndex < pkgCount; pkgIndex++) {
+ const Package* pkg = pg->packages[pkgIndex];
+ if (String8(String16(pkg->package->name)).compare(packageName) == 0) {
+ index = pkgIndex;
+ LOGV("Delete Package %d id=%d name=%s\n",
+ (int)pkgIndex, pkg->package->id,
+ String8(String16(pkg->package->name)).string());
+ break;
+ }
+ }
+ if (index < pkgCount) {
+ const Package* pkg = pg->packages[index];
+ uint32_t id = dtohl(pkg->package->id);
+ if (id != 0 && id < 256) {
+ mPackageMap[id] = 0;
+ }
+ pg->packages.removeAt(index);
+ delete pkg;
+ if (pkgCount == 1) {
+ LOGV("Delete Package Group %d id=%d packageCount=%d name=%s\n",
+ (int)pgIndex, pg->id, (int)pg->packages.size(),
+ String8(pg->name).string());
+ mPackageGroups.removeAt(pgIndex);
+ }
+ delete pg;
+ return;
+ }
+ }
+}
+
#define CHAR16_TO_CSTR(c16, len) (String8(String16(c16,len)).string())
+#ifndef HAVE_ANDROID_OS
+
#define CHAR16_ARRAY_EQ(constant, var, len) \
((len == (sizeof(constant)/sizeof(constant[0]))) && (0 == memcmp((var), (constant), (len))))
@@ -4165,4 +4242,158 @@ void ResTable::print(bool inclValues) const
#endif // HAVE_ANDROID_OS
+void ResTable::dump() const
+{
+ LOGI("mError=0x%x (%s)\n", mError, strerror(mError));
+#if 0
+ LOGI("mParams=%c%c-%c%c,\n",
+ mParams.language[0], mParams.language[1],
+ mParams.country[0], mParams.country[1]);
+#endif
+ size_t pgCount = mPackageGroups.size();
+ LOGI("Package Groups (%d)\n", (int)pgCount);
+ for (size_t pgIndex=0; pgIndex<pgCount; pgIndex++) {
+ const PackageGroup* pg = mPackageGroups[pgIndex];
+ LOGI("Package Group %d id=%d packageCount=%d name=%s\n",
+ (int)pgIndex, pg->id, (int)pg->packages.size(),
+ String8(pg->name).string());
+
+ size_t pkgCount = pg->packages.size();
+ for (size_t pkgIndex=0; pkgIndex<pkgCount; pkgIndex++) {
+ const Package* pkg = pg->packages[pkgIndex];
+ if (pkg->package->id != PACKAGE_RESOURCE_ID_TO_DUMP) continue; // HACK!
+ size_t count = 0;
+ size_t typeCount = pkg->types.size();
+ LOGI(" Package %d id=%d name=%s typeCount=%d\n", (int)pkgIndex,
+ pkg->package->id, String8(String16(pkg->package->name)).string(),
+ (int)typeCount);
+ for (size_t typeIndex=0; typeIndex<typeCount&&count<10; typeIndex++) {
+ const Type* typeConfigs = pkg->getType(typeIndex);
+ if (typeConfigs == NULL) {
+ LOGI(" type %d NULL\n", (int)typeIndex);
+ continue;
+ }
+ const size_t NTC = typeConfigs->configs.size();
+ LOGI(" type %d configCount=%d entryCount=%d\n",
+ (int)typeIndex, (int)NTC, (int)typeConfigs->entryCount);
+ if (typeConfigs->typeSpecFlags != NULL) {
+ for (size_t entryIndex=0; entryIndex<typeConfigs->entryCount&&count<10; entryIndex++) {
+ uint32_t resID = (0xff000000 & ((pkg->package->id)<<24))
+ | (0x00ff0000 & ((typeIndex+1)<<16))
+ | (0x0000ffff & (entryIndex));
+ resource_name resName;
+ this->getResourceName(resID, &resName);
+ count++;
+ LOGI(" spec resource 0x%08x %s:%s/%s: flags=0x%08x\n",
+ resID,
+ CHAR16_TO_CSTR(resName.package, resName.packageLen),
+ CHAR16_TO_CSTR(resName.type, resName.typeLen),
+ CHAR16_TO_CSTR(resName.name, resName.nameLen),
+ dtohl(typeConfigs->typeSpecFlags[entryIndex]));
+ }
+ }
+ for (size_t configIndex=0; configIndex<NTC&&count<10; configIndex++) {
+ const ResTable_type* type = typeConfigs->configs[configIndex];
+ if ((((uint64_t)type)&0x3) != 0) {
+ LOGI(" NON-INTEGER ResTable_type ADDRESS: %p\n", type);
+ continue;
+ }
+ count++;
+ LOGI(" config %d lang=%c%c cnt=%c%c orien=%d touch=%d density=%d key=%d infl=%d nav=%d w=%d h=%d\n",
+ (int)configIndex,
+ type->config.language[0] ? type->config.language[0] : '-',
+ type->config.language[1] ? type->config.language[1] : '-',
+ type->config.country[0] ? type->config.country[0] : '-',
+ type->config.country[1] ? type->config.country[1] : '-',
+ type->config.orientation,
+ type->config.touchscreen,
+ dtohs(type->config.density),
+ type->config.keyboard,
+ type->config.inputFlags,
+ type->config.navigation,
+ dtohs(type->config.screenWidth),
+ dtohs(type->config.screenHeight));
+ size_t entryCount = dtohl(type->entryCount);
+ uint32_t entriesStart = dtohl(type->entriesStart);
+ if ((entriesStart&0x3) != 0) {
+ LOGI(" NON-INTEGER ResTable_type entriesStart OFFSET: %p\n", (void*)entriesStart);
+ continue;
+ }
+ uint32_t typeSize = dtohl(type->header.size);
+ if ((typeSize&0x3) != 0) {
+ LOGI(" NON-INTEGER ResTable_type header.size: %p\n", (void*)typeSize);
+ continue;
+ }
+ for (size_t entryIndex=0; entryIndex<entryCount&&count<10; entryIndex++) {
+ const uint8_t* const end = ((const uint8_t*)type)
+ + dtohl(type->header.size);
+ const uint32_t* const eindex = (const uint32_t*)
+ (((const uint8_t*)type) + dtohs(type->header.headerSize));
+ uint32_t thisOffset = dtohl(eindex[entryIndex]);
+ if (thisOffset == ResTable_type::NO_ENTRY) {
+ continue;
+ }
+
+ uint32_t resID = (0xff000000 & ((pkg->package->id)<<24))
+ | (0x00ff0000 & ((typeIndex+1)<<16))
+ | (0x0000ffff & (entryIndex));
+ resource_name resName;
+ this->getResourceName(resID, &resName);
+ count++;
+ LOGI(" resource 0x%08x %s:%s/%s: ", resID,
+ CHAR16_TO_CSTR(resName.package, resName.packageLen),
+ CHAR16_TO_CSTR(resName.type, resName.typeLen),
+ CHAR16_TO_CSTR(resName.name, resName.nameLen));
+ if ((thisOffset&0x3) != 0) {
+ LOGI("NON-INTEGER OFFSET: %p\n", (void*)thisOffset);
+ continue;
+ }
+ if ((thisOffset+sizeof(ResTable_entry)) > typeSize) {
+ LOGI("OFFSET OUT OF BOUNDS: %p+%p (size is %p)\n",
+ (void*)entriesStart, (void*)thisOffset,
+ (void*)typeSize);
+ continue;
+ }
+
+ const ResTable_entry* ent = (const ResTable_entry*)
+ (((const uint8_t*)type) + entriesStart + thisOffset);
+ if (((entriesStart + thisOffset)&0x3) != 0) {
+ LOGI("NON-INTEGER ResTable_entry OFFSET: %p\n",
+ (void*)(entriesStart + thisOffset));
+ continue;
+ }
+ if ((dtohs(ent->flags)&ResTable_entry::FLAG_COMPLEX) != 0) {
+ LOGI("<bag>");
+ } else {
+ uint16_t esize = dtohs(ent->size);
+ if ((esize&0x3) != 0) {
+ LOGI("NON-INTEGER ResTable_entry SIZE: %p\n", (void*)esize);
+ continue;
+ }
+ if ((thisOffset+esize) > typeSize) {
+ LOGI("ResTable_entry OUT OF BOUNDS: %p+%p+%p (size is %p)\n",
+ (void*)entriesStart, (void*)thisOffset,
+ (void*)esize, (void*)typeSize);
+ continue;
+ }
+
+ const Res_value* value = (const Res_value*)
+ (((const uint8_t*)ent) + esize);
+ count++;
+ LOGI("t=0x%02x d=0x%08x (s=0x%04x r=0x%02x)",
+ (int)value->dataType, (int)dtohl(value->data),
+ (int)dtohs(value->size), (int)value->res0);
+ }
+
+ if ((dtohs(ent->flags)&ResTable_entry::FLAG_PUBLIC) != 0) {
+ LOGI(" (PUBLIC)");
+ }
+ LOGI("\n");
+ }
+ }
+ }
+ }
+ }
+}
+
} // namespace android
diff --git a/media/java/android/media/Ringtone.java b/media/java/android/media/Ringtone.java
index e80d8aa..0529db7 100644
--- a/media/java/android/media/Ringtone.java
+++ b/media/java/android/media/Ringtone.java
@@ -20,8 +20,6 @@ import android.content.ContentResolver;
import android.content.Context;
import android.content.res.AssetFileDescriptor;
import android.database.Cursor;
-import android.media.AudioManager;
-import android.media.MediaPlayer;
import android.net.Uri;
import android.provider.DrmStore;
import android.provider.MediaStore;
@@ -54,7 +52,7 @@ public class Ringtone {
DrmStore.Audio.DATA,
DrmStore.Audio.TITLE
};
-
+
private MediaPlayer mAudio;
private Uri mUri;
@@ -110,6 +108,19 @@ public class Ringtone {
if (mTitle != null) return mTitle;
return mTitle = getTitle(context, mUri, true);
}
+
+ private static String stringForQuery(Cursor cursor) {
+ if (cursor != null) {
+ try {
+ if (cursor.moveToFirst()) {
+ return cursor.getString(0);
+ }
+ } finally {
+ cursor.close();
+ }
+ }
+ return null;
+ }
private static String getTitle(Context context, Uri uri, boolean followSettingsUri) {
Cursor cursor = null;
@@ -129,14 +140,21 @@ public class Ringtone {
.getString(com.android.internal.R.string.ringtone_default_with_actual,
actualTitle);
}
+ } else if (RingtoneManager.THEME_AUTHORITY.equals(authority)) {
+ Uri themes = Uri.parse("content://com.tmobile.thememanager.themes/themes");
+ title = stringForQuery(res.query(themes, new String[] { "ringtone_name" },
+ "ringtone_uri = ?", new String[] { uri.toString() }, null));
+ if (title == null) {
+ title = stringForQuery(res.query(themes, new String[] { "notif_ringtone_name" },
+ "notif_ringtone_uri = ?", new String[] { uri.toString() }, null));
+ }
} else {
-
if (DrmStore.AUTHORITY.equals(authority)) {
cursor = res.query(uri, DRM_COLUMNS, null, null, null);
} else if (MediaStore.AUTHORITY.equals(authority)) {
cursor = res.query(uri, MEDIA_COLUMNS, null, null, null);
}
-
+
if (cursor != null && cursor.getCount() == 1) {
cursor.moveToFirst();
return cursor.getString(2);
diff --git a/media/java/android/media/RingtoneManager.java b/media/java/android/media/RingtoneManager.java
index 8481410..7878071 100644
--- a/media/java/android/media/RingtoneManager.java
+++ b/media/java/android/media/RingtoneManager.java
@@ -21,8 +21,8 @@ import com.android.internal.database.SortCursor;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.app.Activity;
-import android.content.ContentUris;
import android.content.Context;
+import android.content.Intent;
import android.content.res.AssetFileDescriptor;
import android.database.Cursor;
import android.net.Uri;
@@ -53,6 +53,11 @@ public class RingtoneManager {
private static final String TAG = "RingtoneManager";
+ /**
+ * @hide
+ */
+ public static final String ACTION_RINGTONE_CHANGED = "com.tmobile.intent.action.RINGTONE_CHANGED";
+
// Make sure these are in sync with attrs.xml:
// <attr name="ringtoneType">
@@ -112,6 +117,17 @@ public class RingtoneManager {
"android.intent.extra.ringtone.SHOW_SILENT";
/**
+ * Given to the ringtone picker as a boolean. Whether to show an item for
+ * "Buy ringtones".
+ *
+ * @see #ACTION_RINGTONE_PICKER
+ *
+ * @hide
+ */
+ public static final String EXTRA_RINGTONE_SHOW_BUY =
+ "com.tmobile.intent.extra.ringtone.SHOW_BUY";
+
+ /**
* Given to the ringtone picker as a boolean. Whether to include DRM ringtones.
*/
public static final String EXTRA_RINGTONE_INCLUDE_DRM =
@@ -175,26 +191,28 @@ public class RingtoneManager {
public static final String EXTRA_RINGTONE_PICKED_URI =
"android.intent.extra.ringtone.PICKED_URI";
+ static final String THEME_AUTHORITY = "com.tmobile.thememanager.packageresources";
+
// Make sure the column ordering and then ..._COLUMN_INDEX are in sync
private static final String[] INTERNAL_COLUMNS = new String[] {
MediaStore.Audio.Media._ID, MediaStore.Audio.Media.TITLE,
- "\"" + MediaStore.Audio.Media.INTERNAL_CONTENT_URI + "\"",
+ "\"" + MediaStore.Audio.Media.INTERNAL_CONTENT_URI + "/\" || " + MediaStore.Audio.Media._ID,
MediaStore.Audio.Media.TITLE_KEY
};
private static final String[] DRM_COLUMNS = new String[] {
DrmStore.Audio._ID, DrmStore.Audio.TITLE,
- "\"" + DrmStore.Audio.CONTENT_URI + "\"",
+ "\"" + DrmStore.Audio.CONTENT_URI + "/\" || " + DrmStore.Audio._ID,
DrmStore.Audio.TITLE + " AS " + MediaStore.Audio.Media.TITLE_KEY
};
private static final String[] MEDIA_COLUMNS = new String[] {
MediaStore.Audio.Media._ID, MediaStore.Audio.Media.TITLE,
- "\"" + MediaStore.Audio.Media.EXTERNAL_CONTENT_URI + "\"",
+ "\"" + MediaStore.Audio.Media.EXTERNAL_CONTENT_URI + "/\" || " + MediaStore.Audio.Media._ID,
MediaStore.Audio.Media.TITLE_KEY
};
-
+
/**
* The column index (in the cursor returned by {@link #getCursor()} for the
* row ID.
@@ -213,6 +231,14 @@ public class RingtoneManager {
*/
public static final int URI_COLUMN_INDEX = 2;
+ /**
+ * Full uri, rather than just the root stem of the Uri prior to
+ * concatenation of the id.
+ *
+ * @hide
+ */
+ public static final int URI_FULL_COLUMN_INDEX = 3;
+
private Activity mActivity;
private Context mContext;
@@ -365,8 +391,10 @@ public class RingtoneManager {
final Cursor internalCursor = getInternalRingtones();
final Cursor drmCursor = mIncludeDrm ? getDrmRingtones() : null;
final Cursor mediaCursor = getMediaRingtones();
-
- return mCursor = new SortCursor(new Cursor[] { internalCursor, drmCursor, mediaCursor },
+ final Cursor[] themeCursor = getThemeManagerRingtones();
+
+ return mCursor = new SortCursor(new Cursor[] { internalCursor, drmCursor, mediaCursor,
+ themeCursor[0], themeCursor[1] },
MediaStore.Audio.Media.DEFAULT_SORT_ORDER);
}
@@ -401,12 +429,11 @@ public class RingtoneManager {
return getUriFromCursor(cursor);
}
-
+
private static Uri getUriFromCursor(Cursor cursor) {
- return ContentUris.withAppendedId(Uri.parse(cursor.getString(URI_COLUMN_INDEX)), cursor
- .getLong(ID_COLUMN_INDEX));
+ return Uri.parse(cursor.getString(URI_FULL_COLUMN_INDEX));
}
-
+
/**
* Gets the position of a {@link Uri} within this {@link RingtoneManager}.
*
@@ -424,23 +451,12 @@ public class RingtoneManager {
return -1;
}
- // Only create Uri objects when the actual URI changes
- Uri currentUri = null;
- String previousUriString = null;
for (int i = 0; i < cursorCount; i++) {
- String uriString = cursor.getString(URI_COLUMN_INDEX);
- if (currentUri == null || !uriString.equals(previousUriString)) {
- currentUri = Uri.parse(uriString);
- }
-
- if (ringtoneUri.equals(ContentUris.withAppendedId(currentUri, cursor
- .getLong(ID_COLUMN_INDEX)))) {
+ if (ringtoneUri.equals(getUriFromCursor(cursor))) {
return i;
}
cursor.move(1);
-
- previousUriString = uriString;
}
return -1;
@@ -466,6 +482,18 @@ public class RingtoneManager {
uri = getValidRingtoneUriFromCursorAndClose(context, rm.getDrmRingtones());
}
+ if (uri == null) {
+ Cursor[] cursors = rm.getThemeManagerRingtones();
+ if (cursors != null) {
+ for (Cursor cursor: cursors) {
+ uri = getValidRingtoneUriFromCursorAndClose(context, cursor);
+ if (uri != null) {
+ break;
+ }
+ }
+ }
+ }
+
return uri;
}
@@ -510,7 +538,34 @@ public class RingtoneManager {
MediaStore.Audio.Media.DEFAULT_SORT_ORDER)
: null;
}
-
+
+ private String getThemeWhereClause(String uriColumn) {
+ String clause = uriColumn + " IS NOT NULL";
+ if (mIncludeDrm) {
+ return clause;
+ } else {
+ return clause + " AND " + uriColumn + " NOT LIKE '%/assets/%locked%'";
+ }
+ }
+
+ private Cursor[] getThemeManagerRingtones() {
+ Cursor[] cursors = new Cursor[2];
+
+ if ((mType & TYPE_RINGTONE) != 0) {
+ cursors[0] = query(Uri.parse("content://com.tmobile.thememanager.themes/themes"),
+ new String[] { "_id", "ringtone_name AS title", "null", "ringtone_uri" },
+ getThemeWhereClause("ringtone_uri"), null, "title");
+ }
+
+ if ((mType & TYPE_NOTIFICATION) != 0) {
+ cursors[1] = query(Uri.parse("content://com.tmobile.thememanager.themes/themes"),
+ new String[] { "_id", "notif_ringtone_name AS title", "null", "notif_ringtone_name" },
+ getThemeWhereClause("notif_ringtone_uri"), null, "title");
+ }
+
+ return cursors;
+ }
+
private void setFilterColumnsList(int type) {
List<String> columns = mFilterColumns;
columns.clear();
@@ -642,6 +697,10 @@ public class RingtoneManager {
if (setting == null) return;
Settings.System.putString(context.getContentResolver(), setting,
ringtoneUri != null ? ringtoneUri.toString() : null);
+ Intent intent = new Intent();
+ intent.setAction(ACTION_RINGTONE_CHANGED);
+ intent.putExtra(RingtoneManager.EXTRA_RINGTONE_TYPE, type);
+ context.sendBroadcast(intent);
}
private static String getSettingForType(int type) {
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 9877342..6e6d910 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -43,6 +43,7 @@ import android.util.Log;
public class SettingsProvider extends ContentProvider {
private static final String TAG = "SettingsProvider";
private static final boolean LOCAL_LOGV = false;
+ private static String EXTRA_AUTHORITY = "com.tmobile.thememanager.packageresources";
private static final String TABLE_FAVORITES = "favorites";
private static final String TABLE_OLD_FAVORITES = "old_favorites";
@@ -404,7 +405,8 @@ public class SettingsProvider extends ContentProvider {
// Only proxy the openFile call to drm or media providers
String authority = soundUri.getAuthority();
boolean isDrmAuthority = authority.equals(DrmStore.AUTHORITY);
- if (isDrmAuthority || authority.equals(MediaStore.AUTHORITY)) {
+ if (isDrmAuthority || authority.equals(MediaStore.AUTHORITY) ||
+ (EXTRA_AUTHORITY != null && authority.equals(EXTRA_AUTHORITY))) {
if (isDrmAuthority) {
try {
diff --git a/services/java/Android.mk b/services/java/Android.mk
index 5e912d6..b7e7ff8 100644
--- a/services/java/Android.mk
+++ b/services/java/Android.mk
@@ -10,6 +10,7 @@ LOCAL_SRC_FILES := \
LOCAL_MODULE:= services
LOCAL_JAVA_LIBRARIES := android.policy
+LOCAL_STATIC_JAVA_LIBRARIES := libtmobile-widget
include $(BUILD_JAVA_LIBRARY)
diff --git a/services/java/com/android/server/AppsLaunchFailureReceiver.java b/services/java/com/android/server/AppsLaunchFailureReceiver.java
new file mode 100644
index 0000000..6220a18
--- /dev/null
+++ b/services/java/com/android/server/AppsLaunchFailureReceiver.java
@@ -0,0 +1,57 @@
+package com.android.server;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.Configuration;
+import android.content.res.CustomTheme;
+import android.util.Log;
+import android.app.ActivityManager;
+import android.os.SystemClock;
+
+public class AppsLaunchFailureReceiver extends BroadcastReceiver {
+
+ private static final int FAILURES_THRESHOLD = 5;
+ private static final int EXPIRATION_TIME_IN_MILLISECONDS = 30000; // 30 seconds
+
+ private int mFailuresCount = 0;
+ private long mStartTime = 0;
+
+ // This function implements the following logic.
+ // If after a theme was applied the number of application launch failures
+ // at any moment was equal to FAILURES_THRESHOLD
+ // in less than EXPIRATION_TIME_IN_MILLISECONDS
+ // the default theme is applied unconditionally.
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ if (action.equals(Intent.ACTION_APP_LAUNCH_FAILURE)) {
+ long currentTime = SystemClock.uptimeMillis();
+ if (currentTime - mStartTime > EXPIRATION_TIME_IN_MILLISECONDS) {
+ // reset both the count and the timer
+ mStartTime = currentTime;
+ mFailuresCount = 0;
+ }
+ if (mFailuresCount <= FAILURES_THRESHOLD) {
+ mFailuresCount++;
+ if (mFailuresCount == FAILURES_THRESHOLD) {
+ CustomTheme defaultTheme = CustomTheme.getDefault();
+ ActivityManager am = (ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE);
+ Configuration currentConfig = am.getConfiguration();
+ currentConfig.customTheme = new CustomTheme(
+ defaultTheme.getThemeId(),
+ defaultTheme.getThemePackageName());
+ am.updateConfiguration(currentConfig);
+ }
+ }
+ } else if (action.equals(Intent.ACTION_APP_LAUNCH_FAILURE_RESET)) {
+ mFailuresCount = 0;
+ mStartTime = SystemClock.uptimeMillis();
+ } else if (action.equals(Intent.ACTION_PACKAGE_ADDED) ||
+ action.equals(Intent.ACTION_PACKAGE_REMOVED)) {
+ mFailuresCount = 0;
+ mStartTime = SystemClock.uptimeMillis();
+ }
+ }
+
+}
diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java
index a83459e..5b8f51e 100644
--- a/services/java/com/android/server/PackageManagerService.java
+++ b/services/java/com/android/server/PackageManagerService.java
@@ -128,6 +128,8 @@ class PackageManagerService extends IPackageManager.Stub {
private static final int OBSERVER_EVENTS = REMOVE_EVENTS | ADD_EVENTS;
+ private static final int THEME_MAMANER_GUID = 1300;
+
static final int SCAN_MONITOR = 1<<0;
static final int SCAN_NO_DEX = 1<<1;
static final int SCAN_FORCE_DEX = 1<<2;
@@ -354,7 +356,7 @@ class PackageManagerService extends IPackageManager.Stub {
if (mSdkVersion <= 0) {
Log.w(TAG, "**** ro.build.version.sdk not set!");
}
-
+
mContext = context;
mFactoryTest = factoryTest;
mNoDexOpt = "eng".equals(SystemProperties.get("ro.build.type"));
@@ -370,6 +372,9 @@ class PackageManagerService extends IPackageManager.Stub {
MULTIPLE_APPLICATION_UIDS
? LOG_UID : FIRST_APPLICATION_UID,
ApplicationInfo.FLAG_SYSTEM);
+ mSettings.addSharedUserLP("com.tmobile.thememanager",
+ THEME_MAMANER_GUID,
+ ApplicationInfo.FLAG_SYSTEM);
String separateProcesses = SystemProperties.get("debug.separate_processes");
if (separateProcesses != null && separateProcesses.length() > 0) {
@@ -689,7 +694,7 @@ class PackageManagerService extends IPackageManager.Stub {
}
Log.i(TAG, sb.toString());
}
-
+
private void readPermissionsFromXml(File permFile) {
FileReader permReader = null;
try {
@@ -1797,6 +1802,20 @@ class PackageManagerService extends IPackageManager.Stub {
}
return finalList;
}
+
+ public List<PackageInfo> getInstalledThemePackages() {
+ // Returns a list of theme APKs.
+ ArrayList<PackageInfo> finalList = new ArrayList<PackageInfo>();
+ List<PackageInfo> installedPackagesList = getInstalledPackages(0);
+ Iterator<PackageInfo> i = installedPackagesList.iterator();
+ while (i.hasNext()) {
+ final PackageInfo pi = i.next();
+ if (pi != null && pi.isThemeApk) {
+ finalList.add(pi);
+ }
+ }
+ return finalList;
+ }
public List<ApplicationInfo> getInstalledApplications(int flags) {
ArrayList<ApplicationInfo> finalList = new ArrayList<ApplicationInfo>();
@@ -3548,7 +3567,7 @@ class PackageManagerService extends IPackageManager.Stub {
}
};
- private static final void sendPackageBroadcast(String action, String pkg, Bundle extras) {
+ private static final void sendPackageBroadcast(String action, String pkg, String intentCategory, Bundle extras) {
IActivityManager am = ActivityManagerNative.getDefault();
if (am != null) {
try {
@@ -3558,6 +3577,9 @@ class PackageManagerService extends IPackageManager.Stub {
intent.putExtras(extras);
}
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+ if (intentCategory != null) {
+ intent.addCategory(intentCategory);
+ }
am.broadcastIntent(
null, intent,
null, null, 0, null, null, null, false, false);
@@ -3578,6 +3600,7 @@ class PackageManagerService extends IPackageManager.Stub {
int removedUid = -1;
String addedPackage = null;
int addedUid = -1;
+ String category = null;
synchronized (mInstallLock) {
String fullPathStr = null;
@@ -3601,6 +3624,9 @@ class PackageManagerService extends IPackageManager.Stub {
synchronized (mInstallLock) {
PackageParser.Package p = mAppDirs.get(fullPathStr);
if (p != null) {
+ if (p.mIsThemeApk) {
+ category = Intent.CATEGORY_THEME_PACKAGE_INSTALLED_STATE_CHANGE;
+ }
removePackageLI(p, true);
removedPackage = p.applicationInfo.packageName;
removedUid = p.applicationInfo.uid;
@@ -3624,7 +3650,10 @@ class PackageManagerService extends IPackageManager.Stub {
addedUid = p.applicationInfo.uid;
}
}
- }
+ if (p != null && p.mIsThemeApk) {
+ category = Intent.CATEGORY_THEME_PACKAGE_INSTALLED_STATE_CHANGE;
+ }
+ }
synchronized (mPackages) {
mSettings.writeLP();
@@ -3635,12 +3664,12 @@ class PackageManagerService extends IPackageManager.Stub {
Bundle extras = new Bundle(1);
extras.putInt(Intent.EXTRA_UID, removedUid);
extras.putBoolean(Intent.EXTRA_DATA_REMOVED, false);
- sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED, removedPackage, extras);
+ sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED, removedPackage, category, extras);
}
if (addedPackage != null) {
Bundle extras = new Bundle(1);
extras.putInt(Intent.EXTRA_UID, addedUid);
- sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, addedPackage, extras);
+ sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, addedPackage, category, extras);
}
}
@@ -3688,19 +3717,24 @@ class PackageManagerService extends IPackageManager.Stub {
// There appears to be a subtle deadlock condition if the sendPackageBroadcast
// call appears in the synchronized block above.
if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
- res.removedInfo.sendBroadcast(false, true);
+ res.removedInfo.sendBroadcast(false, true, false);
Bundle extras = new Bundle(1);
extras.putInt(Intent.EXTRA_UID, res.uid);
final boolean update = res.removedInfo.removedPackage != null;
if (update) {
extras.putBoolean(Intent.EXTRA_REPLACING, true);
}
+ String category = null;
+ if (res.pkg.mIsThemeApk) {
+ category = Intent.CATEGORY_THEME_PACKAGE_INSTALLED_STATE_CHANGE;
+ }
sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED,
res.pkg.applicationInfo.packageName,
+ category,
extras);
if (update) {
sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED,
- res.pkg.applicationInfo.packageName,
+ res.pkg.applicationInfo.packageName, category,
extras);
}
}
@@ -4046,6 +4080,21 @@ class PackageManagerService extends IPackageManager.Stub {
res.returnCode = setPermissionsLI(pkgName, newPackage, destFilePath,
destResourceFile,
forwardLocked);
+
+ if (pkg.mIsThemeApk) {
+ boolean isThemePackageDrmProtected = false;
+ int N = pkg.mThemeInfos.size();
+ for (int i = 0; i < N; i++) {
+ if (pkg.mThemeInfos.get(i).isDrmProtected) {
+ isThemePackageDrmProtected = true;
+ break;
+ }
+ }
+ if (isThemePackageDrmProtected) {
+ splitThemePackage(destPackageFile);
+ }
+ }
+
if(res.returnCode != PackageManager.INSTALL_SUCCEEDED) {
return;
} else {
@@ -4070,12 +4119,72 @@ class PackageManagerService extends IPackageManager.Stub {
mSettings.writeLP();
}
}
-
+
private File getFwdLockedResource(String pkgName) {
final String publicZipFileName = pkgName + ".zip";
return new File(mAppInstallDir, publicZipFileName);
}
+ private void deleteLockedZipFileIfExists(String originalPackagePath) {
+ String lockedZipFilePath = PackageParser.getLockedZipFilePath(originalPackagePath);
+ File zipFile = new File(lockedZipFilePath);
+ if (zipFile.exists() && zipFile.isFile()) {
+ if (!zipFile.delete()) {
+ Log.w(TAG, "Couldn't delete locked zip file: " + originalPackagePath);
+ }
+ }
+ }
+
+ private void splitThemePackage(File originalFile) {
+ final String originalPackagePath = originalFile.getPath();
+ final String lockedZipFilePath = PackageParser.getLockedZipFilePath(originalPackagePath);
+
+ try {
+ final List<String> drmProtectedEntries = new ArrayList<String>();
+ final ZipFile privateZip = new ZipFile(originalFile.getPath());
+
+ final Enumeration<? extends ZipEntry> privateZipEntries = privateZip.entries();
+ while (privateZipEntries.hasMoreElements()) {
+ final ZipEntry zipEntry = privateZipEntries.nextElement();
+ final String zipEntryName = zipEntry.getName();
+ if (zipEntryName.startsWith("assets/") && zipEntryName.contains("/locked/")) {
+ drmProtectedEntries.add(zipEntryName);
+ }
+ }
+ privateZip.close();
+
+ String [] args = new String[0];
+ args = drmProtectedEntries.toArray(args);
+ int code = mContext.getAssets().splitDrmProtectedThemePackage(
+ originalPackagePath,
+ lockedZipFilePath,
+ args);
+ if (code != 0) {
+ Log.e("PackageManagerService",
+ "splitDrmProtectedThemePackage returned = " + code);
+ }
+ code = FileUtils.setPermissions(
+ lockedZipFilePath,
+ 0640,
+ -1,
+ THEME_MAMANER_GUID);
+ if (code != 0) {
+ Log.e("PackageManagerService",
+ "Set permissions for " + lockedZipFilePath + " returned = " + code);
+ }
+ code = FileUtils.setPermissions(
+ originalPackagePath,
+ 0644,
+ -1, -1);
+ if (code != 0) {
+ Log.e("PackageManagerService",
+ "Set permissions for " + originalPackagePath + " returned = " + code);
+ }
+ } catch (IOException e) {
+ Log.e(TAG, "Failure to generate new zip files for theme");
+ }
+ }
+
private File copyTempInstallFile(Uri pPackageURI,
PackageInstalledInfo res) {
File tmpPackageFile = createTempPackageFile();
@@ -4393,13 +4502,23 @@ class PackageManagerService extends IPackageManager.Stub {
PackageRemovedInfo info = new PackageRemovedInfo();
boolean res;
+ synchronized (mPackages) {
+ PackageParser.Package p = mPackages.get(packageName);
+ if (p != null) {
+ info.isThemeApk = p.mIsThemeApk;
+ if (info.isThemeApk && deleteCodeAndResources &&
+ !info.isRemovedPackageSystemUpdate && sendBroadCast) {
+ deleteLockedZipFileIfExists(p.mPath);
+ }
+ }
+ }
synchronized (mInstallLock) {
res = deletePackageLI(packageName, deleteCodeAndResources, flags, info);
}
if(res && sendBroadCast) {
boolean systemUpdate = info.isRemovedPackageSystemUpdate;
- info.sendBroadcast(deleteCodeAndResources, systemUpdate);
+ info.sendBroadcast(deleteCodeAndResources, systemUpdate, true);
// If the removed package was a system update, the old system packaged
// was re-enabled; we need to broadcast this information
@@ -4408,8 +4527,12 @@ class PackageManagerService extends IPackageManager.Stub {
extras.putInt(Intent.EXTRA_UID, info.removedUid >= 0 ? info.removedUid : info.uid);
extras.putBoolean(Intent.EXTRA_REPLACING, true);
- sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName, extras);
- sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, packageName, extras);
+ String category = null;
+ if (info.isThemeApk) {
+ category = Intent.CATEGORY_THEME_PACKAGE_INSTALLED_STATE_CHANGE;
+ }
+ sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName, category, extras);
+ sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, packageName, category, extras);
}
}
return res;
@@ -4420,8 +4543,10 @@ class PackageManagerService extends IPackageManager.Stub {
int uid = -1;
int removedUid = -1;
boolean isRemovedPackageSystemUpdate = false;
+ boolean isThemeApk = false;
- void sendBroadcast(boolean fullRemove, boolean replacing) {
+ void sendBroadcast(boolean fullRemove, boolean replacing,
+ boolean deleteLockedZipFileIfExists) {
Bundle extras = new Bundle(1);
extras.putInt(Intent.EXTRA_UID, removedUid >= 0 ? removedUid : uid);
extras.putBoolean(Intent.EXTRA_DATA_REMOVED, fullRemove);
@@ -4429,10 +4554,14 @@ class PackageManagerService extends IPackageManager.Stub {
extras.putBoolean(Intent.EXTRA_REPLACING, true);
}
if (removedPackage != null) {
- sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED, removedPackage, extras);
+ String category = null;
+ if (isThemeApk) {
+ category = Intent.CATEGORY_THEME_PACKAGE_INSTALLED_STATE_CHANGE;
+ }
+ sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED, removedPackage, category, extras);
}
if (removedUid >= 0) {
- sendPackageBroadcast(Intent.ACTION_UID_REMOVED, null, extras);
+ sendPackageBroadcast(Intent.ACTION_UID_REMOVED, null, null, extras);
}
}
}
@@ -5100,7 +5229,7 @@ class PackageManagerService extends IPackageManager.Stub {
extras.putString(Intent.EXTRA_CHANGED_COMPONENT_NAME, componentName);
extras.putBoolean(Intent.EXTRA_DONT_KILL_APP, killFlag);
extras.putInt(Intent.EXTRA_UID, packageUid);
- sendPackageBroadcast(Intent.ACTION_PACKAGE_CHANGED, packageName, extras);
+ sendPackageBroadcast(Intent.ACTION_PACKAGE_CHANGED, packageName, null, extras);
}
public String getInstallerPackageName(String packageName) {
@@ -7241,7 +7370,7 @@ class PackageManagerService extends IPackageManager.Stub {
"Error in package manager settings: package "
+ name + " has bad userId " + idStr + " at "
+ parser.getPositionDescription());
- };
+ }
if (su != null) {
int outerDepth = parser.getDepth();
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index b8cf844..c4a357d 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -29,11 +29,16 @@ import android.content.ContentResolver;
import android.content.ContentService;
import android.content.Context;
import android.content.Intent;
+import android.content.IntentFilter;
import android.content.pm.IPackageManager;
import android.database.ContentObserver;
import android.database.Cursor;
import android.media.AudioService;
-import android.os.*;
+import android.os.Looper;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.SystemClock;
+import android.os.SystemProperties;
import android.provider.Contacts.People;
import android.provider.Settings;
import android.server.BluetoothA2dpService;
@@ -393,6 +398,15 @@ class ServerThread extends Thread {
} catch (RemoteException e) {
}
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(Intent.ACTION_APP_LAUNCH_FAILURE);
+ filter.addAction(Intent.ACTION_APP_LAUNCH_FAILURE_RESET);
+ filter.addAction(Intent.ACTION_PACKAGE_ADDED);
+ filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+ filter.addCategory(Intent.CATEGORY_THEME_PACKAGE_INSTALLED_STATE_CHANGE);
+ filter.addDataScheme("package");
+ context.registerReceiver(new AppsLaunchFailureReceiver(), filter);
+
// These are needed to propagate to the runnable below.
final BatteryService batteryF = battery;
final ConnectivityService connectivityF = connectivity;
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index c3aeca4..b89c07d 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -25,6 +25,20 @@ import com.android.server.SystemServer;
import com.android.server.Watchdog;
import com.android.server.WindowManagerService;
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.PrintWriter;
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+
import android.app.Activity;
import android.app.ActivityManager;
import android.app.ActivityManagerNative;
@@ -65,6 +79,7 @@ import android.content.pm.ProviderInfo;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.content.res.Configuration;
+import android.content.res.CustomTheme;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Binder;
@@ -103,7 +118,14 @@ import android.view.View;
import android.view.WindowManager;
import android.view.WindowManagerPolicy;
-import dalvik.system.Zygote;
+import com.android.internal.os.BatteryStatsImpl;
+import com.android.internal.os.RuntimeInit;
+import com.android.server.IntentResolver;
+import com.android.server.ProcessMap;
+import com.android.server.ProcessStats;
+import com.android.server.SystemServer;
+import com.android.server.Watchdog;
+import com.android.server.WindowManagerService;
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
@@ -113,15 +135,10 @@ import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintWriter;
+
+import dalvik.system.Zygote;
+
import java.lang.IllegalStateException;
-import java.lang.ref.WeakReference;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
public final class ActivityManagerService extends ActivityManagerNative implements Watchdog.Monitor {
static final String TAG = "ActivityManager";
@@ -5696,10 +5713,10 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
r.state = ActivityState.PAUSED;
completePauseLocked();
} else {
- EventLog.writeEvent(LOG_AM_FAILED_TO_PAUSE_ACTIVITY,
- System.identityHashCode(r), r.shortComponentName,
- mPausingActivity != null
- ? mPausingActivity.shortComponentName : "(none)");
+ EventLog.writeEvent(LOG_AM_FAILED_TO_PAUSE_ACTIVITY,
+ System.identityHashCode(r), r.shortComponentName,
+ mPausingActivity != null
+ ? mPausingActivity.shortComponentName : "(none)");
}
}
}
@@ -12780,6 +12797,17 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
!values.locale.equals(mConfiguration.locale),
values.userSetLocale);
}
+
+// if(values.themeResource != 0){
+// saveThemeResourceLocked(values.themeResource, (values.themeResource != mConfiguration.themeResource));
+// }
+
+ if (values.customTheme != null) {
+ saveThemeResourceLocked(values.customTheme,
+ (!values.customTheme.equals(mConfiguration.customTheme)));
+ } else if (mConfiguration.customTheme != null) {
+ saveThemeResourceLocked(null, true);
+ }
mConfiguration = newConfig;
Log.i(TAG, "Config changed: " + newConfig);
@@ -12997,6 +13025,30 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
}
+ private void saveThemeResourceLocked(CustomTheme customTheme, boolean isDiff){
+ if(isDiff){
+ String themeId;
+ String themePackage;
+ String resourcePath;
+ boolean hasParent;
+ boolean forceUpdate;
+
+ if (customTheme != null) {
+ themeId = customTheme.getThemeId();
+ themePackage = customTheme.getThemePackageName();
+ } else {
+ themeId = null;
+ themePackage = "";
+ resourcePath = null;
+ hasParent = false;
+ forceUpdate = false;
+ }
+
+ SystemProperties.set(Configuration.THEME_ID_PERSISTENCE_PROPERTY, themeId);
+ SystemProperties.set(Configuration.THEME_PACKAGE_NAME_PERSISTENCE_PROPERTY, themePackage);
+ }
+ }
+
// =========================================================
// LIFETIME MANAGEMENT
// =========================================================
diff --git a/services/java/com/android/server/status/ExpandedView.java b/services/java/com/android/server/status/ExpandedView.java
index d0f14cb..afde479 100644
--- a/services/java/com/android/server/status/ExpandedView.java
+++ b/services/java/com/android/server/status/ExpandedView.java
@@ -19,7 +19,9 @@ public class ExpandedView extends LinearLayout {
int mPrevHeight = -1;
public ExpandedView(Context context, AttributeSet attrs) {
- super(context, attrs);
+ super(context, attrs, com.tmobile.widget.Utils.resolveDefaultStyleAttr(context,
+ "com_android_server_status_expandedView",
+ com.android.internal.R.attr.com_android_server_status_expandedView));
mDisplay = ((WindowManager)context.getSystemService(
Context.WINDOW_SERVICE)).getDefaultDisplay();
}
diff --git a/services/java/com/android/server/status/LatestItemView.java b/services/java/com/android/server/status/LatestItemView.java
index a47f6ad..27d1152 100644
--- a/services/java/com/android/server/status/LatestItemView.java
+++ b/services/java/com/android/server/status/LatestItemView.java
@@ -2,14 +2,15 @@ package com.android.server.status;
import android.content.Context;
import android.util.AttributeSet;
-import android.util.Log;
import android.view.MotionEvent;
import android.widget.FrameLayout;
public class LatestItemView extends FrameLayout {
public LatestItemView(Context context, AttributeSet attrs) {
- super(context, attrs);
+ super(context, attrs, com.tmobile.widget.Utils.resolveDefaultStyleAttr(context,
+ "com_android_server_status_latestItemView",
+ com.android.internal.R.attr.com_android_server_status_latestItemView));
}
public boolean dispatchTouchEvent(MotionEvent ev) {
diff --git a/services/java/com/android/server/status/StatusBarService.java b/services/java/com/android/server/status/StatusBarService.java
index 8d73904..516dbe7 100644
--- a/services/java/com/android/server/status/StatusBarService.java
+++ b/services/java/com/android/server/status/StatusBarService.java
@@ -18,6 +18,7 @@ package com.android.server.status;
import com.android.internal.R;
import com.android.internal.util.CharSequences;
+import com.android.server.am.ActivityManagerService;
import android.app.ActivityManagerNative;
import android.app.Dialog;
@@ -30,6 +31,7 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.content.res.Resources;
+import android.content.res.CustomTheme;
import android.graphics.PixelFormat;
import android.graphics.drawable.Drawable;
import android.net.Uri;
@@ -41,6 +43,8 @@ import android.os.Message;
import android.os.SystemClock;
import android.provider.Telephony;
import android.util.Log;
+import android.util.TypedValue;
+import android.view.ContextThemeWrapper;
import android.view.Display;
import android.view.Gravity;
import android.view.KeyEvent;
@@ -227,6 +231,10 @@ public class StatusBarService extends IStatusBar.Stub
ArrayList<DisableRecord> mDisableRecords = new ArrayList<DisableRecord>();
int mDisabled = 0;
+ private String mThemeId;
+ private String mThemePackageName;
+ private Context mThemeContext;
+
/**
* Construct the service, add the status bar view to the window manager
*/
@@ -242,6 +250,41 @@ public class StatusBarService extends IStatusBar.Stub
mNotificationCallbacks = listener;
}
+ private void createThemedExpandedView(Context context) {
+ try {
+ CustomTheme theme = ActivityManagerService.getDefault().getConfiguration().customTheme;
+ mThemeId = theme.getThemeId();
+ mThemePackageName = theme.getThemePackageName();
+ int styleId = CustomTheme.getStyleId(context, mThemePackageName, mThemeId);
+ if (styleId != -1) {
+ ContextThemeWrapper themeContext = new ContextThemeWrapper(context, styleId);
+ themeContext.useThemedResources(theme.getThemePackageName());
+ mThemeContext = themeContext;
+ } else {
+ mThemeContext = context;
+ }
+ ExpandedView expanded = (ExpandedView)View.inflate(mThemeContext,
+ com.android.internal.R.layout.status_bar_expanded, null);
+ // Uncomment this line iff we want to make the dialog theme'able
+// mExpandedDialog = new ExpandedDialog(themeContext);
+ expanded.mService = this;
+ mExpandedView = expanded;
+ mOngoingTitle = (TextView)expanded.findViewById(R.id.ongoingTitle);
+ mOngoingItems = (LinearLayout)expanded.findViewById(R.id.ongoingItems);
+ mLatestTitle = (TextView)expanded.findViewById(R.id.latestTitle);
+ mLatestItems = (LinearLayout)expanded.findViewById(R.id.latestItems);
+ mNoNotificationsTitle = (TextView)expanded.findViewById(R.id.noNotificationsTitle);
+ mClearButton = (TextView)expanded.findViewById(R.id.clear_all_button);
+ mClearButton.setOnClickListener(mClearButtonListener);
+ mSpnLabel = (TextView)expanded.findViewById(R.id.spnLabel);
+ mPlmnLabel = (TextView)expanded.findViewById(R.id.plmnLabel);
+ mScrollView = (ScrollView)expanded.findViewById(R.id.scroll);
+ mNotificationLinearLayout = expanded.findViewById(R.id.notificationLinearLayout);
+ } catch (RemoteException e) {
+ Log.e("StatusBarService", "Failed to get configuration", e);
+ }
+ }
+
// ================================================================================
// Constructing the view
// ================================================================================
@@ -250,9 +293,9 @@ public class StatusBarService extends IStatusBar.Stub
mRightIconSlots = res.getStringArray(com.android.internal.R.array.status_bar_icon_order);
mRightIcons = new StatusBarIcon[mRightIconSlots.length];
- ExpandedView expanded = (ExpandedView)View.inflate(context,
- com.android.internal.R.layout.status_bar_expanded, null);
- expanded.mService = this;
+ createThemedExpandedView(context);
+ // Comment out this line iff we want to make the dialog theme'able
+ mExpandedDialog = new ExpandedDialog(context);
StatusBarView sb = (StatusBarView)View.inflate(context,
com.android.internal.R.layout.status_bar, null);
sb.mService = this;
@@ -272,29 +315,12 @@ public class StatusBarService extends IStatusBar.Stub
mTickerView = sb.findViewById(R.id.ticker);
mDateView = (DateView)sb.findViewById(R.id.date);
- mExpandedDialog = new ExpandedDialog(context);
- mExpandedView = expanded;
- mOngoingTitle = (TextView)expanded.findViewById(R.id.ongoingTitle);
- mOngoingItems = (LinearLayout)expanded.findViewById(R.id.ongoingItems);
- mLatestTitle = (TextView)expanded.findViewById(R.id.latestTitle);
- mLatestItems = (LinearLayout)expanded.findViewById(R.id.latestItems);
- mNoNotificationsTitle = (TextView)expanded.findViewById(R.id.noNotificationsTitle);
- mClearButton = (TextView)expanded.findViewById(R.id.clear_all_button);
- mClearButton.setOnClickListener(mClearButtonListener);
- mSpnLabel = (TextView)expanded.findViewById(R.id.spnLabel);
- mPlmnLabel = (TextView)expanded.findViewById(R.id.plmnLabel);
- mScrollView = (ScrollView)expanded.findViewById(R.id.scroll);
- mNotificationLinearLayout = expanded.findViewById(R.id.notificationLinearLayout);
-
- mOngoingTitle.setVisibility(View.GONE);
- mLatestTitle.setVisibility(View.GONE);
-
mTicker = new MyTicker(context, sb);
TickerView tickerView = (TickerView)sb.findViewById(R.id.tickerText);
tickerView.mTicker = mTicker;
- mTrackingView = (TrackingView)View.inflate(context,
+ mTrackingView = (TrackingView)View.inflate(mThemeContext,
com.android.internal.R.layout.status_bar_tracking, null);
mTrackingView.mService = this;
mCloseView = (CloseDragHandle)mTrackingView.findViewById(R.id.close);
@@ -824,8 +850,8 @@ public class StatusBarService extends IStatusBar.Stub
}
// create the row view
- LayoutInflater inflater = (LayoutInflater)mContext.getSystemService(
- Context.LAYOUT_INFLATER_SERVICE);
+ LayoutInflater inflater =
+ (LayoutInflater)mThemeContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View row = inflater.inflate(com.android.internal.R.layout.status_bar_latest_event, parent, false);
// bind the click event to the content area
@@ -1750,6 +1776,37 @@ public class StatusBarService extends IStatusBar.Stub
* meantime, just update the things that we know change.
*/
void updateResources() {
+ try {
+ CustomTheme customTheme = ActivityManagerService.getDefault().getConfiguration().customTheme;
+ boolean themeChanged =
+ !customTheme.getThemeId().equalsIgnoreCase(mThemeId) ||
+ !customTheme.getThemePackageName().equalsIgnoreCase(mThemePackageName);
+ if (themeChanged) {
+ createThemedExpandedView(mContext);
+
+ mExpandedDialog.setContentView(mExpandedView,
+ new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,
+ ViewGroup.LayoutParams.WRAP_CONTENT));
+ // re-wire notifications if needed
+ NotificationViewList oldList = mNotificationData;
+ mNotificationData = new NotificationViewList();
+ if (oldList.latestCount() > 0) {
+ for (int i = 0; i < oldList.latestCount(); i++) {
+ StatusBarNotification notification = oldList.getLatest(i);
+ updateNotificationView(notification, null);
+ }
+ }
+ if (oldList.ongoingCount() > 0) {
+ for (int i = 0; i < oldList.ongoingCount(); i++) {
+ StatusBarNotification notification = oldList.getOngoing(i);
+ updateNotificationView(notification, null);
+ }
+ }
+ setAreThereNotifications();
+ }
+ } catch (RemoteException e) {
+ Log.e("StatusBarService", "Can't retrieve default theme", e);
+ }
mClearButton.setText(mContext.getText(R.string.status_bar_clear_all_button));
mOngoingTitle.setText(mContext.getText(R.string.status_bar_ongoing_events_title));
mLatestTitle.setText(mContext.getText(R.string.status_bar_latest_events_title));
diff --git a/test-runner/android/test/mock/MockContext.java b/test-runner/android/test/mock/MockContext.java
index 57b22f8..0f3e02c 100644
--- a/test-runner/android/test/mock/MockContext.java
+++ b/test-runner/android/test/mock/MockContext.java
@@ -85,7 +85,7 @@ public class MockContext extends Context {
public void setTheme(int resid) {
throw new UnsupportedOperationException();
}
-
+
@Override
public Resources.Theme getTheme() {
throw new UnsupportedOperationException();
diff --git a/test-runner/android/test/mock/MockPackageManager.java b/test-runner/android/test/mock/MockPackageManager.java
index 2f313af..1850bf3 100644
--- a/test-runner/android/test/mock/MockPackageManager.java
+++ b/test-runner/android/test/mock/MockPackageManager.java
@@ -36,11 +36,11 @@ import android.content.pm.ProviderInfo;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.ThemeInfo;
import android.content.res.Resources;
import android.content.res.XmlResourceParser;
import android.graphics.drawable.Drawable;
import android.net.Uri;
-import android.os.RemoteException;
import java.util.List;
@@ -120,6 +120,11 @@ public class MockPackageManager extends PackageManager {
}
@Override
+ public List<PackageInfo> getInstalledThemePackages() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
public int checkPermission(String permName, String pkgName) {
throw new UnsupportedOperationException();
}
diff --git a/tools/aapt/Bundle.h b/tools/aapt/Bundle.h
index 1ac13f2..649d97f 100644
--- a/tools/aapt/Bundle.h
+++ b/tools/aapt/Bundle.h
@@ -35,7 +35,7 @@ public:
Bundle(void)
: mCmd(kCommandUnknown), mVerbose(false), mAndroidList(false),
mForce(false), mGrayscaleTolerance(0), mMakePackageDirs(false),
- mUpdate(false), mExtending(false),
+ mUpdate(false), mExtending(false), mExtendedPackageId(0),
mRequireLocalization(false), mPseudolocalize(false),
mValues(false),
mCompressionMethod(0), mOutputAPKFile(NULL),
@@ -72,6 +72,8 @@ public:
void setUpdate(bool val) { mUpdate = val; }
bool getExtending(void) const { return mExtending; }
void setExtending(bool val) { mExtending = val; }
+ int getExtendedPackageId(void) const { return mExtendedPackageId; }
+ void setExtendedPackageId(int val) { mExtendedPackageId = val; }
bool getRequireLocalization(void) const { return mRequireLocalization; }
void setRequireLocalization(bool val) { mRequireLocalization = val; }
bool getPseudolocalize(void) const { return mPseudolocalize; }
@@ -159,6 +161,7 @@ private:
bool mMakePackageDirs;
bool mUpdate;
bool mExtending;
+ int mExtendedPackageId;
bool mRequireLocalization;
bool mPseudolocalize;
bool mValues;
diff --git a/tools/aapt/Main.cpp b/tools/aapt/Main.cpp
index 98286c0..735751c 100644
--- a/tools/aapt/Main.cpp
+++ b/tools/aapt/Main.cpp
@@ -14,6 +14,7 @@
#include <stdlib.h>
#include <getopt.h>
#include <assert.h>
+#include <ctype.h>
using namespace android;
@@ -55,7 +56,7 @@ void usage(void)
" xmltree Print the compiled xmls in the given assets.\n"
" xmlstrings Print the strings of the given compiled xml assets.\n\n", gProgName);
fprintf(stderr,
- " %s p[ackage] [-d][-f][-m][-u][-v][-x][-z][-M AndroidManifest.xml] \\\n"
+ " %s p[ackage] [-d][-f][-m][-u][-v][-x[ extending-resource-id]][-z][-M AndroidManifest.xml] \\\n"
" [-0 extension [-0 extension ...]] [-g tolerance] [-j jarfile] \\\n"
" [--min-sdk-version VAL] [--target-sdk-version VAL] \\\n"
" [--max-sdk-version VAL] [--app-version VAL] \\\n"
@@ -106,7 +107,7 @@ void usage(void)
#endif
" -u update existing packages (add new, replace older, remove deleted files)\n"
" -v verbose output\n"
- " -x create extending (non-application) resource IDs\n"
+ " -x either create or assign (if specified) extending (non-application) resource IDs\n"
" -z require localization of resource attributes marked with\n"
" localization=\"suggested\"\n"
" -A additional directory in which to find raw asset files\n"
@@ -253,6 +254,14 @@ int main(int argc, char* const argv[])
break;
case 'x':
bundle.setExtending(true);
+ argc--;
+ argv++;
+ if (!argc || !isdigit(argv[0][0])) {
+ argc++;
+ argv--;
+ } else {
+ bundle.setExtendedPackageId(atoi(argv[0]));
+ }
break;
case 'z':
bundle.setRequireLocalization(true);
diff --git a/tools/aapt/ResourceTable.cpp b/tools/aapt/ResourceTable.cpp
index 19b9b01..1d4459b 100644
--- a/tools/aapt/ResourceTable.cpp
+++ b/tools/aapt/ResourceTable.cpp
@@ -3557,7 +3557,16 @@ sp<ResourceTable::Package> ResourceTable::getPackage(const String16& package)
mHaveAppPackage = true;
p = new Package(package, 127);
} else {
- p = new Package(package, mNextPackageId);
+ int extendedPackageId = mBundle->getExtendedPackageId();
+ if (extendedPackageId != 0) {
+ if ((uint32_t)extendedPackageId < mNextPackageId) {
+ fprintf(stderr, "Package ID %d already in use!\n", mNextPackageId);
+ return NULL;
+ }
+ p = new Package(package, extendedPackageId);
+ } else {
+ p = new Package(package, mNextPackageId);
+ }
}
//printf("*** NEW PACKAGE: \"%s\" id=%d\n",
// String8(package).string(), p->getAssignedId());
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeXmlBlockParser.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeXmlBlockParser.java
index d842a66..e6791cb 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeXmlBlockParser.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeXmlBlockParser.java
@@ -193,6 +193,11 @@ public class BridgeXmlBlockParser implements XmlResourceParser {
return mParser.getAttributeNamespace(index);
}
+ /** @hide */
+ public int getAttributeDataType(int index) {
+ throw new RuntimeException("getAttributeDataType not supported");
+ }
+
public String getAttributeName(int index) {
return mParser.getAttributeName(index);
}