summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDvTonder <david.vantonder@gmail.com>2012-07-15 10:28:15 -0400
committerRicardo Cerqueira <cyanogenmod@cerqueira.org>2012-11-21 00:25:18 +0000
commit0b636d08439c291322339e02be605be54f589b91 (patch)
tree1abb1921eab3532617ddda7e07939f99de093280
parent8415ee214d09ed7f399d8ff68d4f78c76c68fe08 (diff)
downloadframeworks_base-0b636d08439c291322339e02be605be54f589b91.zip
frameworks_base-0b636d08439c291322339e02be605be54f589b91.tar.gz
frameworks_base-0b636d08439c291322339e02be605be54f589b91.tar.bz2
Framework: Port CM9 features to CM10
This commit includes: - Power menu Reboot - Power menu screenshot - Profiles - Lock screen Calendar - Lock screen Weather - Notification light customization - Battery light customization - IME Selector notification toggle - and a few more things to support Settings Change-Id: Ibd63116df90b06f6ce6adb8a0343059bbb999bfb
-rw-r--r--Android.mk3
-rwxr-xr-xcore/java/android/app/ConnectionSettings.java216
-rw-r--r--core/java/android/app/ContextImpl.java6
-rw-r--r--core/java/android/app/IProfileManager.aidl50
-rw-r--r--core/java/android/app/Notification.java9
-rw-r--r--core/java/android/app/NotificationGroup.aidl19
-rw-r--r--core/java/android/app/NotificationGroup.java201
-rw-r--r--core/java/android/app/Profile.aidl19
-rw-r--r--core/java/android/app/Profile.java595
-rw-r--r--core/java/android/app/ProfileGroup.java348
-rw-r--r--core/java/android/app/ProfileManager.java260
-rw-r--r--core/java/android/app/StreamSettings.java130
-rw-r--r--core/java/android/app/VibratorSettings.java150
-rw-r--r--core/java/android/content/Context.java12
-rw-r--r--core/java/android/net/wimax/WimaxHelper.java188
-rw-r--r--core/java/android/net/wimax/WimaxManagerConstants.java15
-rw-r--r--core/java/android/preference/ListPreferenceMultiSelect.java112
-rw-r--r--core/java/android/preference/VolumePreference.java17
-rw-r--r--core/java/android/provider/Settings.java700
-rw-r--r--core/java/android/view/VolumePanel.java147
-rw-r--r--core/java/android/view/WindowManagerPolicy.java1
-rw-r--r--core/java/com/android/internal/util/weather/HttpRetriever.java152
-rw-r--r--core/java/com/android/internal/util/weather/WeatherInfo.java115
-rw-r--r--core/java/com/android/internal/util/weather/WeatherXmlParser.java177
-rw-r--r--core/java/com/android/internal/util/weather/YahooPlaceFinder.java41
-rw-r--r--core/java/com/android/internal/widget/LockPatternUtils.java178
-rw-r--r--core/res/res/drawable-hdpi/ic_lock_idle_calendar.pngbin0 -> 709 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_lock_profile.pngbin0 -> 3919 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_lock_reboot.pngbin0 -> 1645 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_lock_screenshot.pngbin0 -> 1326 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_lockscreen_chrome_activated.pngbin0 -> 7736 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_lockscreen_chrome_normal.pngbin0 -> 2277 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_lockscreen_google_activated.pngbin12152 -> 8473 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_lockscreen_google_normal.pngbin12262 -> 5413 bytes
-rw-r--r--core/res/res/drawable-hdpi/weather_0.pngbin0 -> 3262 bytes
-rw-r--r--core/res/res/drawable-hdpi/weather_1.pngbin0 -> 3262 bytes
-rw-r--r--core/res/res/drawable-hdpi/weather_10.pngbin0 -> 4531 bytes
-rw-r--r--core/res/res/drawable-hdpi/weather_11.pngbin0 -> 4091 bytes
-rw-r--r--core/res/res/drawable-hdpi/weather_12.pngbin0 -> 4091 bytes
-rw-r--r--core/res/res/drawable-hdpi/weather_13.pngbin0 -> 4103 bytes
-rw-r--r--core/res/res/drawable-hdpi/weather_14.pngbin0 -> 4103 bytes
-rw-r--r--core/res/res/drawable-hdpi/weather_15.pngbin0 -> 4706 bytes
-rw-r--r--core/res/res/drawable-hdpi/weather_16.pngbin0 -> 4305 bytes
-rw-r--r--core/res/res/drawable-hdpi/weather_17.pngbin0 -> 4418 bytes
-rw-r--r--core/res/res/drawable-hdpi/weather_18.pngbin0 -> 4134 bytes
-rw-r--r--core/res/res/drawable-hdpi/weather_19.pngbin0 -> 3355 bytes
-rw-r--r--core/res/res/drawable-hdpi/weather_2.pngbin0 -> 3262 bytes
-rw-r--r--core/res/res/drawable-hdpi/weather_20.pngbin0 -> 3699 bytes
-rw-r--r--core/res/res/drawable-hdpi/weather_21.pngbin0 -> 3991 bytes
-rw-r--r--core/res/res/drawable-hdpi/weather_22.pngbin0 -> 3355 bytes
-rw-r--r--core/res/res/drawable-hdpi/weather_23.pngbin0 -> 3613 bytes
-rw-r--r--core/res/res/drawable-hdpi/weather_24.pngbin0 -> 3613 bytes
-rw-r--r--core/res/res/drawable-hdpi/weather_25.pngbin0 -> 4419 bytes
-rw-r--r--core/res/res/drawable-hdpi/weather_26.pngbin0 -> 4010 bytes
-rw-r--r--core/res/res/drawable-hdpi/weather_27.pngbin0 -> 4380 bytes
-rw-r--r--core/res/res/drawable-hdpi/weather_28.pngbin0 -> 4523 bytes
-rw-r--r--core/res/res/drawable-hdpi/weather_29.pngbin0 -> 4380 bytes
-rw-r--r--core/res/res/drawable-hdpi/weather_3.pngbin0 -> 4412 bytes
-rw-r--r--core/res/res/drawable-hdpi/weather_30.pngbin0 -> 4523 bytes
-rw-r--r--core/res/res/drawable-hdpi/weather_31.pngbin0 -> 3691 bytes
-rw-r--r--core/res/res/drawable-hdpi/weather_32.pngbin0 -> 4246 bytes
-rw-r--r--core/res/res/drawable-hdpi/weather_33.pngbin0 -> 3691 bytes
-rw-r--r--core/res/res/drawable-hdpi/weather_34.pngbin0 -> 4246 bytes
-rw-r--r--core/res/res/drawable-hdpi/weather_35.pngbin0 -> 4588 bytes
-rw-r--r--core/res/res/drawable-hdpi/weather_36.pngbin0 -> 4798 bytes
-rw-r--r--core/res/res/drawable-hdpi/weather_37.pngbin0 -> 4911 bytes
-rw-r--r--core/res/res/drawable-hdpi/weather_38.pngbin0 -> 4734 bytes
-rw-r--r--core/res/res/drawable-hdpi/weather_39.pngbin0 -> 4911 bytes
-rw-r--r--core/res/res/drawable-hdpi/weather_4.pngbin0 -> 4412 bytes
-rw-r--r--core/res/res/drawable-hdpi/weather_40.pngbin0 -> 4573 bytes
-rw-r--r--core/res/res/drawable-hdpi/weather_41.pngbin0 -> 4305 bytes
-rw-r--r--core/res/res/drawable-hdpi/weather_42.pngbin0 -> 4627 bytes
-rw-r--r--core/res/res/drawable-hdpi/weather_43.pngbin0 -> 4305 bytes
-rw-r--r--core/res/res/drawable-hdpi/weather_44.pngbin0 -> 4380 bytes
-rw-r--r--core/res/res/drawable-hdpi/weather_45.pngbin0 -> 4412 bytes
-rw-r--r--core/res/res/drawable-hdpi/weather_46.pngbin0 -> 4103 bytes
-rw-r--r--core/res/res/drawable-hdpi/weather_47.pngbin0 -> 4734 bytes
-rw-r--r--core/res/res/drawable-hdpi/weather_5.pngbin0 -> 4134 bytes
-rw-r--r--core/res/res/drawable-hdpi/weather_6.pngbin0 -> 4134 bytes
-rw-r--r--core/res/res/drawable-hdpi/weather_7.pngbin0 -> 4134 bytes
-rw-r--r--core/res/res/drawable-hdpi/weather_8.pngbin0 -> 4593 bytes
-rw-r--r--core/res/res/drawable-hdpi/weather_9.pngbin0 -> 4180 bytes
-rw-r--r--core/res/res/drawable-hdpi/weather_na.pngbin0 -> 4113 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_lock_idle_calendar.pngbin0 -> 583 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_lock_profile.pngbin0 -> 3517 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_lock_reboot.pngbin0 -> 3374 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_lock_screenshot.pngbin0 -> 1176 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_lockscreen_chrome_activated.pngbin0 -> 4655 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_lockscreen_chrome_normal.pngbin0 -> 1739 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_lockscreen_google_activated.pngbin7057 -> 5042 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_lockscreen_google_normal.pngbin6519 -> 4292 bytes
-rw-r--r--core/res/res/drawable-mdpi/weather_0.pngbin0 -> 3310 bytes
-rw-r--r--core/res/res/drawable-mdpi/weather_1.pngbin0 -> 3310 bytes
-rw-r--r--core/res/res/drawable-mdpi/weather_10.pngbin0 -> 4367 bytes
-rw-r--r--core/res/res/drawable-mdpi/weather_11.pngbin0 -> 4035 bytes
-rw-r--r--core/res/res/drawable-mdpi/weather_12.pngbin0 -> 4035 bytes
-rw-r--r--core/res/res/drawable-mdpi/weather_13.pngbin0 -> 4038 bytes
-rw-r--r--core/res/res/drawable-mdpi/weather_14.pngbin0 -> 4038 bytes
-rw-r--r--core/res/res/drawable-mdpi/weather_15.pngbin0 -> 4670 bytes
-rw-r--r--core/res/res/drawable-mdpi/weather_16.pngbin0 -> 4191 bytes
-rw-r--r--core/res/res/drawable-mdpi/weather_17.pngbin0 -> 4377 bytes
-rw-r--r--core/res/res/drawable-mdpi/weather_18.pngbin0 -> 4132 bytes
-rw-r--r--core/res/res/drawable-mdpi/weather_19.pngbin0 -> 3434 bytes
-rw-r--r--core/res/res/drawable-mdpi/weather_2.pngbin0 -> 3310 bytes
-rw-r--r--core/res/res/drawable-mdpi/weather_20.pngbin0 -> 3622 bytes
-rw-r--r--core/res/res/drawable-mdpi/weather_21.pngbin0 -> 3975 bytes
-rw-r--r--core/res/res/drawable-mdpi/weather_22.pngbin0 -> 3434 bytes
-rw-r--r--core/res/res/drawable-mdpi/weather_23.pngbin0 -> 3613 bytes
-rw-r--r--core/res/res/drawable-mdpi/weather_24.pngbin0 -> 3613 bytes
-rw-r--r--core/res/res/drawable-mdpi/weather_25.pngbin0 -> 4273 bytes
-rw-r--r--core/res/res/drawable-mdpi/weather_26.pngbin0 -> 3875 bytes
-rw-r--r--core/res/res/drawable-mdpi/weather_27.pngbin0 -> 4202 bytes
-rw-r--r--core/res/res/drawable-mdpi/weather_28.pngbin0 -> 4374 bytes
-rw-r--r--core/res/res/drawable-mdpi/weather_29.pngbin0 -> 4202 bytes
-rw-r--r--core/res/res/drawable-mdpi/weather_3.pngbin0 -> 4220 bytes
-rw-r--r--core/res/res/drawable-mdpi/weather_30.pngbin0 -> 4374 bytes
-rw-r--r--core/res/res/drawable-mdpi/weather_31.pngbin0 -> 3583 bytes
-rw-r--r--core/res/res/drawable-mdpi/weather_32.pngbin0 -> 4185 bytes
-rw-r--r--core/res/res/drawable-mdpi/weather_33.pngbin0 -> 3583 bytes
-rw-r--r--core/res/res/drawable-mdpi/weather_34.pngbin0 -> 4185 bytes
-rw-r--r--core/res/res/drawable-mdpi/weather_35.pngbin0 -> 4455 bytes
-rw-r--r--core/res/res/drawable-mdpi/weather_36.pngbin0 -> 4675 bytes
-rw-r--r--core/res/res/drawable-mdpi/weather_37.pngbin0 -> 4691 bytes
-rw-r--r--core/res/res/drawable-mdpi/weather_38.pngbin0 -> 4506 bytes
-rw-r--r--core/res/res/drawable-mdpi/weather_39.pngbin0 -> 4691 bytes
-rw-r--r--core/res/res/drawable-mdpi/weather_4.pngbin0 -> 4220 bytes
-rw-r--r--core/res/res/drawable-mdpi/weather_40.pngbin0 -> 4506 bytes
-rw-r--r--core/res/res/drawable-mdpi/weather_41.pngbin0 -> 4191 bytes
-rw-r--r--core/res/res/drawable-mdpi/weather_42.pngbin0 -> 4466 bytes
-rw-r--r--core/res/res/drawable-mdpi/weather_43.pngbin0 -> 4191 bytes
-rw-r--r--core/res/res/drawable-mdpi/weather_44.pngbin0 -> 4202 bytes
-rw-r--r--core/res/res/drawable-mdpi/weather_45.pngbin0 -> 4220 bytes
-rw-r--r--core/res/res/drawable-mdpi/weather_46.pngbin0 -> 4038 bytes
-rw-r--r--core/res/res/drawable-mdpi/weather_47.pngbin0 -> 4506 bytes
-rw-r--r--core/res/res/drawable-mdpi/weather_5.pngbin0 -> 4132 bytes
-rw-r--r--core/res/res/drawable-mdpi/weather_6.pngbin0 -> 4132 bytes
-rw-r--r--core/res/res/drawable-mdpi/weather_7.pngbin0 -> 4132 bytes
-rw-r--r--core/res/res/drawable-mdpi/weather_8.pngbin0 -> 4486 bytes
-rw-r--r--core/res/res/drawable-mdpi/weather_9.pngbin0 -> 4162 bytes
-rw-r--r--core/res/res/drawable-mdpi/weather_na.pngbin0 -> 3798 bytes
-rw-r--r--core/res/res/drawable-xhdpi/ic_lock_idle_calendar.pngbin0 -> 823 bytes
-rw-r--r--core/res/res/drawable-xhdpi/ic_lock_profile.pngbin0 -> 4208 bytes
-rw-r--r--core/res/res/drawable-xhdpi/ic_lock_reboot.pngbin0 -> 1558 bytes
-rw-r--r--core/res/res/drawable-xhdpi/ic_lock_screenshot.pngbin0 -> 1437 bytes
-rw-r--r--core/res/res/drawable-xhdpi/ic_lockscreen_chrome_activated.pngbin0 -> 10150 bytes
-rw-r--r--core/res/res/drawable-xhdpi/ic_lockscreen_chrome_normal.pngbin0 -> 2481 bytes
-rw-r--r--core/res/res/drawable-xhdpi/ic_lockscreen_google_activated.pngbin17254 -> 10722 bytes
-rw-r--r--core/res/res/drawable-xhdpi/ic_lockscreen_google_normal.pngbin18528 -> 5203 bytes
-rw-r--r--core/res/res/drawable-xhdpi/weather_0.pngbin0 -> 3583 bytes
-rw-r--r--core/res/res/drawable-xhdpi/weather_1.pngbin0 -> 3583 bytes
-rw-r--r--core/res/res/drawable-xhdpi/weather_10.pngbin0 -> 4815 bytes
-rw-r--r--core/res/res/drawable-xhdpi/weather_11.pngbin0 -> 4376 bytes
-rw-r--r--core/res/res/drawable-xhdpi/weather_12.pngbin0 -> 4376 bytes
-rw-r--r--core/res/res/drawable-xhdpi/weather_13.pngbin0 -> 4525 bytes
-rw-r--r--core/res/res/drawable-xhdpi/weather_14.pngbin0 -> 4525 bytes
-rw-r--r--core/res/res/drawable-xhdpi/weather_15.pngbin0 -> 4955 bytes
-rw-r--r--core/res/res/drawable-xhdpi/weather_16.pngbin0 -> 4493 bytes
-rw-r--r--core/res/res/drawable-xhdpi/weather_17.pngbin0 -> 4701 bytes
-rw-r--r--core/res/res/drawable-xhdpi/weather_18.pngbin0 -> 4455 bytes
-rw-r--r--core/res/res/drawable-xhdpi/weather_19.pngbin0 -> 3610 bytes
-rw-r--r--core/res/res/drawable-xhdpi/weather_2.pngbin0 -> 3583 bytes
-rw-r--r--core/res/res/drawable-xhdpi/weather_20.pngbin0 -> 4022 bytes
-rw-r--r--core/res/res/drawable-xhdpi/weather_21.pngbin0 -> 4280 bytes
-rw-r--r--core/res/res/drawable-xhdpi/weather_22.pngbin0 -> 3610 bytes
-rw-r--r--core/res/res/drawable-xhdpi/weather_23.pngbin0 -> 3945 bytes
-rw-r--r--core/res/res/drawable-xhdpi/weather_24.pngbin0 -> 3945 bytes
-rw-r--r--core/res/res/drawable-xhdpi/weather_25.pngbin0 -> 4689 bytes
-rw-r--r--core/res/res/drawable-xhdpi/weather_26.pngbin0 -> 4180 bytes
-rw-r--r--core/res/res/drawable-xhdpi/weather_27.pngbin0 -> 4484 bytes
-rw-r--r--core/res/res/drawable-xhdpi/weather_28.pngbin0 -> 4661 bytes
-rw-r--r--core/res/res/drawable-xhdpi/weather_29.pngbin0 -> 4484 bytes
-rw-r--r--core/res/res/drawable-xhdpi/weather_3.pngbin0 -> 4597 bytes
-rw-r--r--core/res/res/drawable-xhdpi/weather_30.pngbin0 -> 4661 bytes
-rw-r--r--core/res/res/drawable-xhdpi/weather_31.pngbin0 -> 3872 bytes
-rw-r--r--core/res/res/drawable-xhdpi/weather_32.pngbin0 -> 4521 bytes
-rw-r--r--core/res/res/drawable-xhdpi/weather_33.pngbin0 -> 3872 bytes
-rw-r--r--core/res/res/drawable-xhdpi/weather_34.pngbin0 -> 4521 bytes
-rw-r--r--core/res/res/drawable-xhdpi/weather_35.pngbin0 -> 4833 bytes
-rw-r--r--core/res/res/drawable-xhdpi/weather_36.pngbin0 -> 5061 bytes
-rw-r--r--core/res/res/drawable-xhdpi/weather_37.pngbin0 -> 5047 bytes
-rw-r--r--core/res/res/drawable-xhdpi/weather_38.pngbin0 -> 4933 bytes
-rw-r--r--core/res/res/drawable-xhdpi/weather_39.pngbin0 -> 5047 bytes
-rw-r--r--core/res/res/drawable-xhdpi/weather_4.pngbin0 -> 4597 bytes
-rw-r--r--core/res/res/drawable-xhdpi/weather_40.pngbin0 -> 4805 bytes
-rw-r--r--core/res/res/drawable-xhdpi/weather_41.pngbin0 -> 4493 bytes
-rw-r--r--core/res/res/drawable-xhdpi/weather_42.pngbin0 -> 4754 bytes
-rw-r--r--core/res/res/drawable-xhdpi/weather_43.pngbin0 -> 4493 bytes
-rw-r--r--core/res/res/drawable-xhdpi/weather_44.pngbin0 -> 4484 bytes
-rw-r--r--core/res/res/drawable-xhdpi/weather_45.pngbin0 -> 4597 bytes
-rw-r--r--core/res/res/drawable-xhdpi/weather_46.pngbin0 -> 4525 bytes
-rw-r--r--core/res/res/drawable-xhdpi/weather_47.pngbin0 -> 4933 bytes
-rw-r--r--core/res/res/drawable-xhdpi/weather_5.pngbin0 -> 4455 bytes
-rw-r--r--core/res/res/drawable-xhdpi/weather_6.pngbin0 -> 4455 bytes
-rw-r--r--core/res/res/drawable-xhdpi/weather_7.pngbin0 -> 4455 bytes
-rw-r--r--core/res/res/drawable-xhdpi/weather_8.pngbin0 -> 4962 bytes
-rw-r--r--core/res/res/drawable-xhdpi/weather_9.pngbin0 -> 4521 bytes
-rw-r--r--core/res/res/drawable-xhdpi/weather_na.pngbin0 -> 4512 bytes
-rw-r--r--core/res/res/layout-sw600dp/keyguard_screen_status_land.xml168
-rw-r--r--core/res/res/layout-sw600dp/keyguard_screen_status_port.xml166
-rw-r--r--core/res/res/layout/keyguard_screen_tab_unlock.xml165
-rw-r--r--core/res/res/layout/keyguard_screen_tab_unlock_land.xml113
-rw-r--r--core/res/res/values/arrays.xml24
-rwxr-xr-xcore/res/res/values/config.xml21
-rw-r--r--core/res/res/values/public.xml185
-rwxr-xr-xcore/res/res/values/strings.xml118
-rw-r--r--core/res/res/values/symbols.xml1
-rw-r--r--core/res/res/xml/profile_default.xml267
-rw-r--r--media/java/android/media/AudioManager.java24
-rw-r--r--media/java/android/media/RingtoneManager.java69
-rw-r--r--policy/src/com/android/internal/policy/impl/GlobalActions.java236
-rwxr-xr-xpolicy/src/com/android/internal/policy/impl/PhoneWindowManager.java154
-rw-r--r--policy/src/com/android/internal/policy/impl/keyguard_obsolete/KeyguardStatusViewManager.java368
-rw-r--r--policy/src/com/android/internal/policy/impl/keyguard_obsolete/KeyguardViewMediator.java51
-rw-r--r--services/java/com/android/server/BatteryService.java165
-rw-r--r--services/java/com/android/server/InputMethodManagerService.java11
-rwxr-xr-xservices/java/com/android/server/NotificationManagerService.java256
-rw-r--r--services/java/com/android/server/ProfileManagerService.java550
-rw-r--r--services/java/com/android/server/SystemServer.java9
-rwxr-xr-xservices/java/com/android/server/VibratorService.java29
-rw-r--r--services/java/com/android/server/power/ShutdownThread.java81
-rwxr-xr-xservices/java/com/android/server/wm/WindowManagerService.java6
221 files changed, 6868 insertions, 230 deletions
diff --git a/Android.mk b/Android.mk
index d38150f..71cd152 100644
--- a/Android.mk
+++ b/Android.mk
@@ -70,6 +70,7 @@ LOCAL_SRC_FILES += \
core/java/android/app/IBackupAgent.aidl \
core/java/android/app/IInstrumentationWatcher.aidl \
core/java/android/app/INotificationManager.aidl \
+ core/java/android/app/IProfileManager.aidl \
core/java/android/app/IProcessObserver.aidl \
core/java/android/app/ISearchManager.aidl \
core/java/android/app/ISearchManagerCallback.aidl \
@@ -270,6 +271,8 @@ aidl_files := \
frameworks/base/core/java/android/accounts/IAccountAuthenticator.aidl \
frameworks/base/core/java/android/accounts/IAccountAuthenticatorResponse.aidl \
frameworks/base/core/java/android/app/Notification.aidl \
+ frameworks/base/core/java/android/app/NotificationGroup.aidl \
+ frameworks/base/core/java/android/app/Profile.aidl \
frameworks/base/core/java/android/app/PendingIntent.aidl \
frameworks/base/core/java/android/bluetooth/BluetoothDevice.aidl \
frameworks/base/core/java/android/bluetooth/BluetoothHealthAppConfiguration.aidl \
diff --git a/core/java/android/app/ConnectionSettings.java b/core/java/android/app/ConnectionSettings.java
new file mode 100755
index 0000000..00af439
--- /dev/null
+++ b/core/java/android/app/ConnectionSettings.java
@@ -0,0 +1,216 @@
+package android.app;
+
+import android.bluetooth.BluetoothAdapter;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.location.LocationManager;
+import android.net.ConnectivityManager;
+import android.net.wifi.WifiManager;
+import android.net.wimax.WimaxHelper;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.provider.Settings;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+
+/** @hide */
+public final class ConnectionSettings implements Parcelable {
+
+ private int mConnectionId;
+ private int mValue;
+ private boolean mOverride;
+ private boolean mDirty;
+
+ public static final int PROFILE_CONNECTION_MOBILEDATA = 0;
+ public static final int PROFILE_CONNECTION_WIFI = 1;
+ public static final int PROFILE_CONNECTION_WIFIAP = 2;
+ public static final int PROFILE_CONNECTION_WIMAX = 3;
+ public static final int PROFILE_CONNECTION_GPS = 4;
+ public static final int PROFILE_CONNECTION_SYNC = 5;
+ public static final int PROFILE_CONNECTION_BLUETOOTH = 7;
+
+ /** @hide */
+ public static final Parcelable.Creator<ConnectionSettings> CREATOR = new Parcelable.Creator<ConnectionSettings>() {
+ public ConnectionSettings createFromParcel(Parcel in) {
+ return new ConnectionSettings(in);
+ }
+
+ @Override
+ public ConnectionSettings[] newArray(int size) {
+ return new ConnectionSettings[size];
+ }
+ };
+
+
+ public ConnectionSettings(Parcel parcel) {
+ readFromParcel(parcel);
+ }
+
+ public ConnectionSettings(int connectionId) {
+ this(connectionId, 0, false);
+ }
+
+ public ConnectionSettings(int connectionId, int value, boolean override) {
+ mConnectionId = connectionId;
+ mValue = value;
+ mOverride = override;
+ mDirty = false;
+ }
+
+ public int getConnectionId() {
+ return mConnectionId;
+ }
+
+ public int getValue() {
+ return mValue;
+ }
+
+ public void setValue(int value) {
+ mValue = value;
+ mDirty = true;
+ }
+
+ public void setOverride(boolean override) {
+ mOverride = override;
+ mDirty = true;
+ }
+
+ public boolean isOverride() {
+ return mOverride;
+ }
+
+ /** @hide */
+ public boolean isDirty() {
+ return mDirty;
+ }
+
+ public void processOverride(Context context) {
+ BluetoothAdapter bta = BluetoothAdapter.getDefaultAdapter();
+ LocationManager lm = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
+ WifiManager wm = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
+ ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
+
+ boolean forcedState = getValue() == 1;
+ boolean currentState;
+
+ switch (getConnectionId()) {
+ case PROFILE_CONNECTION_MOBILEDATA:
+ currentState = cm.getMobileDataEnabled();
+ if (forcedState != currentState) {
+ cm.setMobileDataEnabled(forcedState);
+ }
+ break;
+ case PROFILE_CONNECTION_BLUETOOTH:
+ currentState = bta.isEnabled();
+ if (forcedState && !currentState) {
+ bta.enable();
+ } else if (!forcedState && currentState) {
+ bta.disable();
+ }
+ break;
+ case PROFILE_CONNECTION_GPS:
+ currentState = lm.isProviderEnabled(LocationManager.GPS_PROVIDER);
+ if (currentState != forcedState) {
+ Settings.Secure.setLocationProviderEnabled(context.getContentResolver(),
+ LocationManager.GPS_PROVIDER, forcedState);
+ }
+ break;
+ case PROFILE_CONNECTION_SYNC:
+ currentState = ContentResolver.getMasterSyncAutomatically();
+ if (forcedState != currentState) {
+ ContentResolver.setMasterSyncAutomatically(forcedState);
+ }
+ break;
+ case PROFILE_CONNECTION_WIFI:
+ int wifiApState = wm.getWifiApState();
+ currentState = wm.isWifiEnabled();
+ if (currentState != forcedState) {
+ // Disable wifi tether
+ if (forcedState && (wifiApState == WifiManager.WIFI_AP_STATE_ENABLING) ||
+ (wifiApState == WifiManager.WIFI_AP_STATE_ENABLED)) {
+ wm.setWifiApEnabled(null, false);
+ }
+ wm.setWifiEnabled(forcedState);
+ }
+ break;
+ case PROFILE_CONNECTION_WIFIAP:
+ int wifiState = wm.getWifiState();
+ currentState = wm.isWifiApEnabled();
+ if (currentState != forcedState) {
+ // Disable wifi
+ if (forcedState && (wifiState == WifiManager.WIFI_STATE_ENABLING) || (wifiState == WifiManager.WIFI_STATE_ENABLED)) {
+ wm.setWifiEnabled(false);
+ }
+ wm.setWifiApEnabled(null, forcedState);
+ }
+ break;
+ case PROFILE_CONNECTION_WIMAX:
+ if (WimaxHelper.isWimaxSupported(context)) {
+ currentState = WimaxHelper.isWimaxEnabled(context);
+ if (currentState != forcedState) {
+ WimaxHelper.setWimaxEnabled(context, forcedState);
+ }
+ }
+ break;
+ }
+ }
+
+ /** @hide */
+ public static ConnectionSettings fromXml(XmlPullParser xpp, Context context)
+ throws XmlPullParserException, IOException {
+ int event = xpp.next();
+ ConnectionSettings connectionDescriptor = new ConnectionSettings(0);
+ while (event != XmlPullParser.END_TAG || !xpp.getName().equals("connectionDescriptor")) {
+ if (event == XmlPullParser.START_TAG) {
+ String name = xpp.getName();
+ if (name.equals("connectionId")) {
+ connectionDescriptor.mConnectionId = Integer.parseInt(xpp.nextText());
+ } else if (name.equals("value")) {
+ connectionDescriptor.mValue = Integer.parseInt(xpp.nextText());
+ } else if (name.equals("override")) {
+ connectionDescriptor.mOverride = Boolean.parseBoolean(xpp.nextText());
+ }
+ }
+ event = xpp.next();
+ }
+ return connectionDescriptor;
+ }
+
+ /** @hide */
+ public void getXmlString(StringBuilder builder, Context context) {
+ builder.append("<connectionDescriptor>\n<connectionId>");
+ builder.append(mConnectionId);
+ builder.append("</connectionId>\n<value>");
+ builder.append(mValue);
+ builder.append("</value>\n<override>");
+ builder.append(mOverride);
+ builder.append("</override>\n</connectionDescriptor>\n");
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ /** @hide */
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(mConnectionId);
+ dest.writeInt(mOverride ? 1 : 0);
+ dest.writeInt(mValue);
+ dest.writeInt(mDirty ? 1 : 0);
+ }
+
+ /** @hide */
+ public void readFromParcel(Parcel in) {
+ mConnectionId = in.readInt();
+ mOverride = in.readInt() != 0;
+ mValue = in.readInt();
+ mDirty = in.readInt() != 0;
+ }
+
+
+}
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 95b6bed..20ed560 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -535,6 +535,12 @@ class ContextImpl extends Context {
IUserManager service = IUserManager.Stub.asInterface(b);
return new UserManager(ctx, service);
}});
+
+ registerService(PROFILE_SERVICE, new ServiceFetcher() {
+ public Object createService(ContextImpl ctx) {
+ final Context outerContext = ctx.getOuterContext();
+ return new ProfileManager (outerContext, ctx.mMainThread.getHandler());
+ }});
}
static ContextImpl getImpl(Context context) {
diff --git a/core/java/android/app/IProfileManager.aidl b/core/java/android/app/IProfileManager.aidl
new file mode 100644
index 0000000..c7c6744
--- /dev/null
+++ b/core/java/android/app/IProfileManager.aidl
@@ -0,0 +1,50 @@
+/* //device/java/android/android/app/IProfileManager.aidl
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package android.app;
+
+import android.app.Profile;
+import android.app.NotificationGroup;
+import android.os.ParcelUuid;
+
+/** {@hide} */
+interface IProfileManager
+{
+ boolean setActiveProfile(in ParcelUuid profileParcelUuid);
+ boolean setActiveProfileByName(String profileName);
+ Profile getActiveProfile();
+
+ boolean addProfile(in Profile profile);
+ boolean removeProfile(in Profile profile);
+ void updateProfile(in Profile profile);
+
+ Profile getProfile(in ParcelUuid profileParcelUuid);
+ Profile getProfileByName(String profileName);
+ Profile[] getProfiles();
+ boolean profileExists(in ParcelUuid profileUuid);
+ boolean profileExistsByName(String profileName);
+ boolean notificationGroupExistsByName(String notificationGroupName);
+
+ NotificationGroup[] getNotificationGroups();
+ void addNotificationGroup(in NotificationGroup group);
+ void removeNotificationGroup(in NotificationGroup group);
+ void updateNotificationGroup(in NotificationGroup group);
+ NotificationGroup getNotificationGroupForPackage(in String pkg);
+ NotificationGroup getNotificationGroup(in ParcelUuid groupParcelUuid);
+
+ void resetAll();
+}
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index e79b214..238a63e 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -437,6 +437,15 @@ public class Notification implements Parcelable
*/
public static final String EXTRA_PEOPLE = "android.people";
+ /**
+ * Bit to be bitwise-ored into the {@link #flags} field that should be
+ * set if this notification should force the led to pulse even if the
+ * screen has been shut off while the notification was active.
+ *
+ * @hide
+ */
+ public static final int FLAG_FORCE_LED_SCREEN_OFF = 0x00000100;
+
private Bundle extras;
/**
diff --git a/core/java/android/app/NotificationGroup.aidl b/core/java/android/app/NotificationGroup.aidl
new file mode 100644
index 0000000..44b6290
--- /dev/null
+++ b/core/java/android/app/NotificationGroup.aidl
@@ -0,0 +1,19 @@
+/**
+ * Copyright (c) 2012, The CyanogenMod Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app;
+
+parcelable NotificationGroup;
diff --git a/core/java/android/app/NotificationGroup.java b/core/java/android/app/NotificationGroup.java
new file mode 100644
index 0000000..bcb70d3
--- /dev/null
+++ b/core/java/android/app/NotificationGroup.java
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import android.content.Context;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.ParcelUuid;
+import android.os.RemoteException;
+import android.text.TextUtils;
+import android.util.Log;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.UUID;
+
+/** @hide */
+public class NotificationGroup implements Parcelable {
+ private static final String TAG = "NotificationGroup";
+
+ private String mName;
+ private int mNameResId;
+
+ private UUID mUuid;
+
+ private Set<String> mPackages = new HashSet<String>();
+
+ private boolean mDirty;
+
+ public static final Parcelable.Creator<NotificationGroup> CREATOR = new Parcelable.Creator<NotificationGroup>() {
+ public NotificationGroup createFromParcel(Parcel in) {
+ return new NotificationGroup(in);
+ }
+
+ @Override
+ public NotificationGroup[] newArray(int size) {
+ return new NotificationGroup[size];
+ }
+ };
+
+ public NotificationGroup(String name) {
+ this(name, -1, null);
+ }
+
+ public NotificationGroup(String name, int nameResId, UUID uuid) {
+ mName = name;
+ mNameResId = nameResId;
+ mUuid = (uuid != null) ? uuid : UUID.randomUUID();
+ mDirty = uuid == null;
+ }
+
+ private NotificationGroup(Parcel in) {
+ readFromParcel(in);
+ }
+
+ @Override
+ public String toString() {
+ return getName();
+ }
+
+ public String getName() {
+ return mName;
+ }
+
+ public void setName(String name) {
+ mName = name;
+ mNameResId = -1;
+ mDirty = true;
+ }
+
+ public UUID getUuid() {
+ return mUuid;
+ }
+
+ public void addPackage(String pkg) {
+ mPackages.add(pkg);
+ mDirty = true;
+ }
+
+ public String[] getPackages() {
+ return mPackages.toArray(new String[mPackages.size()]);
+ }
+
+ public void removePackage(String pkg) {
+ mPackages.remove(pkg);
+ mDirty = true;
+ }
+
+ public boolean hasPackage(String pkg) {
+ return mPackages.contains(pkg);
+ }
+
+ public boolean isDirty() {
+ return mDirty;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(mName);
+ dest.writeInt(mNameResId);
+ dest.writeInt(mDirty ? 1 : 0);
+ new ParcelUuid(mUuid).writeToParcel(dest, 0);
+ dest.writeStringArray(getPackages());
+ }
+
+ public void readFromParcel(Parcel in) {
+ mName = in.readString();
+ mNameResId = in.readInt();
+ mDirty = in.readInt() != 0;
+ mUuid = ParcelUuid.CREATOR.createFromParcel(in).getUuid();
+ mPackages.addAll(Arrays.asList(in.readStringArray()));
+ }
+
+ public void getXmlString(StringBuilder builder, Context context) {
+ builder.append("<notificationGroup ");
+ if (mNameResId > 0) {
+ builder.append("nameres=\"");
+ builder.append(context.getResources().getResourceEntryName(mNameResId));
+ } else {
+ builder.append("name=\"");
+ builder.append(TextUtils.htmlEncode(getName()));
+ }
+ builder.append("\" uuid=\"");
+ builder.append(TextUtils.htmlEncode(getUuid().toString()));
+ builder.append("\">\n");
+ for (String pkg : mPackages) {
+ builder.append("<package>" + TextUtils.htmlEncode(pkg) + "</package>\n");
+ }
+ builder.append("</notificationGroup>\n");
+ mDirty = false;
+ }
+
+ public static NotificationGroup fromXml(XmlPullParser xpp, Context context)
+ throws XmlPullParserException, IOException {
+ String value = xpp.getAttributeValue(null, "nameres");
+ int nameResId = -1;
+ String name = null;
+ UUID uuid = null;
+
+ if (value != null) {
+ nameResId = context.getResources().getIdentifier(value, "string", "android");
+ if (nameResId > 0) {
+ name = context.getResources().getString(nameResId);
+ }
+ }
+
+ if (name == null) {
+ name = xpp.getAttributeValue(null, "name");
+ }
+
+ value = xpp.getAttributeValue(null, "uuid");
+ if (value != null) {
+ try {
+ uuid = UUID.fromString(value);
+ } catch (IllegalArgumentException e) {
+ Log.w(TAG, "UUID not recognized for " + name + ", using new one.");
+ }
+ }
+
+ NotificationGroup notificationGroup = new NotificationGroup(name, nameResId, uuid);
+ int event = xpp.next();
+ while (event != XmlPullParser.END_TAG || !xpp.getName().equals("notificationGroup")) {
+ if (event == XmlPullParser.START_TAG) {
+ if (xpp.getName().equals("package")) {
+ String pkg = xpp.nextText();
+ notificationGroup.addPackage(pkg);
+ }
+ }
+ event = xpp.next();
+ }
+
+ /* we just loaded from XML, no need to save */
+ notificationGroup.mDirty = false;
+
+ return notificationGroup;
+ }
+}
diff --git a/core/java/android/app/Profile.aidl b/core/java/android/app/Profile.aidl
new file mode 100644
index 0000000..d75bd76
--- /dev/null
+++ b/core/java/android/app/Profile.aidl
@@ -0,0 +1,19 @@
+/**
+ * Copyright (c) 2007, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app;
+
+parcelable Profile;
diff --git a/core/java/android/app/Profile.java b/core/java/android/app/Profile.java
new file mode 100644
index 0000000..54e187d
--- /dev/null
+++ b/core/java/android/app/Profile.java
@@ -0,0 +1,595 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app;
+
+import android.content.Context;
+import android.content.Intent;
+import android.media.AudioManager;
+import android.os.Parcel;
+import android.os.ParcelUuid;
+import android.os.Parcelable;
+import android.provider.Settings;
+import android.text.TextUtils;
+import android.util.Log;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+
+/**
+ * @hide
+ */
+public final class Profile implements Parcelable, Comparable {
+
+ private String mName;
+
+ private int mNameResId;
+
+ private UUID mUuid;
+
+ private ArrayList<UUID> mSecondaryUuids = new ArrayList<UUID>();
+
+ private Map<UUID, ProfileGroup> profileGroups = new HashMap<UUID, ProfileGroup>();
+
+ private ProfileGroup mDefaultGroup;
+
+ private boolean mStatusBarIndicator = false;
+
+ private boolean mDirty;
+
+ private static final String TAG = "Profile";
+
+ private int mProfileType;
+
+ private static final int CONDITIONAL_TYPE = 1;
+
+ private static final int TOGGLE_TYPE = 0;
+
+ private Map<Integer, StreamSettings> streams = new HashMap<Integer, StreamSettings>();
+
+ private Map<Integer, ConnectionSettings> connections = new HashMap<Integer, ConnectionSettings>();
+
+ private Map<Integer, VibratorSettings> vibrators = new HashMap<Integer, VibratorSettings>();
+
+ private int mScreenLockMode = LockMode.DEFAULT;
+
+ private int mAirplaneMode = AirplaneMode.DEFAULT;
+
+ /** @hide */
+ public static class LockMode {
+ public static final int DEFAULT = 0;
+ public static final int INSECURE = 1;
+ public static final int DISABLE = 2;
+ }
+
+ /** @hide */
+ public static class AirplaneMode {
+ public static final int DEFAULT = 0;
+ public static final int ENABLE = 1;
+ public static final int DISABLE = 2;
+ }
+
+ /** @hide */
+ public static final Parcelable.Creator<Profile> CREATOR = new Parcelable.Creator<Profile>() {
+ public Profile createFromParcel(Parcel in) {
+ return new Profile(in);
+ }
+
+ @Override
+ public Profile[] newArray(int size) {
+ return new Profile[size];
+ }
+ };
+
+ /** @hide */
+ public Profile(String name) {
+ this(name, -1, UUID.randomUUID());
+ }
+
+ private Profile(String name, int nameResId, UUID uuid) {
+ mName = name;
+ mNameResId = nameResId;
+ mUuid = uuid;
+ mProfileType = TOGGLE_TYPE; //Default to toggle type
+ mDirty = false;
+ }
+
+ private Profile(Parcel in) {
+ readFromParcel(in);
+ }
+
+ public int compareTo(Object obj)
+ {
+ Profile tmp = (Profile) obj;
+ if (mName.compareTo(tmp.mName) < 0) {
+ return -1;
+ } else if (mName.compareTo(tmp.mName) > 0) {
+ return 1;
+ }
+ return 0;
+ }
+
+ /** @hide */
+ public void addProfileGroup(ProfileGroup value) {
+ if (value.isDefaultGroup()) {
+ /* we must not have more than one default group */
+ if (mDefaultGroup != null) {
+ return;
+ }
+ mDefaultGroup = value;
+ }
+ profileGroups.put(value.getUuid(), value);
+ mDirty = true;
+ }
+
+ /** @hide */
+ public void removeProfileGroup(UUID uuid) {
+ if (!profileGroups.get(uuid).isDefaultGroup()) {
+ profileGroups.remove(uuid);
+ } else {
+ Log.e(TAG, "Cannot remove default group: " + uuid);
+ }
+ }
+
+ public ProfileGroup[] getProfileGroups() {
+ return profileGroups.values().toArray(new ProfileGroup[profileGroups.size()]);
+ }
+
+ public ProfileGroup getProfileGroup(UUID uuid) {
+ return profileGroups.get(uuid);
+ }
+
+ public ProfileGroup getDefaultGroup() {
+ return mDefaultGroup;
+ }
+
+ /** @hide */
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ /** @hide */
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(mName);
+ dest.writeInt(mNameResId);
+ new ParcelUuid(mUuid).writeToParcel(dest, 0);
+ ArrayList<ParcelUuid> uuids = new ArrayList<ParcelUuid>(mSecondaryUuids.size());
+ for (UUID u : mSecondaryUuids) {
+ uuids.add(new ParcelUuid(u));
+ }
+ dest.writeParcelableArray(uuids.toArray(new Parcelable[uuids.size()]), flags);
+ dest.writeInt(mStatusBarIndicator ? 1 : 0);
+ dest.writeInt(mProfileType);
+ dest.writeInt(mDirty ? 1 : 0);
+ dest.writeParcelableArray(
+ profileGroups.values().toArray(new Parcelable[profileGroups.size()]), flags);
+ dest.writeParcelableArray(
+ streams.values().toArray(new Parcelable[streams.size()]), flags);
+ dest.writeParcelableArray(
+ connections.values().toArray(new Parcelable[connections.size()]), flags);
+ dest.writeParcelableArray(vibrators.values().toArray(new Parcelable[vibrators.size()]), flags);
+ dest.writeInt(mScreenLockMode);
+ dest.writeInt(mAirplaneMode);
+ }
+
+ /** @hide */
+ public void readFromParcel(Parcel in) {
+ mName = in.readString();
+ mNameResId = in.readInt();
+ mUuid = ParcelUuid.CREATOR.createFromParcel(in).getUuid();
+ for (Parcelable parcel : in.readParcelableArray(null)) {
+ ParcelUuid u = (ParcelUuid) parcel;
+ mSecondaryUuids.add(u.getUuid());
+ }
+ mStatusBarIndicator = (in.readInt() == 1);
+ mProfileType = in.readInt();
+ mDirty = (in.readInt() == 1);
+ for (Parcelable group : in.readParcelableArray(null)) {
+ ProfileGroup grp = (ProfileGroup) group;
+ profileGroups.put(grp.getUuid(), grp);
+ if (grp.isDefaultGroup()) {
+ mDefaultGroup = grp;
+ }
+ }
+ for (Parcelable parcel : in.readParcelableArray(null)) {
+ StreamSettings stream = (StreamSettings) parcel;
+ streams.put(stream.getStreamId(), stream);
+ }
+ for (Parcelable parcel : in.readParcelableArray(null)) {
+ ConnectionSettings connection = (ConnectionSettings) parcel;
+ connections.put(connection.getConnectionId(), connection);
+ }
+ for (Parcelable parcel : in.readParcelableArray(null)) {
+ VibratorSettings vibrator = (VibratorSettings) parcel;
+ vibrators.put(vibrator.getVibratorId(), vibrator);
+ }
+ mScreenLockMode = in.readInt();
+ mAirplaneMode = in.readInt();
+ }
+
+ public String getName() {
+ return mName;
+ }
+
+ /** @hide */
+ public void setName(String name) {
+ mName = name;
+ mNameResId = -1;
+ mDirty = true;
+ }
+
+ public int getProfileType() {
+ return mProfileType;
+ }
+
+ /** @hide */
+ public void setProfileType(int type) {
+ mProfileType = type;
+ mDirty = true;
+ }
+
+ public UUID getUuid() {
+ if (this.mUuid == null) this.mUuid = UUID.randomUUID();
+ return this.mUuid;
+ }
+
+ public UUID[] getSecondaryUuids() {
+ return mSecondaryUuids.toArray(new UUID[mSecondaryUuids.size()]);
+ }
+
+ public void setSecondaryUuids(List<UUID> uuids) {
+ mSecondaryUuids.clear();
+ if (uuids != null) {
+ mSecondaryUuids.addAll(uuids);
+ mDirty = true;
+ }
+ }
+
+ public void addSecondaryUuid(UUID uuid) {
+ if (uuid != null) {
+ mSecondaryUuids.add(uuid);
+ mDirty = true;
+ }
+ }
+
+ public boolean getStatusBarIndicator() {
+ return mStatusBarIndicator;
+ }
+
+ public void setStatusBarIndicator(boolean newStatusBarIndicator) {
+ mStatusBarIndicator = newStatusBarIndicator;
+ mDirty = true;
+ }
+
+ public boolean isConditionalType() {
+ return(mProfileType == CONDITIONAL_TYPE ? true : false);
+ }
+
+ public void setConditionalType() {
+ mProfileType = CONDITIONAL_TYPE;
+ mDirty = true;
+ }
+
+ public int getScreenLockMode() {
+ return mScreenLockMode;
+ }
+
+ public void setScreenLockMode(int screenLockMode) {
+ if (screenLockMode < LockMode.DEFAULT || screenLockMode > LockMode.DISABLE) {
+ mScreenLockMode = LockMode.DEFAULT;
+ } else {
+ mScreenLockMode = screenLockMode;
+ }
+ mDirty = true;
+ }
+
+ public int getAirplaneMode() {
+ return mAirplaneMode;
+ }
+
+ public void setAirplaneMode(int airplaneMode) {
+ if (airplaneMode < AirplaneMode.DEFAULT || airplaneMode > AirplaneMode.DISABLE) {
+ mAirplaneMode = AirplaneMode.DEFAULT;
+ } else {
+ mAirplaneMode = airplaneMode;
+ }
+ mDirty = true;
+ }
+
+ /** @hide */
+ public boolean isDirty() {
+ if (mDirty) {
+ return true;
+ }
+ for (ProfileGroup group : profileGroups.values()) {
+ if (group.isDirty()) {
+ return true;
+ }
+ }
+ for (StreamSettings stream : streams.values()) {
+ if (stream.isDirty()) {
+ return true;
+ }
+ }
+ for (ConnectionSettings conn : connections.values()) {
+ if (conn.isDirty()) {
+ return true;
+ }
+ }
+ for (VibratorSettings vibrator : vibrators.values()) {
+ if (vibrator.isDirty()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /** @hide */
+ public void getXmlString(StringBuilder builder, Context context) {
+ builder.append("<profile ");
+ if (mNameResId > 0) {
+ builder.append("nameres=\"");
+ builder.append(context.getResources().getResourceEntryName(mNameResId));
+ } else {
+ builder.append("name=\"");
+ builder.append(TextUtils.htmlEncode(getName()));
+ }
+ builder.append("\" uuid=\"");
+ builder.append(TextUtils.htmlEncode(getUuid().toString()));
+ builder.append("\">\n");
+
+ builder.append("<uuids>");
+ for (UUID u : mSecondaryUuids) {
+ builder.append("<uuid>");
+ builder.append(TextUtils.htmlEncode(u.toString()));
+ builder.append("</uuid>");
+ }
+ builder.append("</uuids>\n");
+
+ builder.append("<profiletype>");
+ builder.append(getProfileType() == TOGGLE_TYPE ? "toggle" : "conditional");
+ builder.append("</profiletype>\n");
+
+ builder.append("<statusbar>");
+ builder.append(getStatusBarIndicator() ? "yes" : "no");
+ builder.append("</statusbar>\n");
+
+ builder.append("<screen-lock-mode>");
+ builder.append(mScreenLockMode);
+ builder.append("</screen-lock-mode>\n");
+
+ builder.append("<airplane-mode>");
+ builder.append(mAirplaneMode);
+ builder.append("</airplane-mode>\n");
+
+ for (ProfileGroup pGroup : profileGroups.values()) {
+ pGroup.getXmlString(builder, context);
+ }
+ for (StreamSettings sd : streams.values()) {
+ sd.getXmlString(builder, context);
+ }
+ for (ConnectionSettings cs : connections.values()) {
+ cs.getXmlString(builder, context);
+ }
+ for (VibratorSettings vs : vibrators.values()) {
+ vs.getXmlString(builder, context);
+ }
+ builder.append("</profile>\n");
+ mDirty = false;
+ }
+
+ private static List<UUID> readSecondaryUuidsFromXml(XmlPullParser xpp, Context context)
+ throws XmlPullParserException,
+ IOException {
+ ArrayList<UUID> uuids = new ArrayList<UUID>();
+ int event = xpp.next();
+ while (event != XmlPullParser.END_TAG || !xpp.getName().equals("uuids")) {
+ if (event == XmlPullParser.START_TAG) {
+ String name = xpp.getName();
+ if (name.equals("uuid")) {
+ try {
+ uuids.add(UUID.fromString(xpp.nextText()));
+ } catch (NullPointerException e) {
+ Log.w(TAG, "Null Pointer - invalid UUID");
+ } catch (IllegalArgumentException e) {
+ Log.w(TAG, "UUID not recognized");
+ }
+ }
+ }
+ event = xpp.next();
+ }
+ return uuids;
+ }
+
+ /** @hide */
+ public static Profile fromXml(XmlPullParser xpp, Context context)
+ throws XmlPullParserException, IOException {
+ String value = xpp.getAttributeValue(null, "nameres");
+ int profileNameResId = -1;
+ String profileName = null;
+
+ if (value != null) {
+ profileNameResId = context.getResources().getIdentifier(value, "string", "android");
+ if (profileNameResId > 0) {
+ profileName = context.getResources().getString(profileNameResId);
+ }
+ }
+
+ if (profileName == null) {
+ profileName = xpp.getAttributeValue(null, "name");
+ }
+
+ UUID profileUuid = UUID.randomUUID();
+ try {
+ profileUuid = UUID.fromString(xpp.getAttributeValue(null, "uuid"));
+ } catch (NullPointerException e) {
+ Log.w(TAG,
+ "Null Pointer - UUID not found for "
+ + profileName
+ + ". New UUID generated: "
+ + profileUuid.toString()
+ );
+ } catch (IllegalArgumentException e) {
+ Log.w(TAG,
+ "UUID not recognized for "
+ + profileName
+ + ". New UUID generated: "
+ + profileUuid.toString()
+ );
+ }
+
+ Profile profile = new Profile(profileName, profileNameResId, profileUuid);
+ int event = xpp.next();
+ while (event != XmlPullParser.END_TAG) {
+ if (event == XmlPullParser.START_TAG) {
+ String name = xpp.getName();
+ if (name.equals("uuids")) {
+ profile.setSecondaryUuids(readSecondaryUuidsFromXml(xpp, context));
+ }
+ if (name.equals("statusbar")) {
+ profile.setStatusBarIndicator(xpp.nextText().equals("yes"));
+ }
+ if (name.equals("profiletype")) {
+ profile.setProfileType(xpp.nextText().equals("toggle") ? TOGGLE_TYPE : CONDITIONAL_TYPE);
+ }
+ if (name.equals("screen-lock-mode")) {
+ profile.setScreenLockMode(Integer.valueOf(xpp.nextText()));
+ }
+ if (name.equals("airplane-mode")) {
+ profile.setAirplaneMode(Integer.valueOf(xpp.nextText()));
+ }
+ if (name.equals("profileGroup")) {
+ ProfileGroup pg = ProfileGroup.fromXml(xpp, context);
+ profile.addProfileGroup(pg);
+ }
+ if (name.equals("streamDescriptor")) {
+ StreamSettings sd = StreamSettings.fromXml(xpp, context);
+ profile.setStreamSettings(sd);
+ }
+ if (name.equals("connectionDescriptor")) {
+ ConnectionSettings cs = ConnectionSettings.fromXml(xpp, context);
+ profile.connections.put(cs.getConnectionId(), cs);
+ }
+ if (name.equals("vibratorDescriptor")) {
+ VibratorSettings vs = VibratorSettings.fromXml(xpp, context);
+ profile.setVibratorSettings(vs);
+ }
+ }
+ event = xpp.next();
+ }
+
+ /* we just loaded from XML, so nothing needs saving */
+ profile.mDirty = false;
+
+ return profile;
+ }
+
+ /** @hide */
+ public void doSelect(Context context) {
+ // Set stream volumes
+ AudioManager am = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
+ for (StreamSettings sd : streams.values()) {
+ if (sd.isOverride()) {
+ am.setStreamVolume(sd.getStreamId(), sd.getValue(), 0);
+ }
+ }
+ // Set connections
+ for (ConnectionSettings cs : connections.values()) {
+ if (cs.isOverride()) {
+ cs.processOverride(context);
+ }
+ }
+ // Set vibrators
+ for (VibratorSettings vs : vibrators.values()) {
+ if (vs.isOverride()) {
+ vs.processOverride(context);
+ }
+ }
+ // Set airplane mode
+ doSelectAirplaneMode(context);
+ }
+
+ private void doSelectAirplaneMode(Context context) {
+ if (getAirplaneMode() != AirplaneMode.DEFAULT) {
+ int current = Settings.System.getInt(context.getContentResolver(), Settings.System.AIRPLANE_MODE_ON, 0);
+ int target = getAirplaneMode();
+ if (current == 1 && target == AirplaneMode.DISABLE || current == 0 && target == AirplaneMode.ENABLE) {
+ Settings.System.putInt(context.getContentResolver(), Settings.System.AIRPLANE_MODE_ON, 1 - current);
+ Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
+ intent.putExtra("state", target != AirplaneMode.DISABLE);
+ context.sendBroadcast(intent);
+ }
+ }
+ }
+
+ /** @hide */
+ public StreamSettings getSettingsForStream(int streamId){
+ return streams.get(streamId);
+ }
+
+ /** @hide */
+ public void setStreamSettings(StreamSettings descriptor){
+ streams.put(descriptor.getStreamId(), descriptor);
+ mDirty = true;
+ }
+
+ /** @hide */
+ public Collection<StreamSettings> getStreamSettings(){
+ return streams.values();
+ }
+
+ /** @hide */
+ public VibratorSettings getSettingsForVibrator(int vibratorId) {
+ return vibrators.get(vibratorId);
+ }
+
+ /** @hide */
+ public void setVibratorSettings(VibratorSettings descriptor) {
+ vibrators.put(descriptor.getVibratorId(), descriptor);
+ mDirty = true;
+ }
+
+ /** @hide */
+ public Collection<VibratorSettings> getVibratorSettings() {
+ return vibrators.values();
+ }
+
+ /** @hide */
+ public ConnectionSettings getSettingsForConnection(int connectionId){
+ return connections.get(connectionId);
+ }
+
+ /** @hide */
+ public void setConnectionSettings(ConnectionSettings descriptor){
+ connections.put(descriptor.getConnectionId(), descriptor);
+ }
+
+ /** @hide */
+ public Collection<ConnectionSettings> getConnectionSettings(){
+ return connections.values();
+ }
+
+}
diff --git a/core/java/android/app/ProfileGroup.java b/core/java/android/app/ProfileGroup.java
new file mode 100644
index 0000000..b3b70d6
--- /dev/null
+++ b/core/java/android/app/ProfileGroup.java
@@ -0,0 +1,348 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import android.content.Context;
+import android.media.RingtoneManager;
+import android.net.Uri;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.ParcelUuid;
+import android.text.TextUtils;
+import android.util.Log;
+
+import java.io.IOException;
+import java.util.UUID;
+
+/**
+ * @hide
+ */
+public final class ProfileGroup implements Parcelable {
+ private static final String TAG = "ProfileGroup";
+
+ private String mName;
+ private int mNameResId;
+
+ private UUID mUuid;
+
+ private Uri mSoundOverride = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
+ private Uri mRingerOverride = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_RINGTONE);
+
+ private Mode mSoundMode = Mode.DEFAULT;
+ private Mode mRingerMode = Mode.DEFAULT;
+ private Mode mVibrateMode = Mode.DEFAULT;
+ private Mode mLightsMode = Mode.DEFAULT;
+
+ private boolean mDefaultGroup = false;
+ private boolean mDirty;
+
+ /** @hide */
+ public static final Parcelable.Creator<ProfileGroup> CREATOR = new Parcelable.Creator<ProfileGroup>() {
+ public ProfileGroup createFromParcel(Parcel in) {
+ return new ProfileGroup(in);
+ }
+
+ @Override
+ public ProfileGroup[] newArray(int size) {
+ return new ProfileGroup[size];
+ }
+ };
+
+ /** @hide */
+ public ProfileGroup(UUID uuid, boolean defaultGroup) {
+ this(null, uuid, defaultGroup);
+ }
+
+ private ProfileGroup(String name, UUID uuid, boolean defaultGroup) {
+ mName = name;
+ mUuid = (uuid != null) ? uuid : UUID.randomUUID();
+ mDefaultGroup = defaultGroup;
+ mDirty = uuid == null;
+ }
+
+ /** @hide */
+ private ProfileGroup(Parcel in) {
+ readFromParcel(in);
+ }
+
+ /** @hide */
+ public boolean matches(NotificationGroup group, boolean defaultGroup) {
+ if (mUuid.equals(group.getUuid())) {
+ return true;
+ }
+
+ /* fallback matches for backwards compatibility */
+ boolean matches = false;
+
+ /* fallback attempt 1: match name */
+ if (mName != null && mName.equals(group.getName())) {
+ matches = true;
+ /* fallback attempt 2: match for the 'defaultGroup' flag to match the wildcard group */
+ } else if (mDefaultGroup && defaultGroup) {
+ matches = true;
+ }
+
+ if (!matches) {
+ return false;
+ }
+
+ mName = null;
+ mUuid = group.getUuid();
+ mDirty = true;
+
+ return true;
+ }
+
+ public UUID getUuid() {
+ return mUuid;
+ }
+
+ public boolean isDefaultGroup() {
+ return mDefaultGroup;
+ }
+
+ /** @hide */
+ public boolean isDirty() {
+ return mDirty;
+ }
+
+ /** @hide */
+ public void setSoundOverride(Uri sound) {
+ mSoundOverride = sound;
+ mDirty = true;
+ }
+
+ public Uri getSoundOverride() {
+ return mSoundOverride;
+ }
+
+ /** @hide */
+ public void setRingerOverride(Uri ringer) {
+ mRingerOverride = ringer;
+ mDirty = true;
+ }
+
+ public Uri getRingerOverride() {
+ return mRingerOverride;
+ }
+
+ /** @hide */
+ public void setSoundMode(Mode soundMode) {
+ mSoundMode = soundMode;
+ mDirty = true;
+ }
+
+ public Mode getSoundMode() {
+ return mSoundMode;
+ }
+
+ /** @hide */
+ public void setRingerMode(Mode ringerMode) {
+ mRingerMode = ringerMode;
+ mDirty = true;
+ }
+
+ public Mode getRingerMode() {
+ return mRingerMode;
+ }
+
+ /** @hide */
+ public void setVibrateMode(Mode vibrateMode) {
+ mVibrateMode = vibrateMode;
+ mDirty = true;
+ }
+
+ public Mode getVibrateMode() {
+ return mVibrateMode;
+ }
+
+ /** @hide */
+ public void setLightsMode(Mode lightsMode) {
+ mLightsMode = lightsMode;
+ mDirty = true;
+ }
+
+ public Mode getLightsMode() {
+ return mLightsMode;
+ }
+
+ // TODO : add support for LEDs / screen etc.
+
+ /** @hide */
+ public Notification processNotification(Notification notification) {
+
+ switch (mSoundMode) {
+ case OVERRIDE:
+ notification.sound = mSoundOverride;
+ break;
+ case SUPPRESS:
+ silenceNotification(notification);
+ break;
+ case DEFAULT:
+ }
+ switch (mVibrateMode) {
+ case OVERRIDE:
+ notification.defaults |= Notification.DEFAULT_VIBRATE;
+ break;
+ case SUPPRESS:
+ suppressVibrate(notification);
+ break;
+ case DEFAULT:
+ }
+ switch (mLightsMode) {
+ case OVERRIDE:
+ notification.defaults |= Notification.DEFAULT_LIGHTS;
+ break;
+ case SUPPRESS:
+ suppressLights(notification);
+ break;
+ case DEFAULT:
+ }
+ return notification;
+ }
+
+ private void silenceNotification(Notification notification) {
+ notification.defaults &= (~Notification.DEFAULT_SOUND);
+ notification.sound = null;
+ }
+
+ private void suppressVibrate(Notification notification) {
+ notification.defaults &= (~Notification.DEFAULT_VIBRATE);
+ notification.vibrate = null;
+ }
+
+ private void suppressLights(Notification notification) {
+ notification.defaults &= (~Notification.DEFAULT_LIGHTS);
+ notification.flags &= (~Notification.FLAG_SHOW_LIGHTS);
+ }
+
+ /** @hide */
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ /** @hide */
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(mName);
+ new ParcelUuid(mUuid).writeToParcel(dest, 0);
+ dest.writeInt(mDefaultGroup ? 1 : 0);
+ dest.writeInt(mDirty ? 1 : 0);
+ dest.writeParcelable(mSoundOverride, flags);
+ dest.writeParcelable(mRingerOverride, flags);
+
+ dest.writeString(mSoundMode.name());
+ dest.writeString(mRingerMode.name());
+ dest.writeString(mVibrateMode.name());
+ dest.writeString(mLightsMode.name());
+ }
+
+ /** @hide */
+ public void readFromParcel(Parcel in) {
+ mName = in.readString();
+ mUuid = ParcelUuid.CREATOR.createFromParcel(in).getUuid();
+ mDefaultGroup = in.readInt() != 0;
+ mDirty = in.readInt() != 0;
+ mSoundOverride = in.readParcelable(null);
+ mRingerOverride = in.readParcelable(null);
+
+ mSoundMode = Mode.valueOf(Mode.class, in.readString());
+ mRingerMode = Mode.valueOf(Mode.class, in.readString());
+ mVibrateMode = Mode.valueOf(Mode.class, in.readString());
+ mLightsMode = Mode.valueOf(Mode.class, in.readString());
+ }
+
+ public enum Mode {
+ SUPPRESS, DEFAULT, OVERRIDE;
+ }
+
+ /** @hide */
+ public void getXmlString(StringBuilder builder, Context context) {
+ builder.append("<profileGroup uuid=\"");
+ builder.append(TextUtils.htmlEncode(mUuid.toString()));
+ if (mName != null) {
+ builder.append("\" name=\"");
+ builder.append(mName);
+ }
+ builder.append("\" default=\"");
+ builder.append(isDefaultGroup());
+ builder.append("\">\n<sound>");
+ builder.append(TextUtils.htmlEncode(mSoundOverride.toString()));
+ builder.append("</sound>\n<ringer>");
+ builder.append(TextUtils.htmlEncode(mRingerOverride.toString()));
+ builder.append("</ringer>\n<soundMode>");
+ builder.append(mSoundMode);
+ builder.append("</soundMode>\n<ringerMode>");
+ builder.append(mRingerMode);
+ builder.append("</ringerMode>\n<vibrateMode>");
+ builder.append(mVibrateMode);
+ builder.append("</vibrateMode>\n<lightsMode>");
+ builder.append(mLightsMode);
+ builder.append("</lightsMode>\n</profileGroup>\n");
+ mDirty = false;
+ }
+
+ /** @hide */
+ public static ProfileGroup fromXml(XmlPullParser xpp, Context context)
+ throws XmlPullParserException, IOException {
+ String name = xpp.getAttributeValue(null, "name");
+ UUID uuid = null;
+ String value = xpp.getAttributeValue(null, "uuid");
+
+ if (value != null) {
+ try {
+ uuid = UUID.fromString(value);
+ } catch (IllegalArgumentException e) {
+ Log.w(TAG, "UUID not recognized for " + name + ", using new one.");
+ }
+ }
+
+ value = xpp.getAttributeValue(null, "default");
+ boolean defaultGroup = TextUtils.equals(value, "true");
+
+ ProfileGroup profileGroup = new ProfileGroup(name, uuid, defaultGroup);
+ int event = xpp.next();
+ while (event != XmlPullParser.END_TAG || !xpp.getName().equals("profileGroup")) {
+ if (event == XmlPullParser.START_TAG) {
+ name = xpp.getName();
+ if (name.equals("sound")) {
+ profileGroup.setSoundOverride(Uri.parse(xpp.nextText()));
+ } else if (name.equals("ringer")) {
+ profileGroup.setRingerOverride(Uri.parse(xpp.nextText()));
+ } else if (name.equals("soundMode")) {
+ profileGroup.setSoundMode(Mode.valueOf(xpp.nextText()));
+ } else if (name.equals("ringerMode")) {
+ profileGroup.setRingerMode(Mode.valueOf(xpp.nextText()));
+ } else if (name.equals("vibrateMode")) {
+ profileGroup.setVibrateMode(Mode.valueOf(xpp.nextText()));
+ } else if (name.equals("lightsMode")) {
+ profileGroup.setLightsMode(Mode.valueOf(xpp.nextText()));
+ }
+ }
+ event = xpp.next();
+ }
+
+ /* we just loaded from XML, no need to save */
+ profileGroup.mDirty = false;
+
+ return profileGroup;
+ }
+}
diff --git a/core/java/android/app/ProfileManager.java b/core/java/android/app/ProfileManager.java
new file mode 100644
index 0000000..4a0f1b7
--- /dev/null
+++ b/core/java/android/app/ProfileManager.java
@@ -0,0 +1,260 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app;
+
+import java.util.UUID;
+
+import android.content.Context;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.ParcelUuid;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.Log;
+
+/**
+ * @hide
+ */
+public class ProfileManager {
+
+ private static IProfileManager sService;
+
+ private Context mContext;
+
+ private static final String TAG = "ProfileManager";
+
+ /** @hide */
+ static public IProfileManager getService() {
+ if (sService != null) {
+ return sService;
+ }
+ IBinder b = ServiceManager.getService(Context.PROFILE_SERVICE);
+ sService = IProfileManager.Stub.asInterface(b);
+ return sService;
+ }
+
+ /** @hide */
+ ProfileManager(Context context, Handler handler) {
+ mContext = context;
+ }
+
+ @Deprecated
+ public void setActiveProfile(String profileName) {
+ try {
+ getService().setActiveProfileByName(profileName);
+ } catch (RemoteException e) {
+ Log.e(TAG, e.getLocalizedMessage(), e);
+ }
+ }
+
+ public void setActiveProfile(UUID profileUuid) {
+ try {
+ getService().setActiveProfile(new ParcelUuid(profileUuid));
+ } catch (RemoteException e) {
+ Log.e(TAG, e.getLocalizedMessage(), e);
+ }
+ }
+
+ public Profile getActiveProfile() {
+ try {
+ return getService().getActiveProfile();
+ } catch (RemoteException e) {
+ Log.e(TAG, e.getLocalizedMessage(), e);
+ }
+ return null;
+ }
+
+ /** @hide */
+ public void addProfile(Profile profile) {
+ try {
+ getService().addProfile(profile);
+ } catch (RemoteException e) {
+ Log.e(TAG, e.getLocalizedMessage(), e);
+ }
+ }
+
+ /** @hide */
+ public void removeProfile(Profile profile) {
+ try {
+ getService().removeProfile(profile);
+ } catch (RemoteException e) {
+ Log.e(TAG, e.getLocalizedMessage(), e);
+ }
+ }
+
+ /** @hide */
+ public void updateProfile(Profile profile) {
+ try {
+ getService().updateProfile(profile);
+ } catch (RemoteException e) {
+ Log.e(TAG, e.getLocalizedMessage(), e);
+ }
+ }
+
+ @Deprecated
+ public Profile getProfile(String profileName) {
+ try {
+ return getService().getProfileByName(profileName);
+ } catch (RemoteException e) {
+ Log.e(TAG, e.getLocalizedMessage(), e);
+ }
+ return null;
+ }
+
+ public Profile getProfile(UUID profileUuid) {
+ try {
+ return getService().getProfile(new ParcelUuid(profileUuid));
+ } catch (RemoteException e) {
+ Log.e(TAG, e.getLocalizedMessage(), e);
+ }
+ return null;
+ }
+
+ public String[] getProfileNames() {
+ try {
+ Profile[] profiles = getService().getProfiles();
+ String[] names = new String[profiles.length];
+ for (int i = 0; i < profiles.length; i++) {
+ names[i] = profiles[i].getName();
+ }
+ return names;
+ } catch (RemoteException e) {
+ Log.e(TAG, e.getLocalizedMessage(), e);
+ }
+ return null;
+ }
+
+ public Profile[] getProfiles() {
+ try {
+ return getService().getProfiles();
+ } catch (RemoteException e) {
+ Log.e(TAG, e.getLocalizedMessage(), e);
+ }
+ return null;
+ }
+
+ public boolean profileExists(String profileName) {
+ try {
+ return getService().profileExistsByName(profileName);
+ } catch (RemoteException e) {
+ Log.e(TAG, e.getLocalizedMessage(), e);
+ // To be on the safe side, we'll return "true", to prevent duplicate profiles
+ // from being created.
+ return true;
+ }
+ }
+
+ public boolean profileExists(UUID profileUuid) {
+ try {
+ return getService().profileExists(new ParcelUuid(profileUuid));
+ } catch (RemoteException e) {
+ Log.e(TAG, e.getLocalizedMessage(), e);
+ // To be on the safe side, we'll return "true", to prevent duplicate profiles
+ // from being created.
+ return true;
+ }
+ }
+
+ public boolean notificationGroupExists(String notificationGroupName) {
+ try {
+ return getService().notificationGroupExistsByName(notificationGroupName);
+ } catch (RemoteException e) {
+ Log.e(TAG, e.getLocalizedMessage(), e);
+ // To be on the safe side, we'll return "true", to prevent duplicate notification
+ // groups from being created.
+ return true;
+ }
+ }
+
+ /** @hide */
+ public NotificationGroup[] getNotificationGroups() {
+ try {
+ return getService().getNotificationGroups();
+ } catch (RemoteException e) {
+ Log.e(TAG, e.getLocalizedMessage(), e);
+ }
+ return null;
+ }
+
+ /** @hide */
+ public void addNotificationGroup(NotificationGroup group) {
+ try {
+ getService().addNotificationGroup(group);
+ } catch (RemoteException e) {
+ Log.e(TAG, e.getLocalizedMessage(), e);
+ }
+ }
+
+ /** @hide */
+ public void removeNotificationGroup(NotificationGroup group) {
+ try {
+ getService().removeNotificationGroup(group);
+ } catch (RemoteException e) {
+ Log.e(TAG, e.getLocalizedMessage(), e);
+ }
+ }
+
+ /** @hide */
+ public void updateNotificationGroup(NotificationGroup group) {
+ try {
+ getService().updateNotificationGroup(group);
+ } catch (RemoteException e) {
+ Log.e(TAG, e.getLocalizedMessage(), e);
+ }
+ }
+
+ /** @hide */
+ public NotificationGroup getNotificationGroupForPackage(String pkg) {
+ try {
+ return getService().getNotificationGroupForPackage(pkg);
+ } catch (RemoteException e) {
+ Log.e(TAG, e.getLocalizedMessage(), e);
+ }
+ return null;
+ }
+
+ /** @hide */
+ public NotificationGroup getNotificationGroup(UUID uuid) {
+ try {
+ return getService().getNotificationGroup(new ParcelUuid(uuid));
+ } catch (RemoteException e) {
+ Log.e(TAG, e.getLocalizedMessage(), e);
+ }
+ return null;
+ }
+
+ /** @hide */
+ public ProfileGroup getActiveProfileGroup(String packageName) {
+ NotificationGroup notificationGroup = getNotificationGroupForPackage(packageName);
+ if(notificationGroup == null){
+ ProfileGroup defaultGroup = getActiveProfile().getDefaultGroup();
+ return defaultGroup;
+ }
+ return getActiveProfile().getProfileGroup(notificationGroup.getUuid());
+ }
+
+ /** @hide */
+ public void resetAll() {
+ try {
+ getService().resetAll();
+ } catch (RemoteException e) {
+ Log.e(TAG, e.getLocalizedMessage(), e);
+ } catch (SecurityException e) {
+ Log.e(TAG, e.getLocalizedMessage(), e);
+ }
+ }
+}
diff --git a/core/java/android/app/StreamSettings.java b/core/java/android/app/StreamSettings.java
new file mode 100644
index 0000000..2f3bf27
--- /dev/null
+++ b/core/java/android/app/StreamSettings.java
@@ -0,0 +1,130 @@
+
+package android.app;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import android.content.Context;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.io.IOException;
+
+/** @hide */
+public final class StreamSettings implements Parcelable{
+
+ private int mStreamId;
+ private int mValue;
+ private boolean mOverride;
+ private boolean mDirty;
+
+ /** @hide */
+ public static final Parcelable.Creator<StreamSettings> CREATOR = new Parcelable.Creator<StreamSettings>() {
+ public StreamSettings createFromParcel(Parcel in) {
+ return new StreamSettings(in);
+ }
+
+ @Override
+ public StreamSettings[] newArray(int size) {
+ return new StreamSettings[size];
+ }
+ };
+
+
+ public StreamSettings(Parcel parcel) {
+ readFromParcel(parcel);
+ }
+
+ public StreamSettings(int streamId) {
+ this(streamId, 0, false);
+ }
+
+ public StreamSettings(int streamId, int value, boolean override) {
+ mStreamId = streamId;
+ mValue = value;
+ mOverride = override;
+ mDirty = false;
+ }
+
+ public int getStreamId() {
+ return mStreamId;
+ }
+
+ public int getValue() {
+ return mValue;
+ }
+
+ public void setValue(int value) {
+ mValue = value;
+ mDirty = true;
+ }
+
+ public void setOverride(boolean override) {
+ mOverride = override;
+ mDirty = true;
+ }
+
+ public boolean isOverride() {
+ return mOverride;
+ }
+
+ /** @hide */
+ public boolean isDirty() {
+ return mDirty;
+ }
+
+ /** @hide */
+ public static StreamSettings fromXml(XmlPullParser xpp, Context context)
+ throws XmlPullParserException, IOException {
+ int event = xpp.next();
+ StreamSettings streamDescriptor = new StreamSettings(0);
+ while (event != XmlPullParser.END_TAG || !xpp.getName().equals("streamDescriptor")) {
+ if (event == XmlPullParser.START_TAG) {
+ String name = xpp.getName();
+ if (name.equals("streamId")) {
+ streamDescriptor.mStreamId = Integer.parseInt(xpp.nextText());
+ } else if (name.equals("value")) {
+ streamDescriptor.mValue = Integer.parseInt(xpp.nextText());
+ } else if (name.equals("override")) {
+ streamDescriptor.mOverride = Boolean.parseBoolean(xpp.nextText());
+ }
+ }
+ event = xpp.next();
+ }
+ return streamDescriptor;
+ }
+
+ /** @hide */
+ public void getXmlString(StringBuilder builder, Context context) {
+ builder.append("<streamDescriptor>\n<streamId>");
+ builder.append(mStreamId);
+ builder.append("</streamId>\n<value>");
+ builder.append(mValue);
+ builder.append("</value>\n<override>");
+ builder.append(mOverride);
+ builder.append("</override>\n</streamDescriptor>\n");
+ mDirty = false;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ /** @hide */
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(mStreamId);
+ dest.writeInt(mOverride ? 1 : 0);
+ dest.writeInt(mValue);
+ dest.writeInt(mDirty ? 1 : 0);
+ }
+
+ /** @hide */
+ public void readFromParcel(Parcel in) {
+ mStreamId = in.readInt();
+ mOverride = in.readInt() != 0;
+ mValue = in.readInt();
+ mDirty = in.readInt() != 0;
+ }
+}
diff --git a/core/java/android/app/VibratorSettings.java b/core/java/android/app/VibratorSettings.java
new file mode 100644
index 0000000..10e5ca2
--- /dev/null
+++ b/core/java/android/app/VibratorSettings.java
@@ -0,0 +1,150 @@
+
+package android.app;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import android.content.Context;
+import android.media.AudioManager;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.io.IOException;
+
+/** @hide */
+public final class VibratorSettings implements Parcelable{
+
+ public static final int OFF = 0;
+ public static final int SILENT = 1;
+ public static final int ON = 2;
+
+ private int mVibratorId;
+ private int mValue;
+ private boolean mOverride;
+ private boolean mDirty;
+
+ /** @hide */
+ public static final Parcelable.Creator<VibratorSettings> CREATOR = new Parcelable.Creator<VibratorSettings>() {
+ public VibratorSettings createFromParcel(Parcel in) {
+ return new VibratorSettings(in);
+ }
+
+ @Override
+ public VibratorSettings[] newArray(int size) {
+ return new VibratorSettings[size];
+ }
+ };
+
+
+ public VibratorSettings(Parcel parcel) {
+ readFromParcel(parcel);
+ }
+
+ public VibratorSettings(int vibratorId) {
+ this(vibratorId, 0, false);
+ }
+
+ public VibratorSettings(int vibratorId, int value, boolean override) {
+ mVibratorId = vibratorId;
+ mValue = value;
+ mOverride = override;
+ mDirty = false;
+ }
+
+ public int getVibratorId() {
+ return mVibratorId;
+ }
+
+ public int getValue() {
+ return mValue;
+ }
+
+ public void setValue(int value) {
+ mValue = value;
+ mDirty = true;
+ }
+
+ public void setOverride(boolean override) {
+ mOverride = override;
+ mDirty = true;
+ }
+
+ public boolean isOverride() {
+ return mOverride;
+ }
+
+ /** @hide */
+ public boolean isDirty() {
+ return mDirty;
+ }
+
+ /** @hide */
+ public static VibratorSettings fromXml(XmlPullParser xpp, Context context)
+ throws XmlPullParserException, IOException {
+ int event = xpp.next();
+ VibratorSettings vibratorDescriptor = new VibratorSettings(0);
+ while (event != XmlPullParser.END_TAG || !xpp.getName().equals("vibratorDescriptor")) {
+ if (event == XmlPullParser.START_TAG) {
+ String name = xpp.getName();
+ if (name.equals("vibratorId")) {
+ vibratorDescriptor.mVibratorId = Integer.parseInt(xpp.nextText());
+ } else if (name.equals("value")) {
+ vibratorDescriptor.mValue = Integer.parseInt(xpp.nextText());
+ } else if (name.equals("override")) {
+ vibratorDescriptor.mOverride = Boolean.parseBoolean(xpp.nextText());
+ }
+ }
+ event = xpp.next();
+ }
+ return vibratorDescriptor;
+ }
+
+ /** @hide */
+ public void getXmlString(StringBuilder builder, Context context) {
+ builder.append("<vibratorDescriptor>\n<vibratorId>");
+ builder.append(mVibratorId);
+ builder.append("</vibratorId>\n<value>");
+ builder.append(mValue);
+ builder.append("</value>\n<override>");
+ builder.append(mOverride);
+ builder.append("</override>\n</vibratorDescriptor>\n");
+ mDirty = false;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ /** @hide */
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(mVibratorId);
+ dest.writeInt(mOverride ? 1 : 0);
+ dest.writeInt(mValue);
+ dest.writeInt(mDirty ? 1 : 0);
+ }
+
+ /** @hide */
+ public void readFromParcel(Parcel in) {
+ mVibratorId = in.readInt();
+ mOverride = in.readInt() != 0;
+ mValue = in.readInt();
+ mDirty = in.readInt() != 0;
+ }
+
+ /** @hide */
+ public void processOverride(Context context) {
+ AudioManager amgr = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
+ switch (mValue) {
+ case OFF:
+ amgr.setVibrateSetting(mVibratorId, AudioManager.VIBRATE_SETTING_OFF);
+ break;
+ case SILENT:
+ amgr.setVibrateSetting(mVibratorId, AudioManager.VIBRATE_SETTING_ONLY_SILENT);
+ default:
+ amgr.setVibrateSetting(mVibratorId, AudioManager.VIBRATE_SETTING_ON);
+ break;
+ }
+ }
+}
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 7aa2507..f0c6ce8 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -1890,6 +1890,18 @@ public abstract class Context {
/**
* Use with {@link #getSystemService} to retrieve a
+ * {@link android.app.ProfileManager} for setting
+ * notification profiles.
+ *
+ * @see #getSystemService
+ * @see android.app.ProfileManager
+ *
+ * @hide
+ */
+ public static final String PROFILE_SERVICE = "profile";
+
+ /**
+ * Use with {@link #getSystemService} to retrieve a
* {@link android.view.accessibility.AccessibilityManager} for giving the user
* feedback for UI events through the registered event listeners.
*
diff --git a/core/java/android/net/wimax/WimaxHelper.java b/core/java/android/net/wimax/WimaxHelper.java
new file mode 100644
index 0000000..f6c7a40
--- /dev/null
+++ b/core/java/android/net/wimax/WimaxHelper.java
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) 2011 The CyanogenMod Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wimax;
+
+import dalvik.system.DexClassLoader;
+
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.ServiceManager;
+import android.util.Log;
+import android.provider.Settings;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+
+/**
+ * {@hide}
+ */
+public class WimaxHelper {
+
+ private static final String TAG = "WimaxHelper";
+
+ private static final String WIMAX_CONTROLLER_CLASSNAME = "com.htc.net.wimax.WimaxController";
+ private static final String WIMAX_MANAGER_CLASSNAME = "android.net.fourG.wimax.Wimax4GManager";
+
+ private static DexClassLoader sWimaxClassLoader;
+ private static String sWimaxManagerClassname, sIsWimaxEnabledMethodname,
+ sSetWimaxEnabledMethodname, sGetWimaxStateMethodname;
+
+ public static boolean isWimaxSupported(Context context) {
+ return context.getResources().getBoolean(
+ com.android.internal.R.bool.config_wimaxEnabled);
+ }
+
+ public static DexClassLoader getWimaxClassLoader(Context context) {
+ if (isWimaxSupported(context)) {
+ if (sWimaxClassLoader == null) {
+ sWimaxManagerClassname = context.getResources().getString(
+ com.android.internal.R.string.config_wimaxManagerClassname);
+
+ // WimaxController::getWimaxState == Wimax4GManager::get4GState.
+ // However, Wimax4GManager also implements a different getWimaxState
+ // method, which returns a WimaxState object describing the connection
+ // state, not the enabled state. Other methods are similarly renamed.
+ if (sWimaxManagerClassname.equals(WIMAX_CONTROLLER_CLASSNAME)) {
+ sIsWimaxEnabledMethodname = "isWimaxEnabled";
+ sSetWimaxEnabledMethodname = "setWimaxEnabled";
+ sGetWimaxStateMethodname = "getWimaxState";
+ } else if (sWimaxManagerClassname.equals(WIMAX_MANAGER_CLASSNAME)) {
+ sIsWimaxEnabledMethodname = "is4GEnabled";
+ sSetWimaxEnabledMethodname = "set4GEnabled";
+ sGetWimaxStateMethodname = "get4GState";
+ }
+
+ String wimaxJarLocation = context.getResources().getString(
+ com.android.internal.R.string.config_wimaxServiceJarLocation);
+ String wimaxLibLocation = context.getResources().getString(
+ com.android.internal.R.string.config_wimaxNativeLibLocation);
+ sWimaxClassLoader = new DexClassLoader(wimaxJarLocation,
+ new ContextWrapper(context).getCacheDir().getAbsolutePath(),
+ wimaxLibLocation,ClassLoader.getSystemClassLoader());
+ }
+ return sWimaxClassLoader;
+ }
+ return null;
+ }
+
+ public static Object createWimaxService(Context context, Handler handler) {
+ Object controller = null;
+
+ try {
+ DexClassLoader wimaxClassLoader = getWimaxClassLoader(context);
+ if (sWimaxManagerClassname.equals(WIMAX_CONTROLLER_CLASSNAME)) {
+ // Load supersonic's and speedy's WimaxController.
+ IBinder b = ServiceManager.getService(WimaxManagerConstants.WIMAX_SERVICE);
+ if (b != null) {
+ Class<?> klass = wimaxClassLoader.loadClass("com.htc.net.wimax.IWimaxController$Stub");
+ if (klass != null) {
+ Method asInterface = klass.getMethod("asInterface", IBinder.class);
+ Object wc = asInterface.invoke(null, b);
+ if (wc != null) {
+ klass = wimaxClassLoader.loadClass(WIMAX_CONTROLLER_CLASSNAME);
+ if (klass != null) {
+ Constructor<?> ctor = klass.getDeclaredConstructors()[1];
+ controller = ctor.newInstance(wc, handler);
+ }
+ }
+ }
+ }
+ } else if (sWimaxManagerClassname.equals(WIMAX_MANAGER_CLASSNAME)) {
+ // Load crespo4g's (and epicmtd's) Wimax4GManager.
+ // Note that crespo4g's implementation grabs WIMAX_SERVICE internally, so
+ // it doesn't need to be passed in. Other implementations (may) require
+ // WIMAX_SERVICE to be grabbed externally, so check Wimax4GManager::<init>.
+ Class<?> klass = wimaxClassLoader.loadClass(WIMAX_MANAGER_CLASSNAME);
+ if (klass != null) {
+ Constructor<?> ctor = klass.getDeclaredConstructors()[0];
+ controller = ctor.newInstance();
+ }
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "Unable to create WimaxController instance", e);
+ }
+
+ return controller;
+ }
+
+ public static boolean isWimaxEnabled(Context context) {
+ boolean ret = false;
+ try {
+ Object wimaxService = context.getSystemService(WimaxManagerConstants.WIMAX_SERVICE);
+ Method m = wimaxService.getClass().getMethod(sIsWimaxEnabledMethodname);
+ ret = (Boolean) m.invoke(wimaxService);
+ } catch (Exception e) {
+ Log.e(TAG, "Unable to get WiMAX enabled state!", e);
+ }
+ return ret;
+ }
+
+ public static boolean setWimaxEnabled(Context context, boolean enabled) {
+ boolean ret = false;
+ try {
+ Object wimaxService = context.getSystemService(WimaxManagerConstants.WIMAX_SERVICE);
+ Method m = wimaxService.getClass().getMethod(sSetWimaxEnabledMethodname, boolean.class);
+ ret = (Boolean) m.invoke(wimaxService, enabled);
+ if (ret)
+ Settings.Secure.putInt(context.getContentResolver(),
+ Settings.Secure.WIMAX_ON, (Boolean) enabled ? 1 : 0);
+ } catch (Exception e) {
+ Log.e(TAG, "Unable to set WiMAX state!", e);
+ }
+ return ret;
+ }
+
+ public static int getWimaxState(Context context) {
+ int ret = 0;
+ try {
+ Object wimaxService = context.getSystemService(WimaxManagerConstants.WIMAX_SERVICE);
+ Method m = wimaxService.getClass().getMethod(sGetWimaxStateMethodname);
+ ret = (Integer) m.invoke(wimaxService);
+ } catch (Exception e) {
+ Log.e(TAG, "Unable to get WiMAX state!", e);
+ }
+ return ret;
+ }
+
+ public static boolean wimaxRescan(Context context) {
+ boolean ret = false;
+ try {
+ Object wimaxService = context.getSystemService(WimaxManagerConstants.WIMAX_SERVICE);
+ Method wimaxRescan = wimaxService.getClass().getMethod("wimaxRescan");
+ if (wimaxRescan != null) {
+ wimaxRescan.invoke(wimaxService);
+ ret = true;
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "Unable to perform WiMAX rescan!", e);
+ }
+ return ret;
+ }
+
+ private static Object getWimaxInfo(Context context) {
+ Object wimaxInfo = null;
+ try {
+ Object wimaxService = context.getSystemService(WimaxManagerConstants.WIMAX_SERVICE);
+ Method getConnectionInfo = wimaxService.getClass().getMethod("getConnectionInfo");
+ wimaxInfo = getConnectionInfo.invoke(wimaxService);
+ } catch (Exception e) {
+ Log.e(TAG, "Unable to get a WimaxInfo object!", e);
+ }
+ return wimaxInfo;
+ }
+}
diff --git a/core/java/android/net/wimax/WimaxManagerConstants.java b/core/java/android/net/wimax/WimaxManagerConstants.java
index b4aaf5b..a8239ba 100644
--- a/core/java/android/net/wimax/WimaxManagerConstants.java
+++ b/core/java/android/net/wimax/WimaxManagerConstants.java
@@ -67,11 +67,21 @@ public class WimaxManagerConstants
public static final int NET_4G_STATE_DISABLED = 1;
/**
+ * Indicatates Wimax is disabling.
+ */
+ public static final int NET_4G_STATE_DISABLING = 0;
+
+ /**
* Indicatates Wimax is enabled.
*/
public static final int NET_4G_STATE_ENABLED = 3;
/**
+ * Indicatates Wimax is enabling.
+ */
+ public static final int NET_4G_STATE_ENABLING = 2;
+
+ /**
* Indicatates Wimax status is known.
*/
public static final int NET_4G_STATE_UNKNOWN = 4;
@@ -101,4 +111,9 @@ public class WimaxManagerConstants
*/
public static final int WIMAX_STATE_DISCONNECTED = 9;
+ /**
+ * Constants for HTC/SQN WiMAX implementation
+ */
+ public static final String WIMAX_ENABLED_CHANGED_ACTION = "com.htc.net.wimax.WIMAX_ENABLED_CHANGED";
+ public static final String CURRENT_WIMAX_ENABLED_STATE = "curWimaxEnabledState";
}
diff --git a/core/java/android/preference/ListPreferenceMultiSelect.java b/core/java/android/preference/ListPreferenceMultiSelect.java
new file mode 100644
index 0000000..83edc72
--- /dev/null
+++ b/core/java/android/preference/ListPreferenceMultiSelect.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2012 The CyanogenMod Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.preference;
+
+import android.app.AlertDialog.Builder;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.text.TextUtils;
+import android.util.AttributeSet;
+
+/**
+ * This Preference type is required for the Power Widget functionality. It should
+ * not be used for any other multi select lists, use the Android MultiselectListPreference
+ * instead
+ * @hide
+ */
+public class ListPreferenceMultiSelect extends ListPreference {
+
+ private static final String SEPARATOR = "OV=I=XseparatorX=I=VO";
+
+ private boolean[] mClickedDialogEntryIndices;
+
+ public ListPreferenceMultiSelect(Context context) {
+ super(context);
+ }
+
+ public ListPreferenceMultiSelect(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @Override
+ protected void onPrepareDialogBuilder(Builder builder) {
+ CharSequence[] entries = getEntries();
+ CharSequence[] entryValues = getEntryValues();
+
+ if (entries == null || entryValues == null || entries.length != entryValues.length) {
+ throw new IllegalStateException(
+ this.getClass().getSimpleName()
+ + " requires an entries array and an entryValues array which are both the same length");
+ }
+
+ mClickedDialogEntryIndices = new boolean[entryValues.length];
+ restoreCheckedEntries();
+ builder.setMultiChoiceItems(entries, mClickedDialogEntryIndices, new DialogInterface.OnMultiChoiceClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which, boolean isChecked) {
+ mClickedDialogEntryIndices[which] = isChecked;
+ }
+ });
+ }
+
+ public static String[] parseStoredValue(CharSequence val) {
+ if (TextUtils.isEmpty(val)) {
+ return null;
+ } else {
+ return val.toString().split(SEPARATOR);
+ }
+ }
+
+ private void restoreCheckedEntries() {
+ CharSequence[] entryValues = getEntryValues();
+
+ String[] vals = parseStoredValue(getValue());
+ if (vals != null) {
+ for (String val : vals) {
+ for (int i = 0; i < entryValues.length; i++) {
+ CharSequence entry = entryValues[i];
+ if (entry.equals(val)) {
+ mClickedDialogEntryIndices[i] = true;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ @Override
+ protected void onDialogClosed(boolean positiveResult) {
+ CharSequence[] entryValues = getEntryValues();
+
+ if (positiveResult && entryValues != null) {
+ StringBuilder value = new StringBuilder();
+ for (int i = 0; i < entryValues.length; i++) {
+ if (mClickedDialogEntryIndices[i]) {
+ if (value.length() > 0) {
+ value.append(SEPARATOR);
+ }
+ value.append(entryValues[i]);
+ }
+ }
+
+ String val = value.toString();
+ if (callChangeListener(val)) {
+ setValue(val);
+ }
+ }
+ }
+}
diff --git a/core/java/android/preference/VolumePreference.java b/core/java/android/preference/VolumePreference.java
index caf55d7..b763022 100644
--- a/core/java/android/preference/VolumePreference.java
+++ b/core/java/android/preference/VolumePreference.java
@@ -146,6 +146,11 @@ public class VolumePreference extends SeekBarDialogPreference implements
}
}
+ /** @hide */
+ protected boolean onVolumeChange(SeekBarVolumizer volumizer, int value) {
+ return true;
+ }
+
@Override
protected Parcelable onSaveInstanceState() {
final Parcelable superState = super.onSaveInstanceState();
@@ -305,10 +310,14 @@ public class VolumePreference extends SeekBarDialogPreference implements
}
void postSetVolume(int progress) {
- // Do the volume changing separately to give responsive UI
- mLastProgress = progress;
- mHandler.removeCallbacks(this);
- mHandler.post(this);
+ if (onVolumeChange(this, progress)) {
+ // Do the volume changing separately to give responsive UI
+ mLastProgress = progress;
+ mHandler.removeCallbacks(this);
+ mHandler.post(this);
+ } else {
+ mSeekBar.setProgress(mLastProgress);
+ }
}
public void onStartTrackingTouch(SeekBar seekBar) {
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 2a3f916..99db53c 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -1688,6 +1688,148 @@ public final class Settings {
public static final int SCREEN_BRIGHTNESS_MODE_AUTOMATIC = 1;
/**
+ * Indicates that custom light sensor settings has changed.
+ * The value is random and changes reloads light settings.
+ *
+ * @hide
+ */
+ public static final String LIGHTS_CHANGED = "lights_changed";
+
+ /**
+ * Whether custom light sensor levels & values are enabled. The value is
+ * boolean (1 or 0).
+ *
+ * @hide
+ */
+ public static final String LIGHT_SENSOR_CUSTOM = "light_sensor_custom";
+
+ /**
+ * Screen dim value to use if LIGHT_SENSOR_CUSTOM is set. The value is int.
+ * Default is android.os.BRIGHTNESS_DIM.
+ *
+ * @hide
+ */
+ public static final String LIGHT_SCREEN_DIM = "light_screen_dim";
+
+ /**
+ * Custom light sensor levels. The value is a comma separated int array
+ * with length N.
+ * Example: "100,300,3000".
+ *
+ * @hide
+ */
+ public static final String LIGHT_SENSOR_LEVELS = "light_sensor_levels";
+
+ /**
+ * Custom light sensor lcd values. The value is a comma separated int array
+ * with length N+1.
+ * Example: "10,50,100,255".
+ *
+ * @hide
+ */
+ public static final String LIGHT_SENSOR_LCD_VALUES = "light_sensor_lcd_values";
+
+ /**
+ * Custom light sensor lcd values. The value is a comma separated int array
+ * with length N+1.
+ * Example: "10,50,100,255".
+ *
+ * @hide
+ */
+ public static final String LIGHT_SENSOR_BUTTON_VALUES = "light_sensor_button_values";
+
+ /**
+ * Custom light sensor lcd values. The value is a comma separated int array
+ * with length N+1.
+ * Example: "10,50,100,255".
+ *
+ * @hide
+ */
+ public static final String LIGHT_SENSOR_KEYBOARD_VALUES = "light_sensor_keyboard_values";
+
+ /**
+ * Whether light sensor is allowed to decrease when calculating automatic
+ * backlight. The value is boolean (1 or 0).
+ *
+ * @hide
+ */
+ public static final String LIGHT_DECREASE = "light_decrease";
+
+ /**
+ * Light sensor hysteresis for decreasing backlight. The value is
+ * int (0-99) representing % (0-0.99 as float). Example:
+ *
+ * Levels Output
+ * 0 - 100 50
+ * 100 - 200 100
+ * 200 - Inf 255
+ *
+ * Current sensor value is 150 which gives light value 100. Hysteresis is 50.
+ * Current level lower bound is 100 and previous lower bound is 0.
+ * Sensor value must drop below 100-(100-0)*(50/100)=50 for output to become 50
+ * (corresponding to the 0 - 100 level).
+ * @hide
+ */
+ public static final String LIGHT_HYSTERESIS = "light_hysteresis";
+
+ /**
+ * Whether light sensor used when calculating automatic backlight should
+ * be filtered through an moving average filter.
+ * The value is boolean (1 or 0).
+ *
+ * @hide
+ */
+ public static final String LIGHT_FILTER = "light_filter";
+
+ /**
+ * Window length of filter used when calculating automatic backlight.
+ * One minute means that the average sensor value last minute is used.
+ * The value is integer (milliseconds)
+ *
+ * @hide
+ */
+ public static final String LIGHT_FILTER_WINDOW = "light_filter_window";
+
+ /**
+ * Reset threshold of filter used when calculating automatic backlight.
+ * Sudden large jumps in sensor value resets the filter. This is used
+ * to make the filter respond quickly to large enough changes in input
+ * while still filtering small changes. Example:
+ *
+ * Current filter value (average) is 100 and sensor value is changing to
+ * 10, 150, 100, 30, 50. The filter is continously taking the average of
+ * the samples. Now the user goes outside and the value jumps over 1000.
+ * The difference between current average and new sample is larger than
+ * the reset threshold and filter is reset. It begins calculating a new
+ * average on samples around 1000 (say, 800, 1200, 1000, 1100 etc.)
+ *
+ * The value is integer (lux)
+ *
+ * @hide
+ */
+ public static final String LIGHT_FILTER_RESET = "light_filter_reset";
+
+ /**
+ * Sample interval of filter used when calculating automatic backlight.
+ * The value is integer (milliseconds)
+ *
+ * @hide
+ */
+ public static final String LIGHT_FILTER_INTERVAL = "light_filter_interval";
+
+ /**
+ * Whether to enable the electron beam animation when turning screen on
+ *
+ * @hide */
+ public static final String ELECTRON_BEAM_ANIMATION_ON = "electron_beam_animation_on";
+
+ /**
+ * Whether to enable the electron beam animation when turning screen off
+ *
+ * @hide */
+ public static final String ELECTRON_BEAM_ANIMATION_OFF = "electron_beam_animation_off";
+
+ /**
* Control whether the process CPU usage meter should be shown.
*
* @deprecated Use {@link Global#SHOW_PROCESSES} instead
@@ -1706,6 +1848,22 @@ public final class Settings {
public static final String ALWAYS_FINISH_ACTIVITIES = Global.ALWAYS_FINISH_ACTIVITIES;
/**
+ * Volume Overlay Mode, This is behaviour of the volume overlay panel
+ * Defaults to 0 - which is simple
+ * @hide
+ */
+ public static final String MODE_VOLUME_OVERLAY = "mode_volume_overlay";
+
+ /** @hide */
+ public static final int VOLUME_OVERLAY_SINGLE = 0;
+ /** @hide */
+ public static final int VOLUME_OVERLAY_EXPANDABLE = 1;
+ /** @hide */
+ public static final int VOLUME_OVERLAY_EXPANDED = 2;
+ /** @hide */
+ public static final int VOLUME_OVERLAY_NONE = 3;
+
+ /**
* Determines which streams are affected by ringer mode changes. The
* stream type's bit should be set to 1 if it should be muted when going
* into an inaudible ringer mode.
@@ -1782,6 +1940,12 @@ public final class Settings {
public static final String VOLUME_BLUETOOTH_SCO = "volume_bluetooth_sco";
/**
+ * Whether to prevent loud volume levels when headset is first plugged in.
+ * @hide
+ */
+ public static final String SAFE_HEADSET_VOLUME_RESTORE = "safe_headset_volume_restore";
+
+ /**
* Master volume (float in the range 0.0f to 1.0f).
* @hide
*/
@@ -1813,6 +1977,24 @@ public final class Settings {
"notifications_use_ring_volume";
/**
+ * Whether the phone ringtone should be played in an increasing manner
+ * @hide
+ */
+ public static final String INCREASING_RING = "increasing_ring";
+
+ /**
+ * Minimum volume index for increasing ring volume
+ * @hide
+ */
+ public static final String INCREASING_RING_MIN_VOLUME = "increasing_ring_min_vol";
+
+ /**
+ * Time (in ms) between ringtone volume increases
+ * @hide
+ */
+ public static final String INCREASING_RING_INTERVAL = "increasing_ring_interval";
+
+ /**
* Whether silent mode should allow vibration feedback. This is used
* internally in AudioService and the Sound settings activity to
* coordinate decoupling of vibrate and silent modes. This setting
@@ -2008,6 +2190,19 @@ public final class Settings {
public static final String ACCELEROMETER_ROTATION = "accelerometer_rotation";
/**
+ * Control the type of rotation which can be performed using the accelerometer
+ * if ACCELEROMETER_ROTATION is enabled.
+ * Value is a bitwise combination of
+ * 1 = 0 degrees (portrait)
+ * 2 = 90 degrees (left)
+ * 4 = 180 degrees (inverted portrait)
+ * 8 = 270 degrees (right)
+ * Setting to 0 is effectively orientation lock
+ * @hide
+ */
+ public static final String ACCELEROMETER_ROTATION_ANGLES = "accelerometer_rotation_angles";
+
+ /**
* Default screen rotation when no other policy applies.
* When {@link #ACCELEROMETER_ROTATION} is zero and no on-screen Activity expresses a
* preference, this rotation value will be used. Must be one of the
@@ -2079,6 +2274,13 @@ public final class Settings {
public static final String TTY_MODE = "tty_mode";
/**
+ * Whether noise suppression is enabled. The value is
+ * boolean (1 or 0).
+ * @hide
+ */
+ public static final String NOISE_SUPPRESSION = "noise_suppression";
+
+ /**
* Whether the sounds effects (key clicks, lid open ...) are enabled. The value is
* boolean (1 or 0).
*/
@@ -2105,6 +2307,109 @@ public final class Settings {
public static final String NOTIFICATION_LIGHT_PULSE = "notification_light_pulse";
/**
+ * What color to use for the notification LED by default
+ * @hide
+ */
+ public static final String NOTIFICATION_LIGHT_PULSE_DEFAULT_COLOR = "notification_light_pulse_default_color";
+
+ /**
+ * How long to flash the notification LED by default
+ * @hide
+ */
+ public static final String NOTIFICATION_LIGHT_PULSE_DEFAULT_LED_ON = "notification_light_pulse_default_led_on";
+
+ /**
+ * How long to wait between flashes for the notification LED by default
+ * @hide
+ */
+ public static final String NOTIFICATION_LIGHT_PULSE_DEFAULT_LED_OFF = "notification_light_pulse_default_led_off";
+
+ /**
+ * What color to use for the missed call notification LED
+ * @hide
+ */
+ public static final String NOTIFICATION_LIGHT_PULSE_CALL_COLOR = "notification_light_pulse_call_color";
+
+ /**
+ * How long to flash the missed call notification LED
+ * @hide
+ */
+ public static final String NOTIFICATION_LIGHT_PULSE_CALL_LED_ON = "notification_light_pulse_call_led_on";
+
+ /**
+ * How long to wait between flashes for the missed call notification LED
+ * @hide
+ */
+ public static final String NOTIFICATION_LIGHT_PULSE_CALL_LED_OFF = "notification_light_pulse_call_led_off";
+
+ /**
+ * What color to use for the voicemail notification LED
+ * @hide
+ */
+ public static final String NOTIFICATION_LIGHT_PULSE_VMAIL_COLOR = "notification_light_pulse_vmail_color";
+
+ /**
+ * How long to flash the voicemail notification LED
+ * @hide
+ */
+ public static final String NOTIFICATION_LIGHT_PULSE_VMAIL_LED_ON = "notification_light_pulse_vmail_led_on";
+
+ /**
+ * How long to wait between flashes for the voicemail notification LED
+ * @hide
+ */
+ public static final String NOTIFICATION_LIGHT_PULSE_VMAIL_LED_OFF = "notification_light_pulse_vmail_led_off";
+
+ /**
+ * Whether to use the custom LED values for the notification pulse LED.
+ * @hide
+ */
+ public static final String NOTIFICATION_LIGHT_PULSE_CUSTOM_ENABLE = "notification_light_pulse_custom_enable";
+
+ /**
+ * Which custom LED values to use for the notification pulse LED.
+ * @hide
+ */
+ public static final String NOTIFICATION_LIGHT_PULSE_CUSTOM_VALUES = "notification_light_pulse_custom_values";
+
+ /**
+ * Whether the battery light should be enabled (if hardware supports it)
+ * The value is boolean (1 or 0).
+ * @hide
+ */
+ public static final String BATTERY_LIGHT_ENABLED = "battery_light_enabled";
+
+ /**
+ * Whether the battery LED should repeatedly flash when the battery is low
+ * on charge. The value is boolean (1 or 0).
+ * @hide
+ */
+ public static final String BATTERY_LIGHT_PULSE = "battery_light_pulse";
+
+ /**
+ * What color to use for the battery LED while charging - low
+ * @hide
+ */
+ public static final String BATTERY_LIGHT_LOW_COLOR = "battery_light_low_color";
+
+ /**
+ * What color to use for the battery LED while charging - medium
+ * @hide
+ */
+ public static final String BATTERY_LIGHT_MEDIUM_COLOR = "battery_light_medium_color";
+
+ /**
+ * What color to use for the battery LED while charging - full
+ * @hide
+ */
+ public static final String BATTERY_LIGHT_FULL_COLOR = "battery_light_full_color";
+
+ /** Sprint MWI Quirk: Show message wait indicator notifications
+ * @hide
+ */
+ public static final String ENABLE_MWI_NOTIFICATION = "enable_mwi_notification";
+
+ /**
* Show pointer location on screen?
* 0 = no
* 1 = yes
@@ -2265,6 +2570,362 @@ public final class Settings {
public static final String POINTER_SPEED = "pointer_speed";
/**
+ * Use the Notification Power Widget? (Who wouldn't!)
+ *
+ * @hide
+ */
+ public static final String EXPANDED_VIEW_WIDGET = "expanded_view_widget";
+
+ /**
+ * Whether to hide the notification screen after clicking on a widget
+ * button
+ *
+ * @hide
+ */
+ public static final String EXPANDED_HIDE_ONCHANGE = "expanded_hide_onchange";
+
+ /**
+ * Hide scroll bar in power widget
+ *
+ * @hide
+ */
+ public static final String EXPANDED_HIDE_SCROLLBAR = "expanded_hide_scrollbar";
+
+ /**
+ * Hide indicator in status bar widget
+ *
+ * @hide
+ */
+ public static final String EXPANDED_HIDE_INDICATOR = "expanded_hide_indicator";
+
+ /**
+ * Haptic feedback in power widget
+ *
+ * @hide
+ */
+ public static final String EXPANDED_HAPTIC_FEEDBACK = "expanded_haptic_feedback";
+
+ /**
+ * Notification Indicator Color
+ *
+ * @hide
+ */
+ public static final String EXPANDED_VIEW_WIDGET_COLOR = "expanded_widget_color";
+
+ /**
+ * Widget Buttons to Use
+ *
+ * @hide
+ */
+ public static final String WIDGET_BUTTONS = "expanded_widget_buttons";
+
+ /**
+ * Widget Buttons to Use - Tablet
+ *
+ * @hide
+ */
+ public static final String WIDGET_BUTTONS_TABLET = "expanded_widget_buttons_tablet";
+
+ /**
+ * Navigation controls to Use
+ *
+ * @hide
+ */
+ public static final String NAV_BUTTONS = "nav_buttons";
+
+ /**
+ * Notification Power Widget - Custom Brightness Mode
+ * @hide
+ */
+ public static final String EXPANDED_BRIGHTNESS_MODE = "expanded_brightness_mode";
+
+ /**
+ * Notification Power Widget - Custom Network Mode
+ * @hide
+ */
+ public static final String EXPANDED_NETWORK_MODE = "expanded_network_mode";
+
+ /**
+ * Notification Power Widget - Custom LTE Toggle
+ * 1 - lte on, 0 - lte off
+ * @hide
+ */
+ public static final String LTE_MODE = "lte_mode";
+
+ /**
+ * Notification Power Widget - Custom Screen Timeout
+ * @hide
+ */
+ public static final String EXPANDED_SCREENTIMEOUT_MODE = "expanded_screentimeout_mode";
+
+ /**
+ * Notification Power Widget - Custom Ring Mode
+ * @hide
+ */
+ public static final String EXPANDED_RING_MODE = "expanded_ring_mode";
+
+ /**
+ * Notification Power Widget - Custom Torch Mode
+ * @hide
+ */
+ public static final String EXPANDED_FLASH_MODE = "expanded_flash_mode";
+
+ /**
+ * AutoHide CombinedBar on tablets.
+ * @hide
+ */
+ public static final String COMBINED_BAR_AUTO_HIDE = "combined_bar_auto_hide";
+
+ /**
+ * Display style of AM/PM next to clock in status bar
+ * 0: Normal display (Eclair stock)
+ * 1: Small display (Froyo stock)
+ * 2: No display (Gingerbread/ICS stock)
+ * default: 2
+ * @hide
+ */
+ public static final String STATUS_BAR_AM_PM = "status_bar_am_pm";
+
+ /**
+ * Display style of the status bar battery information
+ * 0: Display the stock battery information
+ * 1: Display cm battery percentage implementation / dont show stock icon
+ * 2: Hide the battery information
+ * default: 0
+ * @hide
+ */
+ public static final String STATUS_BAR_BATTERY = "status_bar_battery";
+
+ /**
+ * Whether to show the clock in status bar
+ * of the stock battery icon
+ * 0: don't show the clock
+ * 1: show the clock
+ * default: 1
+ * @hide
+ */
+ public static final String STATUS_BAR_CLOCK = "status_bar_clock";
+
+ /**
+ * Whether to show the signal text or signal bars.
+ * default: 0
+ * 0: show signal bars
+ * 1: show signal text numbers
+ * 2: show signal text numbers w/small dBm appended
+ * @hide
+ */
+ public static final String STATUS_BAR_SIGNAL_TEXT = "status_bar_signal";
+
+ /**
+ * Whether to control brightness from status bar
+ *
+ * @hide
+ */
+ public static final String STATUS_BAR_BRIGHTNESS_CONTROL = "status_bar_brightness_control";
+
+ /**
+ * Whether to show the IME switcher in the status bar
+ * @hide
+ */
+ public static final String STATUS_BAR_IME_SWITCHER = "status_bar_ime_switcher";
+
+ /**
+ * Whether to use a separate delay for "slide to unlock" and security
+ * lock
+ * @hide
+ */
+ public static final String SCREEN_LOCK_SLIDE_DELAY_TOGGLE = "screen_lock_slide_delay_toggle";
+
+ /**
+ * How many ms to delay before enabling the "slide to unlock" screen
+ * lock when the screen goes off due to timeout
+ * @hide
+ */
+ public static final String SCREEN_LOCK_SLIDE_TIMEOUT_DELAY = "screen_lock_slide_timeout_delay";
+
+ /**
+ * How many ms to delay before enabling the "slide to unlock" screen
+ * lock when the screen is turned off by the user
+ * @hide
+ */
+ public static final String SCREEN_LOCK_SLIDE_SCREENOFF_DELAY = "screen_lock_slide_screenoff_delay";
+
+ /**
+ * Whether to use the custom quick unlock screen control
+ * @hide
+ */
+ public static final String LOCKSCREEN_QUICK_UNLOCK_CONTROL = "lockscreen_quick_unlock_control";
+
+ /**
+ * Boolean value whether to link ringtone and notification volumes
+ *
+ * @hide
+ */
+ public static final String VOLUME_LINK_NOTIFICATION = "volume_link_notification";
+
+ /**
+ * Whether to unlock the menu key. The value is boolean (1 or 0).
+ * @hide
+ */
+ public static final String MENU_UNLOCK_SCREEN = "menu_unlock_screen";
+
+ /**
+ * Whether to wake the screen with the volume keys, the value is boolean.
+ * @hide
+ */
+ public static final String VOLUME_WAKE_SCREEN = "volume_wake_screen";
+
+ /**
+ * Whether or not volume button music controls should be enabled to seek media tracks
+ * @hide
+ */
+ public static final String VOLBTN_MUSIC_CONTROLS = "volbtn_music_controls";
+
+ /**
+ * Whether national data roaming should be used.
+ * @hide
+ */
+ public static final String MVNO_ROAMING = "mvno_roaming";
+
+ /**
+ * Whether to enable quiet hours.
+ * @hide
+ */
+ public static final String QUIET_HOURS_ENABLED = "quiet_hours_enabled";
+
+ /**
+ * Sets when quiet hours starts. This is stored in minutes from the start of the day.
+ * @hide
+ */
+ public static final String QUIET_HOURS_START = "quiet_hours_start";
+
+ /**
+ * Sets when quiet hours end. This is stored in minutes from the start of the day.
+ * @hide
+ */
+ public static final String QUIET_HOURS_END = "quiet_hours_end";
+
+ /**
+ * Whether to remove the sound from outgoing notifications during quiet hours.
+ * @hide
+ */
+ public static final String QUIET_HOURS_MUTE = "quiet_hours_mute";
+
+ /**
+ * Whether to disable haptic feedback during quiet hours.
+ * @hide
+ */
+ public static final String QUIET_HOURS_HAPTIC = "quiet_hours_haptic";
+
+ /**
+ * Whether to remove the vibration from outgoing notifications during quiet hours.
+ * @hide
+ */
+ public static final String QUIET_HOURS_STILL = "quiet_hours_still";
+
+ /**
+ * Whether to attempt to dim the LED color during quiet hours.
+ * @hide
+ */
+ public static final String QUIET_HOURS_DIM = "quiet_hours_dim";
+
+ /**
+ * Sets the lockscreen background style
+ * @hide
+ */
+ public static final String LOCKSCREEN_BACKGROUND = "lockscreen_background";
+
+ /**
+ * Show the weather on the lock screen
+ * @hide
+ */
+ public static final String LOCKSCREEN_WEATHER = "lockscreen_weather";
+
+ /**
+ * Show the current weather location on the lock screen
+ * @hide
+ */
+ public static final String WEATHER_SHOW_LOCATION = "weather_show_location";
+
+ /**
+ * Show the current weather location on the lock screen
+ * @hide
+ */
+ public static final String WEATHER_SHOW_TIMESTAMP = "weather_show_timestamp";
+
+ /**
+ * Use the custom/manually configured weather location
+ * @hide
+ */
+ public static final String WEATHER_USE_CUSTOM_LOCATION = "weather_use_custom_location";
+
+ /**
+ * Stores the custom/manually configured weather location
+ * @hide
+ */
+ public static final String WEATHER_CUSTOM_LOCATION = "weather_custom_location";
+
+ /**
+ * Stores the weather update frequency
+ * @hide
+ */
+ public static final String WEATHER_UPDATE_INTERVAL = "weather_update_interval";
+
+ /**
+ * Use Metric measurements (celcius, km/h) for weather data
+ * @hide
+ */
+ public static final String WEATHER_USE_METRIC = "weather_use_metric";
+
+ /**
+ * Invert low/high temperature display
+ * @hide
+ */
+ public static final String WEATHER_INVERT_LOWHIGH = "weather_invert_lowhigh";
+
+ /**
+ * Whether to show the next calendar event
+ * @hide
+ */
+ public static final String LOCKSCREEN_CALENDAR = "lockscreen_calendar";
+
+ /**
+ * Whether to show the next calendar event's location
+ * @hide
+ */
+ public static final String LOCKSCREEN_CALENDAR_SHOW_LOCATION = "lockscreen_calendar_show_location";
+
+ /**
+ * Whether to show the next calendar event's description
+ * @hide
+ */
+ public static final String LOCKSCREEN_CALENDAR_SHOW_DESCRIPTION = "lockscreen_calendar_show_description";
+
+ /**
+ * Which calendars to look for events
+ * @hide
+ */
+ public static final String LOCKSCREEN_CALENDARS = "lockscreen_calendars";
+
+ /**
+ * How far in the future to look for events
+ * @hide
+ */
+ public static final String LOCKSCREEN_CALENDAR_LOOKAHEAD = "lockscreen_calendar_lookahead";
+
+ /**
+ * Whether to find only events with reminders
+ * @hide
+ */
+ public static final String LOCKSCREEN_CALENDAR_REMINDERS_ONLY = "lockscreen_calendar_reminders_only";
+
+ /**
+ * Show the pending notification counts as overlays on the status bar
+ * @hide
+ */
+ public static final String STATUS_BAR_NOTIF_COUNT = "status_bar_notif_count";
+
+ /**
* Settings to backup. This is here so that it's in the same place as the settings
* keys and easy to update.
*
@@ -2315,10 +2976,13 @@ public final class Settings {
AUTO_TIME_ZONE, // moved to global
TIME_12_24,
DATE_FORMAT,
+ ACCELEROMETER_ROTATION,
+ USER_ROTATION,
DTMF_TONE_WHEN_DIALING,
DTMF_TONE_TYPE_WHEN_DIALING,
HEARING_AID,
TTY_MODE,
+ NOISE_SUPPRESSION,
SOUND_EFFECTS_ENABLED,
HAPTIC_FEEDBACK_ENABLED,
POWER_SOUNDS_ENABLED, // moved to global
@@ -2326,10 +2990,18 @@ public final class Settings {
LOCKSCREEN_SOUNDS_ENABLED,
SHOW_WEB_SUGGESTIONS,
NOTIFICATION_LIGHT_PULSE,
+ NOTIFICATION_LIGHT_PULSE_DEFAULT_COLOR,
+ NOTIFICATION_LIGHT_PULSE_DEFAULT_LED_ON,
+ NOTIFICATION_LIGHT_PULSE_DEFAULT_LED_OFF,
SIP_CALL_OPTIONS,
SIP_RECEIVE_CALLS,
POINTER_SPEED,
- VIBRATE_WHEN_RINGING
+ QUIET_HOURS_ENABLED,
+ QUIET_HOURS_START,
+ QUIET_HOURS_END,
+ QUIET_HOURS_MUTE,
+ QUIET_HOURS_STILL,
+ QUIET_HOURS_DIM,
};
// Settings moved to Settings.Secure
@@ -3082,6 +3754,12 @@ public final class Settings {
public static final String ADB_ENABLED = Global.ADB_ENABLED;
/**
+ * The TCP/IP port to run ADB on, or -1 for USB
+ * @hide
+ */
+ public static final String ADB_PORT = "adb_port";
+
+ /**
* The hostname for this device
* @hide
*/
@@ -3261,6 +3939,13 @@ public final class Settings {
"lock_screen_owner_info_enabled";
/**
+ * Whether the unsecure widget screen will be shown before a secure
+ * lock screen
+ * @hide
+ */
+ public static final String LOCK_BEFORE_UNLOCK =
+ "lock_before_unlock";
+ /**
* The Logging ID (a unique 64-bit value) as a hex string.
* Used as a pseudonymous identifier for logging.
* @deprecated This identifier is poorly initialized and has
@@ -3679,6 +4364,12 @@ public final class Settings {
Global.WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS;
/**
+ * Whether the Wimax should be on. Only the WiMAX service should touch this.
+ * @hide
+ */
+ public static final String WIMAX_ON = "wimax_on";
+
+ /**
* Whether background data usage is allowed.
*
* @deprecated As of {@link VERSION_CODES#ICE_CREAM_SANDWICH},
@@ -4292,6 +4983,13 @@ public final class Settings {
public static final String POWER_SOUNDS_ENABLED = "power_sounds_enabled";
/**
+ * Whether to allow killing of the foreground app by long-pressing the Back button
+ * @hide
+ */
+ public static final String KILL_APP_LONGPRESS_BACK = "kill_app_longpress_back";
+
+
+ /**
* Whether we keep the device on while the device is plugged in.
* Supported values are:
* <ul>
diff --git a/core/java/android/view/VolumePanel.java b/core/java/android/view/VolumePanel.java
index d7c7f46..2497e95 100644
--- a/core/java/android/view/VolumePanel.java
+++ b/core/java/android/view/VolumePanel.java
@@ -35,7 +35,10 @@ import android.media.ToneGenerator;
import android.net.Uri;
import android.os.Handler;
import android.os.Message;
+import android.os.RemoteException;
import android.os.Vibrator;
+import android.provider.Settings;
+import android.provider.Settings.System;
import android.util.Log;
import android.view.WindowManager.LayoutParams;
import android.widget.ImageView;
@@ -99,12 +102,16 @@ public class VolumePanel extends Handler implements OnSeekBarChangeListener, Vie
private static final int STREAM_MASTER = -100;
// Pseudo stream type for remote volume is defined in AudioService.STREAM_REMOTE_MUSIC
+ public static final String ACTION_VOLUME_OVERLAY_CHANGED
+ = "android.intent.action.VOLUME_OVERLAY_CHANGED";
+
protected Context mContext;
private AudioManager mAudioManager;
protected AudioService mAudioService;
private boolean mRingIsSilent;
private boolean mShowCombinedVolumes;
private boolean mVoiceCapable;
+ private int mCurrentOverlayStyle = -1;
// True if we want to play tones on the system stream when the master stream is specified.
private final boolean mPlayMasterStreamTones;
@@ -326,12 +333,26 @@ public class VolumePanel extends Handler implements OnSeekBarChangeListener, Vie
mPlayMasterStreamTones = masterVolumeOnly && masterVolumeKeySounds;
+ // get the users preference
+ int choosenStyle = Settings.System.getInt(context.getContentResolver(),Settings.System.MODE_VOLUME_OVERLAY, -1);
+ // by default -1 is expected - deal with choosing the right default
+ if (choosenStyle == -1) {
+ if (mVoiceCapable) {
+ choosenStyle = Settings.System.VOLUME_OVERLAY_SINGLE;
+ } else {
+ choosenStyle = Settings.System.VOLUME_OVERLAY_EXPANDABLE;
+ }
+ }
+ changeOverlayStyle(choosenStyle);
+ mMoreButton.setOnClickListener(this);
+
listenToRingerMode();
}
private void listenToRingerMode() {
final IntentFilter filter = new IntentFilter();
filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION);
+ filter.addAction(ACTION_VOLUME_OVERLAY_CHANGED);
mContext.registerReceiver(new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
@@ -340,18 +361,45 @@ public class VolumePanel extends Handler implements OnSeekBarChangeListener, Vie
if (AudioManager.RINGER_MODE_CHANGED_ACTION.equals(action)) {
removeMessages(MSG_RINGER_MODE_CHANGED);
sendMessage(obtainMessage(MSG_RINGER_MODE_CHANGED));
+ } else if (ACTION_VOLUME_OVERLAY_CHANGED.equals(action)) {
+ int state = (Integer) intent.getExtra("state");
+ changeOverlayStyle(state);
}
}
}, filter);
}
- private boolean isMuted(int streamType) {
- if (streamType == STREAM_MASTER) {
- return mAudioManager.isMasterMute();
- } else if (streamType == AudioService.STREAM_REMOTE_MUSIC) {
- return (mAudioService.getRemoteStreamVolume() <= 0);
- } else {
- return mAudioManager.isStreamMute(streamType);
+ private void changeOverlayStyle(int newStyle) {
+ Log.i("VolumePanel", "changeOverlayStyle : " + newStyle);
+ // Don't change to the same style
+ if (newStyle == mCurrentOverlayStyle) return;
+ switch (newStyle) {
+ case Settings.System.VOLUME_OVERLAY_SINGLE :
+ mMoreButton.setVisibility(View.GONE);
+ mDivider.setVisibility(View.GONE);
+ mShowCombinedVolumes = false;
+ mCurrentOverlayStyle = Settings.System.VOLUME_OVERLAY_SINGLE;
+ break;
+ case Settings.System.VOLUME_OVERLAY_EXPANDABLE :
+ mMoreButton.setVisibility(View.VISIBLE);
+ mDivider.setVisibility(View.VISIBLE);
+ mShowCombinedVolumes = true;
+ mCurrentOverlayStyle = Settings.System.VOLUME_OVERLAY_EXPANDABLE;
+ break;
+ case Settings.System.VOLUME_OVERLAY_EXPANDED :
+ mMoreButton.setVisibility(View.GONE);
+ mDivider.setVisibility(View.GONE);
+ mShowCombinedVolumes = true;
+ if (mCurrentOverlayStyle == Settings.System.VOLUME_OVERLAY_NONE) {
+ addOtherVolumes();
+ expand();
+ }
+ mCurrentOverlayStyle = Settings.System.VOLUME_OVERLAY_EXPANDED;
+ break;
+ case Settings.System.VOLUME_OVERLAY_NONE :
+ mShowCombinedVolumes = false;
+ mCurrentOverlayStyle = Settings.System.VOLUME_OVERLAY_NONE;
+ break;
}
}
@@ -385,6 +433,10 @@ public class VolumePanel extends Handler implements OnSeekBarChangeListener, Vie
}
}
+ private boolean isMuted(int streamType) {
+ return mAudioManager.isStreamMute(streamType);
+ }
+
private void createSliders() {
LayoutInflater inflater = (LayoutInflater) mContext
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
@@ -406,6 +458,7 @@ public class VolumePanel extends Handler implements OnSeekBarChangeListener, Vie
sc.iconRes = streamRes.iconRes;
sc.iconMuteRes = streamRes.iconMuteRes;
sc.icon.setImageResource(sc.iconRes);
+ sc.icon.setOnClickListener(this);
sc.seekbarView = (SeekBar) sc.group.findViewById(R.id.seekbar);
int plusOne = (streamType == AudioSystem.STREAM_BLUETOOTH_SCO ||
streamType == AudioSystem.STREAM_VOICE_CALL) ? 1 : 0;
@@ -442,6 +495,10 @@ public class VolumePanel extends Handler implements OnSeekBarChangeListener, Vie
if (!STREAMS[i].show || streamType == mActiveStreamType) {
continue;
}
+ // Skip ring volume for non-phone devices
+ if (!mVoiceCapable && streamType == AudioManager.STREAM_RING) {
+ continue;
+ }
StreamControl sc = mStreamControls.get(streamType);
mSliderGroup.addView(sc.group);
updateSlider(sc);
@@ -475,10 +532,22 @@ public class VolumePanel extends Handler implements OnSeekBarChangeListener, Vie
private void expand() {
final int count = mSliderGroup.getChildCount();
for (int i = 0; i < count; i++) {
- mSliderGroup.getChildAt(i).setVisibility(View.VISIBLE);
+ if (mSliderGroup.getChildAt(i).getVisibility() != View.VISIBLE) {
+ mSliderGroup.getChildAt(i).setVisibility(View.VISIBLE);
+ }
+ }
+ mMoreButton.setVisibility(View.GONE);
+ mDivider.setVisibility(View.GONE);
+ }
+
+ private void hideSlider(int mActiveStreamType) {
+ final int count = mSliderGroup.getChildCount();
+ for (int i = 0; i < count; i++) {
+ StreamControl sc = (StreamControl) mSliderGroup.getChildAt(i).getTag();
+ if (mActiveStreamType == sc.streamType) {
+ mSliderGroup.getChildAt(i).setVisibility(View.GONE);
+ }
}
- mMoreButton.setVisibility(View.INVISIBLE);
- mDivider.setVisibility(View.INVISIBLE);
}
private void collapse() {
@@ -578,8 +647,12 @@ public class VolumePanel extends Handler implements OnSeekBarChangeListener, Vie
if ((flags & AudioManager.FLAG_SHOW_UI) != 0) {
synchronized (this) {
- if (mActiveStreamType != streamType) {
- reorderSliders(streamType);
+ if (mActiveStreamType == -1 || streamType != mActiveStreamType) {
+ if (streamType != mActiveStreamType &&
+ mCurrentOverlayStyle == Settings.System.VOLUME_OVERLAY_EXPANDABLE) {
+ hideSlider(mActiveStreamType);
+ }
+ reorderSliders(streamType);
}
onShowVolumeChanged(streamType, flags);
}
@@ -709,17 +782,32 @@ public class VolumePanel extends Handler implements OnSeekBarChangeListener, Vie
} else {
sc.seekbarView.setEnabled(true);
}
+ // If adjusting Ring volume and preference is to link it to Notification
+ if (streamType == mAudioManager.STREAM_RING &&
+ System.getInt(mContext.getContentResolver(),System.VOLUME_LINK_NOTIFICATION, 1) == 1) {
+ StreamControl notifySc = mStreamControls.get(mAudioManager.STREAM_NOTIFICATION);
+ if (index > notifySc.seekbarView.getMax()) {
+ notifySc.seekbarView.setProgress(notifySc.seekbarView.getMax());
+ } else {
+ notifySc.seekbarView.setProgress(index);
+ }
+ }
}
- if (!mDialog.isShowing()) {
+ // Only Show if style needs it
+ if (!mDialog.isShowing() && mCurrentOverlayStyle != Settings.System.VOLUME_OVERLAY_NONE) {
int stream = (streamType == AudioService.STREAM_REMOTE_MUSIC) ? -1 : streamType;
// when the stream is for remote playback, use -1 to reset the stream type evaluation
mAudioManager.forceVolumeControlStream(stream);
mDialog.setContentView(mView);
// Showing dialog - use collapsed state
- if (mShowCombinedVolumes) {
+ if (mShowCombinedVolumes && mCurrentOverlayStyle != Settings.System.VOLUME_OVERLAY_EXPANDED) {
collapse();
}
+ // If just changed the style and we need to expand
+ if (mCurrentOverlayStyle == Settings.System.VOLUME_OVERLAY_EXPANDED) {
+ expand();
+ }
mDialog.show();
}
@@ -995,13 +1083,34 @@ public class VolumePanel extends Handler implements OnSeekBarChangeListener, Vie
sendMessage(obtainMessage(MSG_TIMEOUT));
}
- public void onProgressChanged(SeekBar seekBar, int progress,
- boolean fromUser) {
+ public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
final Object tag = seekBar.getTag();
if (fromUser && tag instanceof StreamControl) {
StreamControl sc = (StreamControl) tag;
if (getStreamVolume(sc.streamType) != progress) {
setStreamVolume(sc.streamType, progress, 0);
+ // if audio is linked then adjust other one if change made by user
+ if (fromUser && System.getInt(mContext.getContentResolver(),System.VOLUME_LINK_NOTIFICATION, 1) == 1) {
+ if (sc.streamType == AudioManager.STREAM_RING) {
+ StreamControl notifySc = mStreamControls.get(AudioManager.STREAM_NOTIFICATION);
+ if (notifySc != null) {
+ if (progress > notifySc.seekbarView.getMax()) {
+ notifySc.seekbarView.setProgress(notifySc.seekbarView.getMax());
+ } else {
+ notifySc.seekbarView.setProgress(progress);
+ }
+ }
+ } else if (sc.streamType == AudioManager.STREAM_NOTIFICATION) {
+ StreamControl phoneSc = mStreamControls.get(AudioManager.STREAM_RING);
+ if (phoneSc != null) {
+ if (progress > phoneSc.seekbarView.getMax()) {
+ phoneSc.seekbarView.setProgress(phoneSc.seekbarView.getMax());
+ } else {
+ phoneSc.seekbarView.setProgress(progress);
+ }
+ }
+ }
+ }
}
}
resetTimeout();
@@ -1027,6 +1136,12 @@ public class VolumePanel extends Handler implements OnSeekBarChangeListener, Vie
public void onClick(View v) {
if (v == mMoreButton) {
expand();
+ } else if (v instanceof ImageView) {
+ Intent volumeSettings = new Intent(android.provider.Settings.ACTION_SOUND_SETTINGS);
+ volumeSettings.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
+ forceTimeout();
+ mContext.startActivity(volumeSettings);
+ return;
}
resetTimeout();
}
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index 26739b3..fd5449c 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -399,6 +399,7 @@ public interface WindowManagerPolicy {
public void shutdown(boolean confirm);
public void rebootSafeMode(boolean confirm);
+ public void reboot();
}
/**
diff --git a/core/java/com/android/internal/util/weather/HttpRetriever.java b/core/java/com/android/internal/util/weather/HttpRetriever.java
new file mode 100644
index 0000000..a3417a0
--- /dev/null
+++ b/core/java/com/android/internal/util/weather/HttpRetriever.java
@@ -0,0 +1,152 @@
+/******************************************************************************
+ * Class : HttpConnectHelper.java *
+ * Main Weather activity, in this demo apps i use API from yahoo, you can *
+ * use other weather web service which you prefer *
+ * *
+ * Version : v1.0 *
+ * Date : May 09, 2011 *
+ * Copyright (c)-2011 DatNQ some right reserved *
+ * You can distribute, modify or what ever you want but WITHOUT ANY WARRANTY *
+ * Be honest by keep credit of this file *
+ * *
+ * If you have any concern, feel free to contact with me via email, i will *
+ * check email in free time *
+ * Email: nguyendatnq@gmail.com *
+ * ---------------------------------------------------------------------------*
+ * Modification Logs: *
+ * KEYCHANGE DATE AUTHOR DESCRIPTION *
+ * ---------------------------------------------------------------------------*
+ * ------- May 09, 2011 DatNQ Create new *
+ ******************************************************************************/
+
+/**
+ * Modification into Android-internal HttpRetreiver.java
+ * Copyright (C) 2012 The AOKP Project
+ */
+
+
+package com.android.internal.util.weather;
+
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpResponse;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.impl.client.DefaultHttpClient;
+import org.apache.http.util.EntityUtils;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.HttpURLConnection;
+import java.net.URL;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+
+import org.w3c.dom.Document;
+
+import android.util.Log;
+
+public class HttpRetriever {
+
+ private final String TAG = getClass().getSimpleName();
+ private DefaultHttpClient client = new DefaultHttpClient();
+ private HttpURLConnection httpConnection;
+
+ public String retrieve(String url) {
+ HttpGet get = new HttpGet(url);
+ try {
+ HttpResponse getResponse = client.execute(get);
+ HttpEntity getResponseEntity = getResponse.getEntity();
+ if (getResponseEntity != null) {
+ String response = EntityUtils.toString(getResponseEntity);
+ return response;
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ private void requestConnectServer(String strURL) throws IOException {
+ httpConnection = (HttpURLConnection) new URL(strURL).openConnection();
+ httpConnection.connect();
+
+ if (httpConnection.getResponseCode() != HttpURLConnection.HTTP_OK) {
+ Log.e(TAG, "Something wrong with connection");
+ httpConnection.disconnect();
+ throw new IOException("Error in connection: " + httpConnection.getResponseCode());
+ }
+ }
+
+ private void requestDisconnect() {
+ if (httpConnection != null) {
+ httpConnection.disconnect();
+ }
+ }
+
+ public Document getDocumentFromURL(String strURL) throws IOException {
+ if (strURL == null) {
+ Log.e(TAG, "Invalid input URL");
+ return null;
+ }
+
+ // Connect to server, get data and close
+ requestConnectServer(strURL);
+ String strDocContent = getDataFromConnection();
+ requestDisconnect();
+
+ if (strDocContent == null) {
+ Log.e(TAG, "Cannot get XML content");
+ return null;
+ }
+
+ int strContentSize = strDocContent.length();
+ StringBuffer strBuff = new StringBuffer();
+ strBuff.setLength(strContentSize + 1);
+ strBuff.append(strDocContent);
+ ByteArrayInputStream is = new ByteArrayInputStream(strDocContent.getBytes());
+
+ DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
+ DocumentBuilder db;
+ Document docData = null;
+
+ try {
+ db = dbf.newDocumentBuilder();
+ docData = db.parse(is);
+ } catch (Exception e) {
+ Log.e(TAG, "Parser data error");
+ return null;
+ }
+ return docData;
+ }
+
+ private String getDataFromConnection() throws IOException {
+ if (httpConnection == null) {
+ Log.e(TAG, "Connection is null");
+ return null;
+ }
+
+ String strValue = null;
+ InputStream inputStream = httpConnection.getInputStream();
+ if (inputStream == null) {
+ Log.e(TAG, "Input stream error");
+ return null;
+ }
+
+ StringBuffer strBuf = new StringBuffer();
+ BufferedReader buffReader = new BufferedReader(new InputStreamReader(inputStream));
+ String strLine = "";
+
+ while ((strLine = buffReader.readLine()) != null) {
+ strBuf.append(strLine + "\n");
+ strValue += strLine + "\n";
+ }
+
+ // Release resource to system
+ buffReader.close();
+ inputStream.close();
+ return strBuf.toString();
+ }
+}
diff --git a/core/java/com/android/internal/util/weather/WeatherInfo.java b/core/java/com/android/internal/util/weather/WeatherInfo.java
new file mode 100644
index 0000000..2b65785
--- /dev/null
+++ b/core/java/com/android/internal/util/weather/WeatherInfo.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2012 The AOKP Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.util.weather;
+
+import android.content.Context;
+import com.android.internal.R;
+
+public class WeatherInfo {
+
+ public static final String NODATA = "-";
+
+ public String city, forecast_date, condition, condition_code, temp, temp_unit,
+ humidity, wind, wind_dir, speed_unit, low, high;
+ public long last_sync;
+
+ public WeatherInfo() {
+ this.city = NODATA;
+ this.forecast_date = NODATA;
+ this.condition = NODATA;
+ this.condition_code = NODATA;
+ this.temp = NODATA;
+ this.temp_unit = NODATA;
+ this.humidity = NODATA;
+ this.wind = NODATA;
+ this.wind_dir = NODATA;
+ this.speed_unit = NODATA;
+ this.low = NODATA;
+ this.high = NODATA;
+ this.last_sync = 0;
+ }
+
+ public WeatherInfo(Context context, String city, String fdate, String condition, String condition_code,
+ String temp, String temp_unit, String humidity,
+ String wind, String wind_dir, String speed_unit,
+ String low, String high, long last_sync) {
+ this.city = city;
+ this.forecast_date = fdate;
+ this.condition = condition;
+ this.condition_code = condition_code;
+ this.humidity = humidity + "%";
+ this.wind = calcDirection(context, wind_dir) + " " + trimSpeed(wind) + speed_unit;
+ this.speed_unit = speed_unit;
+ this.last_sync = last_sync;
+ // Only the current temperature gets the temp_unit added.
+ this.temp_unit = temp_unit;
+ this.temp = temp + "°" + temp_unit;
+ this.low = low + "°";
+ this.high = high + "°";
+ }
+
+ /**
+ * find the optimal weather string (helper function for translation)
+ *
+ * @param conditionCode condition code from Yahoo (this is the main
+ * identifier which will be used to find a matching translation
+ * in the project's resources
+ * @param providedString
+ * @return either the defaultString (which should be Yahoo's weather
+ * condition text), or the translated version from resources
+ */
+ public static String getTranslatedConditionString(Context context, int conditionCode,
+ String providedString) {
+ int resID = context.getResources().getIdentifier("weather_" + conditionCode, "string",
+ context.getPackageName());
+ return (resID != 0) ? context.getResources().getString(resID) : providedString;
+ }
+
+ private String calcDirection(Context context, String degrees) {
+ try {
+ int deg = Integer.parseInt(degrees);
+ if (deg >= 338 || deg <= 22)
+ return context.getResources().getString(R.string.weather_N);
+ else if (deg < 68)
+ return context.getResources().getString(R.string.weather_NE);
+ else if (deg < 113)
+ return context.getResources().getString(R.string.weather_E);
+ else if (deg < 158)
+ return context.getResources().getString(R.string.weather_SE);
+ else if (deg < 203)
+ return context.getResources().getString(R.string.weather_S);
+ else if (deg < 248)
+ return context.getResources().getString(R.string.weather_SW);
+ else if (deg < 293)
+ return context.getResources().getString(R.string.weather_W);
+ else if (deg < 338)
+ return context.getResources().getString(R.string.weather_NW);
+ else
+ return "";
+ } catch (NumberFormatException e) {
+ return "";
+ }
+ }
+
+ private String trimSpeed(String speed) {
+ try {
+ return String.valueOf(Math.round(Float.parseFloat(speed)));
+ } catch (NumberFormatException e) {
+ return "";
+ }
+ }
+}
diff --git a/core/java/com/android/internal/util/weather/WeatherXmlParser.java b/core/java/com/android/internal/util/weather/WeatherXmlParser.java
new file mode 100644
index 0000000..a2986fc
--- /dev/null
+++ b/core/java/com/android/internal/util/weather/WeatherXmlParser.java
@@ -0,0 +1,177 @@
+/******************************************************************************
+ * Class : YahooWeatherHelper.java *
+ * Parser helper for Yahoo *
+ * *
+ * Version : v1.0 *
+ * Date : May 06, 2011 *
+ * Copyright (c)-2011 DatNQ some right reserved *
+ * You can distribute, modify or what ever you want but WITHOUT ANY WARRANTY *
+ * Be honest by keep credit of this file *
+ * *
+ * If you have any concern, feel free to contact with me via email, i will *
+ * check email in free time *
+ * Email: nguyendatnq@gmail.com *
+ * ---------------------------------------------------------------------------*
+ * Modification Logs: *
+ * KEYCHANGE DATE AUTHOR DESCRIPTION *
+ * ---------------------------------------------------------------------------*
+ * ------- May 06, 2011 DatNQ Create new *
+ ******************************************************************************/
+/*
+ * Modification into Android-internal WeatherXmlParser.java
+ * Copyright (C) 2012 The AOKP Project
+ */
+
+package com.android.internal.util.weather;
+
+import java.io.StringReader;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.InputSource;
+
+import android.content.Context;
+import android.util.Log;
+
+public class WeatherXmlParser {
+
+ protected static final String TAG = "WeatherXmlParser";
+
+ /** Yahoo attributes */
+ private static final String PARAM_YAHOO_LOCATION = "yweather:location";
+ private static final String PARAM_YAHOO_UNIT = "yweather:units";
+ private static final String PARAM_YAHOO_ATMOSPHERE = "yweather:atmosphere";
+ private static final String PARAM_YAHOO_CONDITION = "yweather:condition";
+ private static final String PARAM_YAHOO_WIND = "yweather:wind";
+ private static final String PARAM_YAHOO_FORECAST = "yweather:forecast";
+
+ private static final String ATT_YAHOO_CITY = "city";
+ private static final String ATT_YAHOO_TEMP = "temp";
+ private static final String ATT_YAHOO_CODE = "code";
+ private static final String ATT_YAHOO_TEMP_UNIT = "temperature";
+ private static final String ATT_YAHOO_HUMIDITY = "humidity";
+ private static final String ATT_YAHOO_TEXT = "text";
+ private static final String ATT_YAHOO_DATE = "date";
+ private static final String ATT_YAHOO_SPEED = "speed";
+ private static final String ATT_YAHOO_DIRECTION = "direction";
+ private static final String ATT_YAHOO_TODAY_HIGH = "high";
+ private static final String ATT_YAHOO_TODAY_LOW = "low";
+
+ private Context mContext;
+
+ public WeatherXmlParser(Context context) {
+ mContext = context;
+ }
+
+ public WeatherInfo parseWeatherResponse(Document docWeather) {
+ if (docWeather == null) {
+ Log.e(TAG, "Invalid doc weather");
+ return null;
+ }
+
+ String strCity = null;
+ String strDate = null;
+ String strCondition = null;
+ String strCondition_code = null;
+ String strTemp = null;
+ String strTempUnit = null;
+ String strHumidity = null;
+ String strWindSpeed = null;
+ String strWindDir = null;
+ String strSpeedUnit = null;
+ String strHigh = null;
+ String strLow = null;
+
+ try {
+ Element root = docWeather.getDocumentElement();
+ root.normalize();
+
+ NamedNodeMap locationNode = root.getElementsByTagName(PARAM_YAHOO_LOCATION).item(0)
+ .getAttributes();
+ if (locationNode != null) {
+ strCity = locationNode.getNamedItem(ATT_YAHOO_CITY).getNodeValue();
+ }
+
+ NamedNodeMap unitNode = root.getElementsByTagName(PARAM_YAHOO_UNIT).item(0)
+ .getAttributes();
+
+ if (locationNode != null) {
+ strTempUnit = unitNode.getNamedItem(ATT_YAHOO_TEMP_UNIT).getNodeValue();
+ strSpeedUnit = unitNode.getNamedItem(ATT_YAHOO_SPEED).getNodeValue();
+ }
+
+ NamedNodeMap atmosNode = root.getElementsByTagName(PARAM_YAHOO_ATMOSPHERE).item(0)
+ .getAttributes();
+ if (atmosNode != null) {
+ strHumidity = atmosNode.getNamedItem(ATT_YAHOO_HUMIDITY).getNodeValue();
+ }
+
+ NamedNodeMap conditionNode = root.getElementsByTagName(PARAM_YAHOO_CONDITION).item(0)
+ .getAttributes();
+ if (conditionNode != null) {
+ strCondition = conditionNode.getNamedItem(ATT_YAHOO_TEXT).getNodeValue();
+ strCondition_code = conditionNode.getNamedItem(ATT_YAHOO_CODE).getNodeValue();
+ strCondition = WeatherInfo.getTranslatedConditionString(mContext, Integer.parseInt(strCondition_code), strCondition);
+ strTemp = conditionNode.getNamedItem(ATT_YAHOO_TEMP).getNodeValue();
+ strDate = conditionNode.getNamedItem(ATT_YAHOO_DATE).getNodeValue();
+ }
+
+ NamedNodeMap temNode = root.getElementsByTagName(PARAM_YAHOO_WIND).item(0)
+ .getAttributes();
+ if (temNode != null) {
+ strWindSpeed = temNode.getNamedItem(ATT_YAHOO_SPEED).getNodeValue();
+ strWindDir = temNode.getNamedItem(ATT_YAHOO_DIRECTION).getNodeValue();
+ }
+
+ NamedNodeMap fcNode = root.getElementsByTagName(PARAM_YAHOO_FORECAST).item(0).getAttributes();
+ if (fcNode != null) {
+ strHigh = fcNode.getNamedItem(ATT_YAHOO_TODAY_HIGH).getNodeValue();
+ strLow = fcNode.getNamedItem(ATT_YAHOO_TODAY_LOW).getNodeValue();
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "Something wrong with parser data: " + e.toString());
+ return null;
+ }
+
+ /* Weather info */
+ WeatherInfo yahooWeatherInfo = new WeatherInfo(mContext, strCity, strDate, strCondition, strCondition_code, strTemp,
+ strTempUnit, strHumidity, strWindSpeed, strWindDir, strSpeedUnit, strLow, strHigh, System.currentTimeMillis());
+
+ Log.d(TAG, "Weather updated for " + strCity + ": " + strDate + ", " + strCondition + "(" + strCondition_code
+ + "), " + strTemp + strTempUnit + ", " + strHumidity + "% humidity, " + ", wind: " + strWindDir + " at "
+ + strWindSpeed + strSpeedUnit + ", low: " + strLow + strTempUnit + " high: " + strHigh + strTempUnit);
+
+ return yahooWeatherInfo;
+ }
+
+ public String parsePlaceFinderResponse(String response) {
+ try {
+
+ DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
+ DocumentBuilder db = dbf.newDocumentBuilder();
+ Document doc = db.parse(new InputSource(new StringReader(response)));
+
+ NodeList resultNodes = doc.getElementsByTagName("Result");
+
+ Node resultNode = resultNodes.item(0);
+ NodeList attrsList = resultNode.getChildNodes();
+
+ for (int i = 0; i < attrsList.getLength(); i++) {
+ Node node = attrsList.item(i);
+ Node firstChild = node.getFirstChild();
+ if ("woeid".equalsIgnoreCase(node.getNodeName()) && firstChild != null) {
+ return firstChild.getNodeValue();
+ }
+ }
+ } catch (Exception e) {
+ Log.e(TAG, e.toString());
+ }
+ return null;
+ }
+}
diff --git a/core/java/com/android/internal/util/weather/YahooPlaceFinder.java b/core/java/com/android/internal/util/weather/YahooPlaceFinder.java
new file mode 100644
index 0000000..fb8efe4
--- /dev/null
+++ b/core/java/com/android/internal/util/weather/YahooPlaceFinder.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2012 The AOKP Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.util.weather;
+
+import android.content.Context;
+
+public class YahooPlaceFinder {
+
+ private static final String YAHOO_API_BASE_REV_URL = "http://where.yahooapis.com/geocode?appid=jYkTZp64&q=%1$s,+%2$s&gflags=R";
+ private static final String YAHOO_API_BASE_URL = "http://where.yahooapis.com/geocode?appid=jYkTZp64&q=%1$s";
+
+ public static String reverseGeoCode(Context c, double latitude, double longitude) {
+
+ String url = String.format(YAHOO_API_BASE_REV_URL, String.valueOf(latitude),
+ String.valueOf(longitude));
+ String response = new HttpRetriever().retrieve(url);
+ return new WeatherXmlParser(c).parsePlaceFinderResponse(response);
+
+ }
+
+ public static String GeoCode(Context c, String location) {
+ String url = String.format(YAHOO_API_BASE_URL, location).replace(' ', '+');
+ String response = new HttpRetriever().retrieve(url);
+ return new WeatherXmlParser(c).parsePlaceFinderResponse(response);
+ }
+
+}
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index 75fef24..8f419e4 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2007 The Android Open Source Project
+ * Copyright (C) 2012 The CyanogenMod Project (Calendar)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -23,6 +24,8 @@ import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
+import android.database.Cursor;
+import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
@@ -31,10 +34,13 @@ import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.UserHandle;
import android.os.storage.IMountService;
+import android.provider.CalendarContract;
import android.provider.Settings;
import android.security.KeyStore;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
+import android.text.format.DateFormat;
+import android.text.format.Time;
import android.util.Log;
import android.view.IWindowManager;
import android.view.View;
@@ -47,7 +53,10 @@ import com.google.android.collect.Lists;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
+import java.text.SimpleDateFormat;
+import java.util.Date;
import java.util.List;
+import java.util.TimeZone;
/**
* Utilities for the lock pattern and its settings.
@@ -1038,6 +1047,166 @@ public class LockPatternUtils {
return nextAlarm;
}
+ /**
+ * @return A formatted string of the next calendar event with a reminder
+ * (for showing on the lock screen), or null if there is no next event
+ * within a certain look-ahead time.
+ */
+ public String[] getNextCalendarAlarm(long lookahead, String[] calendars,
+ boolean remindersOnly) {
+ long now = System.currentTimeMillis();
+ long later = now + lookahead;
+
+ StringBuilder where = new StringBuilder();
+ if (remindersOnly) {
+ where.append(CalendarContract.Events.HAS_ALARM + "=1");
+ }
+ if (calendars != null && calendars.length > 0) {
+ if (remindersOnly) {
+ where.append(" AND ");
+ }
+ where.append(CalendarContract.Events.CALENDAR_ID + " in (");
+ for (int i = 0; i < calendars.length; i++) {
+ where.append(calendars[i]);
+ if (i != calendars.length - 1) {
+ where.append(",");
+ }
+ }
+ where.append(") ");
+ }
+
+ // Projection array
+ String[] projection = new String[] {
+ CalendarContract.Events.TITLE,
+ CalendarContract.Instances.BEGIN,
+ CalendarContract.Events.DESCRIPTION,
+ CalendarContract.Events.EVENT_LOCATION,
+ CalendarContract.Events.ALL_DAY
+ };
+
+ // The indices for the projection array
+ int TITLE_INDEX = 0;
+ int BEGIN_TIME_INDEX = 1;
+ int DESCRIPTION_INDEX = 2;
+ int LOCATION_INDEX = 3;
+ int ALL_DAY_INDEX = 4;
+
+ Uri uri = Uri.withAppendedPath(CalendarContract.Instances.CONTENT_URI,
+ String.format("%d/%d", now, later));
+ String[] nextCalendarAlarm = new String[2];
+ Cursor cursor = null;
+
+ try {
+ cursor = mContentResolver.query(uri, projection,
+ where.toString(), null, "begin ASC");
+
+ if (cursor != null && cursor.moveToFirst()) {
+
+ String title = cursor.getString(TITLE_INDEX);
+ long begin = cursor.getLong(BEGIN_TIME_INDEX);
+ String description = cursor.getString(DESCRIPTION_INDEX);
+ String location = cursor.getString(LOCATION_INDEX);
+ boolean allDay = cursor.getInt(ALL_DAY_INDEX) != 0;
+
+ // Check the next event in the case of all day event. As UTC is used for all day
+ // events, the next event may be the one that actually starts sooner
+ if (allDay && !cursor.isLast()) {
+ cursor.moveToNext();
+ long nextBegin = cursor.getLong(BEGIN_TIME_INDEX);
+ if (nextBegin < begin + TimeZone.getDefault().getOffset(begin)) {
+ title = cursor.getString(TITLE_INDEX);
+ begin = nextBegin;
+ description = cursor.getString(DESCRIPTION_INDEX);
+ location = cursor.getString(LOCATION_INDEX);
+ allDay = cursor.getInt(ALL_DAY_INDEX) != 0;
+ }
+ }
+
+ // Set the event title as the first array item
+ nextCalendarAlarm[0] = title.toString();
+
+ // Start building the event details string
+ // Starting with the date
+ Date start = new Date(begin);
+ StringBuilder sb = new StringBuilder();
+
+ if (allDay) {
+ SimpleDateFormat sdf = new SimpleDateFormat(
+ mContext.getString(R.string.abbrev_wday_month_day_no_year));
+ // Calendar stores all-day events in UTC -- setting the time zone ensures
+ // the correct date is shown.
+ sdf.setTimeZone(TimeZone.getTimeZone(Time.TIMEZONE_UTC));
+ sb.append(sdf.format(start));
+ } else {
+ sb.append(DateFormat.format("E", start));
+ sb.append(" ");
+ sb.append(DateFormat.getTimeFormat(mContext).format(start));
+ }
+
+ // Add the event location if it should be shown
+ int showLocation = Settings.System.getInt(mContext.getContentResolver(),
+ Settings.System.LOCKSCREEN_CALENDAR_SHOW_LOCATION, 0);
+ if (showLocation != 0 && !TextUtils.isEmpty(location)) {
+ switch(showLocation) {
+ case 1:
+ // Show first line
+ int end = location.indexOf('\n');
+ if(end == -1) {
+ sb.append(": " + location);
+ } else {
+ sb.append(": " + location.substring(0, end));
+ }
+ break;
+ case 2:
+ // Show all
+ sb.append(": " + location);
+ break;
+ }
+ }
+
+ // Add the event description if it should be shown
+ int showDescription = Settings.System.getInt(mContext.getContentResolver(),
+ Settings.System.LOCKSCREEN_CALENDAR_SHOW_DESCRIPTION, 0);
+ if (showDescription != 0 && !TextUtils.isEmpty(description)) {
+
+ // Show the appropriate separator
+ if (showLocation == 0) {
+ sb.append(": ");
+ } else {
+ sb.append(" - ");
+ }
+
+ switch(showDescription) {
+ case 1:
+ // Show first line
+ int end = description.indexOf('\n');
+ if(end == -1) {
+ sb.append(description);
+ } else {
+ sb.append(description.substring(0, end));
+ }
+ break;
+ case 2:
+ // Show all
+ sb.append(description);
+ break;
+ }
+ }
+
+ // Set the time, location and description as the second array item
+ nextCalendarAlarm[1] = sb.toString();
+ }
+ } catch (Exception e) {
+ // Do nothing
+ } finally {
+ if (cursor != null) {
+ cursor.close();
+ }
+ }
+
+ return nextCalendarAlarm;
+ }
+
private boolean getBoolean(String secureSettingKey, boolean defaultValue) {
try {
return getLockSettings().getBoolean(secureSettingKey, defaultValue,
@@ -1346,4 +1515,13 @@ public class LockPatternUtils {
return false;
}
+ /**
+ * @hide
+ * Set the lock-before-unlock option (show widgets before the secure
+ * unlock screen). See config_enableLockBeforeUnlockScreen
+ */
+ public void setLockBeforeUnlock(boolean enabled) {
+ setBoolean(Settings.Secure.LOCK_BEFORE_UNLOCK, enabled);
+ }
+
}
diff --git a/core/res/res/drawable-hdpi/ic_lock_idle_calendar.png b/core/res/res/drawable-hdpi/ic_lock_idle_calendar.png
new file mode 100644
index 0000000..05b68b1
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_lock_idle_calendar.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lock_profile.png b/core/res/res/drawable-hdpi/ic_lock_profile.png
new file mode 100644
index 0000000..7fc4cec
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_lock_profile.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lock_reboot.png b/core/res/res/drawable-hdpi/ic_lock_reboot.png
new file mode 100644
index 0000000..ca00936
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_lock_reboot.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lock_screenshot.png b/core/res/res/drawable-hdpi/ic_lock_screenshot.png
new file mode 100644
index 0000000..5ef76f7
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_lock_screenshot.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_chrome_activated.png b/core/res/res/drawable-hdpi/ic_lockscreen_chrome_activated.png
new file mode 100644
index 0000000..75357a0
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_lockscreen_chrome_activated.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_chrome_normal.png b/core/res/res/drawable-hdpi/ic_lockscreen_chrome_normal.png
new file mode 100644
index 0000000..f6f29d1
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_lockscreen_chrome_normal.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_google_activated.png b/core/res/res/drawable-hdpi/ic_lockscreen_google_activated.png
index 2c4847c..7c105e6 100644
--- a/core/res/res/drawable-hdpi/ic_lockscreen_google_activated.png
+++ b/core/res/res/drawable-hdpi/ic_lockscreen_google_activated.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_google_normal.png b/core/res/res/drawable-hdpi/ic_lockscreen_google_normal.png
index 656f3ba..5daf9ed 100644
--- a/core/res/res/drawable-hdpi/ic_lockscreen_google_normal.png
+++ b/core/res/res/drawable-hdpi/ic_lockscreen_google_normal.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/weather_0.png b/core/res/res/drawable-hdpi/weather_0.png
new file mode 100644
index 0000000..9e539b6
--- /dev/null
+++ b/core/res/res/drawable-hdpi/weather_0.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/weather_1.png b/core/res/res/drawable-hdpi/weather_1.png
new file mode 100644
index 0000000..9e539b6
--- /dev/null
+++ b/core/res/res/drawable-hdpi/weather_1.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/weather_10.png b/core/res/res/drawable-hdpi/weather_10.png
new file mode 100644
index 0000000..daf991e
--- /dev/null
+++ b/core/res/res/drawable-hdpi/weather_10.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/weather_11.png b/core/res/res/drawable-hdpi/weather_11.png
new file mode 100644
index 0000000..91a74a5
--- /dev/null
+++ b/core/res/res/drawable-hdpi/weather_11.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/weather_12.png b/core/res/res/drawable-hdpi/weather_12.png
new file mode 100644
index 0000000..91a74a5
--- /dev/null
+++ b/core/res/res/drawable-hdpi/weather_12.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/weather_13.png b/core/res/res/drawable-hdpi/weather_13.png
new file mode 100644
index 0000000..b2f41a5
--- /dev/null
+++ b/core/res/res/drawable-hdpi/weather_13.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/weather_14.png b/core/res/res/drawable-hdpi/weather_14.png
new file mode 100644
index 0000000..b2f41a5
--- /dev/null
+++ b/core/res/res/drawable-hdpi/weather_14.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/weather_15.png b/core/res/res/drawable-hdpi/weather_15.png
new file mode 100644
index 0000000..2e92b35
--- /dev/null
+++ b/core/res/res/drawable-hdpi/weather_15.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/weather_16.png b/core/res/res/drawable-hdpi/weather_16.png
new file mode 100644
index 0000000..bf4564c
--- /dev/null
+++ b/core/res/res/drawable-hdpi/weather_16.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/weather_17.png b/core/res/res/drawable-hdpi/weather_17.png
new file mode 100644
index 0000000..f7948c1
--- /dev/null
+++ b/core/res/res/drawable-hdpi/weather_17.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/weather_18.png b/core/res/res/drawable-hdpi/weather_18.png
new file mode 100644
index 0000000..802a80f
--- /dev/null
+++ b/core/res/res/drawable-hdpi/weather_18.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/weather_19.png b/core/res/res/drawable-hdpi/weather_19.png
new file mode 100644
index 0000000..b67ba5e
--- /dev/null
+++ b/core/res/res/drawable-hdpi/weather_19.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/weather_2.png b/core/res/res/drawable-hdpi/weather_2.png
new file mode 100644
index 0000000..9e539b6
--- /dev/null
+++ b/core/res/res/drawable-hdpi/weather_2.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/weather_20.png b/core/res/res/drawable-hdpi/weather_20.png
new file mode 100644
index 0000000..fd40f33
--- /dev/null
+++ b/core/res/res/drawable-hdpi/weather_20.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/weather_21.png b/core/res/res/drawable-hdpi/weather_21.png
new file mode 100644
index 0000000..8349b21
--- /dev/null
+++ b/core/res/res/drawable-hdpi/weather_21.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/weather_22.png b/core/res/res/drawable-hdpi/weather_22.png
new file mode 100644
index 0000000..b67ba5e
--- /dev/null
+++ b/core/res/res/drawable-hdpi/weather_22.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/weather_23.png b/core/res/res/drawable-hdpi/weather_23.png
new file mode 100644
index 0000000..ca015be
--- /dev/null
+++ b/core/res/res/drawable-hdpi/weather_23.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/weather_24.png b/core/res/res/drawable-hdpi/weather_24.png
new file mode 100644
index 0000000..ca015be
--- /dev/null
+++ b/core/res/res/drawable-hdpi/weather_24.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/weather_25.png b/core/res/res/drawable-hdpi/weather_25.png
new file mode 100644
index 0000000..32cb0d8
--- /dev/null
+++ b/core/res/res/drawable-hdpi/weather_25.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/weather_26.png b/core/res/res/drawable-hdpi/weather_26.png
new file mode 100644
index 0000000..ce9761a
--- /dev/null
+++ b/core/res/res/drawable-hdpi/weather_26.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/weather_27.png b/core/res/res/drawable-hdpi/weather_27.png
new file mode 100644
index 0000000..67433a7
--- /dev/null
+++ b/core/res/res/drawable-hdpi/weather_27.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/weather_28.png b/core/res/res/drawable-hdpi/weather_28.png
new file mode 100644
index 0000000..43f3df8
--- /dev/null
+++ b/core/res/res/drawable-hdpi/weather_28.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/weather_29.png b/core/res/res/drawable-hdpi/weather_29.png
new file mode 100644
index 0000000..67433a7
--- /dev/null
+++ b/core/res/res/drawable-hdpi/weather_29.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/weather_3.png b/core/res/res/drawable-hdpi/weather_3.png
new file mode 100644
index 0000000..708a2e6
--- /dev/null
+++ b/core/res/res/drawable-hdpi/weather_3.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/weather_30.png b/core/res/res/drawable-hdpi/weather_30.png
new file mode 100644
index 0000000..43f3df8
--- /dev/null
+++ b/core/res/res/drawable-hdpi/weather_30.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/weather_31.png b/core/res/res/drawable-hdpi/weather_31.png
new file mode 100644
index 0000000..d545d77
--- /dev/null
+++ b/core/res/res/drawable-hdpi/weather_31.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/weather_32.png b/core/res/res/drawable-hdpi/weather_32.png
new file mode 100644
index 0000000..c55e4b3
--- /dev/null
+++ b/core/res/res/drawable-hdpi/weather_32.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/weather_33.png b/core/res/res/drawable-hdpi/weather_33.png
new file mode 100644
index 0000000..d545d77
--- /dev/null
+++ b/core/res/res/drawable-hdpi/weather_33.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/weather_34.png b/core/res/res/drawable-hdpi/weather_34.png
new file mode 100644
index 0000000..c55e4b3
--- /dev/null
+++ b/core/res/res/drawable-hdpi/weather_34.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/weather_35.png b/core/res/res/drawable-hdpi/weather_35.png
new file mode 100644
index 0000000..3cd1b81
--- /dev/null
+++ b/core/res/res/drawable-hdpi/weather_35.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/weather_36.png b/core/res/res/drawable-hdpi/weather_36.png
new file mode 100644
index 0000000..06cb774
--- /dev/null
+++ b/core/res/res/drawable-hdpi/weather_36.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/weather_37.png b/core/res/res/drawable-hdpi/weather_37.png
new file mode 100644
index 0000000..8b2c4d1
--- /dev/null
+++ b/core/res/res/drawable-hdpi/weather_37.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/weather_38.png b/core/res/res/drawable-hdpi/weather_38.png
new file mode 100644
index 0000000..f0509ef
--- /dev/null
+++ b/core/res/res/drawable-hdpi/weather_38.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/weather_39.png b/core/res/res/drawable-hdpi/weather_39.png
new file mode 100644
index 0000000..8b2c4d1
--- /dev/null
+++ b/core/res/res/drawable-hdpi/weather_39.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/weather_4.png b/core/res/res/drawable-hdpi/weather_4.png
new file mode 100644
index 0000000..708a2e6
--- /dev/null
+++ b/core/res/res/drawable-hdpi/weather_4.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/weather_40.png b/core/res/res/drawable-hdpi/weather_40.png
new file mode 100644
index 0000000..fb3c06d
--- /dev/null
+++ b/core/res/res/drawable-hdpi/weather_40.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/weather_41.png b/core/res/res/drawable-hdpi/weather_41.png
new file mode 100644
index 0000000..bf4564c
--- /dev/null
+++ b/core/res/res/drawable-hdpi/weather_41.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/weather_42.png b/core/res/res/drawable-hdpi/weather_42.png
new file mode 100644
index 0000000..7b81366
--- /dev/null
+++ b/core/res/res/drawable-hdpi/weather_42.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/weather_43.png b/core/res/res/drawable-hdpi/weather_43.png
new file mode 100644
index 0000000..bf4564c
--- /dev/null
+++ b/core/res/res/drawable-hdpi/weather_43.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/weather_44.png b/core/res/res/drawable-hdpi/weather_44.png
new file mode 100644
index 0000000..67433a7
--- /dev/null
+++ b/core/res/res/drawable-hdpi/weather_44.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/weather_45.png b/core/res/res/drawable-hdpi/weather_45.png
new file mode 100644
index 0000000..708a2e6
--- /dev/null
+++ b/core/res/res/drawable-hdpi/weather_45.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/weather_46.png b/core/res/res/drawable-hdpi/weather_46.png
new file mode 100644
index 0000000..b2f41a5
--- /dev/null
+++ b/core/res/res/drawable-hdpi/weather_46.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/weather_47.png b/core/res/res/drawable-hdpi/weather_47.png
new file mode 100644
index 0000000..f0509ef
--- /dev/null
+++ b/core/res/res/drawable-hdpi/weather_47.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/weather_5.png b/core/res/res/drawable-hdpi/weather_5.png
new file mode 100644
index 0000000..802a80f
--- /dev/null
+++ b/core/res/res/drawable-hdpi/weather_5.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/weather_6.png b/core/res/res/drawable-hdpi/weather_6.png
new file mode 100644
index 0000000..802a80f
--- /dev/null
+++ b/core/res/res/drawable-hdpi/weather_6.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/weather_7.png b/core/res/res/drawable-hdpi/weather_7.png
new file mode 100644
index 0000000..802a80f
--- /dev/null
+++ b/core/res/res/drawable-hdpi/weather_7.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/weather_8.png b/core/res/res/drawable-hdpi/weather_8.png
new file mode 100644
index 0000000..e36a680
--- /dev/null
+++ b/core/res/res/drawable-hdpi/weather_8.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/weather_9.png b/core/res/res/drawable-hdpi/weather_9.png
new file mode 100644
index 0000000..7651b3e
--- /dev/null
+++ b/core/res/res/drawable-hdpi/weather_9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/weather_na.png b/core/res/res/drawable-hdpi/weather_na.png
new file mode 100644
index 0000000..4a43283
--- /dev/null
+++ b/core/res/res/drawable-hdpi/weather_na.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lock_idle_calendar.png b/core/res/res/drawable-mdpi/ic_lock_idle_calendar.png
new file mode 100644
index 0000000..2834c8f
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_lock_idle_calendar.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lock_profile.png b/core/res/res/drawable-mdpi/ic_lock_profile.png
new file mode 100644
index 0000000..d47ba16
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_lock_profile.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lock_reboot.png b/core/res/res/drawable-mdpi/ic_lock_reboot.png
new file mode 100644
index 0000000..2b125b9
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_lock_reboot.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lock_screenshot.png b/core/res/res/drawable-mdpi/ic_lock_screenshot.png
new file mode 100644
index 0000000..9996e72
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_lock_screenshot.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_chrome_activated.png b/core/res/res/drawable-mdpi/ic_lockscreen_chrome_activated.png
new file mode 100644
index 0000000..52a4221e
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_lockscreen_chrome_activated.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_chrome_normal.png b/core/res/res/drawable-mdpi/ic_lockscreen_chrome_normal.png
new file mode 100644
index 0000000..1abda2f
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_lockscreen_chrome_normal.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_google_activated.png b/core/res/res/drawable-mdpi/ic_lockscreen_google_activated.png
index 32a68e0..35a3ad5 100644
--- a/core/res/res/drawable-mdpi/ic_lockscreen_google_activated.png
+++ b/core/res/res/drawable-mdpi/ic_lockscreen_google_activated.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_google_normal.png b/core/res/res/drawable-mdpi/ic_lockscreen_google_normal.png
index 2f7efcf..292b0ce 100644
--- a/core/res/res/drawable-mdpi/ic_lockscreen_google_normal.png
+++ b/core/res/res/drawable-mdpi/ic_lockscreen_google_normal.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/weather_0.png b/core/res/res/drawable-mdpi/weather_0.png
new file mode 100644
index 0000000..1553c55
--- /dev/null
+++ b/core/res/res/drawable-mdpi/weather_0.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/weather_1.png b/core/res/res/drawable-mdpi/weather_1.png
new file mode 100644
index 0000000..1553c55
--- /dev/null
+++ b/core/res/res/drawable-mdpi/weather_1.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/weather_10.png b/core/res/res/drawable-mdpi/weather_10.png
new file mode 100644
index 0000000..c44b8f7
--- /dev/null
+++ b/core/res/res/drawable-mdpi/weather_10.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/weather_11.png b/core/res/res/drawable-mdpi/weather_11.png
new file mode 100644
index 0000000..ee01b1cf
--- /dev/null
+++ b/core/res/res/drawable-mdpi/weather_11.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/weather_12.png b/core/res/res/drawable-mdpi/weather_12.png
new file mode 100644
index 0000000..ee01b1cf
--- /dev/null
+++ b/core/res/res/drawable-mdpi/weather_12.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/weather_13.png b/core/res/res/drawable-mdpi/weather_13.png
new file mode 100644
index 0000000..c922139
--- /dev/null
+++ b/core/res/res/drawable-mdpi/weather_13.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/weather_14.png b/core/res/res/drawable-mdpi/weather_14.png
new file mode 100644
index 0000000..c922139
--- /dev/null
+++ b/core/res/res/drawable-mdpi/weather_14.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/weather_15.png b/core/res/res/drawable-mdpi/weather_15.png
new file mode 100644
index 0000000..27dbc3f
--- /dev/null
+++ b/core/res/res/drawable-mdpi/weather_15.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/weather_16.png b/core/res/res/drawable-mdpi/weather_16.png
new file mode 100644
index 0000000..d575139
--- /dev/null
+++ b/core/res/res/drawable-mdpi/weather_16.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/weather_17.png b/core/res/res/drawable-mdpi/weather_17.png
new file mode 100644
index 0000000..7ac7828
--- /dev/null
+++ b/core/res/res/drawable-mdpi/weather_17.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/weather_18.png b/core/res/res/drawable-mdpi/weather_18.png
new file mode 100644
index 0000000..a1ae654
--- /dev/null
+++ b/core/res/res/drawable-mdpi/weather_18.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/weather_19.png b/core/res/res/drawable-mdpi/weather_19.png
new file mode 100644
index 0000000..b750e26
--- /dev/null
+++ b/core/res/res/drawable-mdpi/weather_19.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/weather_2.png b/core/res/res/drawable-mdpi/weather_2.png
new file mode 100644
index 0000000..1553c55
--- /dev/null
+++ b/core/res/res/drawable-mdpi/weather_2.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/weather_20.png b/core/res/res/drawable-mdpi/weather_20.png
new file mode 100644
index 0000000..8790ddd
--- /dev/null
+++ b/core/res/res/drawable-mdpi/weather_20.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/weather_21.png b/core/res/res/drawable-mdpi/weather_21.png
new file mode 100644
index 0000000..242ab7a
--- /dev/null
+++ b/core/res/res/drawable-mdpi/weather_21.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/weather_22.png b/core/res/res/drawable-mdpi/weather_22.png
new file mode 100644
index 0000000..b750e26
--- /dev/null
+++ b/core/res/res/drawable-mdpi/weather_22.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/weather_23.png b/core/res/res/drawable-mdpi/weather_23.png
new file mode 100644
index 0000000..ddefbf1
--- /dev/null
+++ b/core/res/res/drawable-mdpi/weather_23.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/weather_24.png b/core/res/res/drawable-mdpi/weather_24.png
new file mode 100644
index 0000000..ddefbf1
--- /dev/null
+++ b/core/res/res/drawable-mdpi/weather_24.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/weather_25.png b/core/res/res/drawable-mdpi/weather_25.png
new file mode 100644
index 0000000..766d094
--- /dev/null
+++ b/core/res/res/drawable-mdpi/weather_25.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/weather_26.png b/core/res/res/drawable-mdpi/weather_26.png
new file mode 100644
index 0000000..1445f9e
--- /dev/null
+++ b/core/res/res/drawable-mdpi/weather_26.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/weather_27.png b/core/res/res/drawable-mdpi/weather_27.png
new file mode 100644
index 0000000..3835d5b
--- /dev/null
+++ b/core/res/res/drawable-mdpi/weather_27.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/weather_28.png b/core/res/res/drawable-mdpi/weather_28.png
new file mode 100644
index 0000000..a362aaf
--- /dev/null
+++ b/core/res/res/drawable-mdpi/weather_28.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/weather_29.png b/core/res/res/drawable-mdpi/weather_29.png
new file mode 100644
index 0000000..3835d5b
--- /dev/null
+++ b/core/res/res/drawable-mdpi/weather_29.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/weather_3.png b/core/res/res/drawable-mdpi/weather_3.png
new file mode 100644
index 0000000..0fd0158
--- /dev/null
+++ b/core/res/res/drawable-mdpi/weather_3.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/weather_30.png b/core/res/res/drawable-mdpi/weather_30.png
new file mode 100644
index 0000000..a362aaf
--- /dev/null
+++ b/core/res/res/drawable-mdpi/weather_30.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/weather_31.png b/core/res/res/drawable-mdpi/weather_31.png
new file mode 100644
index 0000000..886b845
--- /dev/null
+++ b/core/res/res/drawable-mdpi/weather_31.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/weather_32.png b/core/res/res/drawable-mdpi/weather_32.png
new file mode 100644
index 0000000..4e6827a
--- /dev/null
+++ b/core/res/res/drawable-mdpi/weather_32.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/weather_33.png b/core/res/res/drawable-mdpi/weather_33.png
new file mode 100644
index 0000000..886b845
--- /dev/null
+++ b/core/res/res/drawable-mdpi/weather_33.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/weather_34.png b/core/res/res/drawable-mdpi/weather_34.png
new file mode 100644
index 0000000..4e6827a
--- /dev/null
+++ b/core/res/res/drawable-mdpi/weather_34.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/weather_35.png b/core/res/res/drawable-mdpi/weather_35.png
new file mode 100644
index 0000000..b8ba7c4
--- /dev/null
+++ b/core/res/res/drawable-mdpi/weather_35.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/weather_36.png b/core/res/res/drawable-mdpi/weather_36.png
new file mode 100644
index 0000000..005295a
--- /dev/null
+++ b/core/res/res/drawable-mdpi/weather_36.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/weather_37.png b/core/res/res/drawable-mdpi/weather_37.png
new file mode 100644
index 0000000..290e2a2
--- /dev/null
+++ b/core/res/res/drawable-mdpi/weather_37.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/weather_38.png b/core/res/res/drawable-mdpi/weather_38.png
new file mode 100644
index 0000000..92785f5
--- /dev/null
+++ b/core/res/res/drawable-mdpi/weather_38.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/weather_39.png b/core/res/res/drawable-mdpi/weather_39.png
new file mode 100644
index 0000000..290e2a2
--- /dev/null
+++ b/core/res/res/drawable-mdpi/weather_39.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/weather_4.png b/core/res/res/drawable-mdpi/weather_4.png
new file mode 100644
index 0000000..0fd0158
--- /dev/null
+++ b/core/res/res/drawable-mdpi/weather_4.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/weather_40.png b/core/res/res/drawable-mdpi/weather_40.png
new file mode 100644
index 0000000..25fbd20
--- /dev/null
+++ b/core/res/res/drawable-mdpi/weather_40.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/weather_41.png b/core/res/res/drawable-mdpi/weather_41.png
new file mode 100644
index 0000000..d575139
--- /dev/null
+++ b/core/res/res/drawable-mdpi/weather_41.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/weather_42.png b/core/res/res/drawable-mdpi/weather_42.png
new file mode 100644
index 0000000..f259805
--- /dev/null
+++ b/core/res/res/drawable-mdpi/weather_42.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/weather_43.png b/core/res/res/drawable-mdpi/weather_43.png
new file mode 100644
index 0000000..d575139
--- /dev/null
+++ b/core/res/res/drawable-mdpi/weather_43.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/weather_44.png b/core/res/res/drawable-mdpi/weather_44.png
new file mode 100644
index 0000000..3835d5b
--- /dev/null
+++ b/core/res/res/drawable-mdpi/weather_44.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/weather_45.png b/core/res/res/drawable-mdpi/weather_45.png
new file mode 100644
index 0000000..0fd0158
--- /dev/null
+++ b/core/res/res/drawable-mdpi/weather_45.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/weather_46.png b/core/res/res/drawable-mdpi/weather_46.png
new file mode 100644
index 0000000..c922139
--- /dev/null
+++ b/core/res/res/drawable-mdpi/weather_46.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/weather_47.png b/core/res/res/drawable-mdpi/weather_47.png
new file mode 100644
index 0000000..92785f5
--- /dev/null
+++ b/core/res/res/drawable-mdpi/weather_47.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/weather_5.png b/core/res/res/drawable-mdpi/weather_5.png
new file mode 100644
index 0000000..a1ae654
--- /dev/null
+++ b/core/res/res/drawable-mdpi/weather_5.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/weather_6.png b/core/res/res/drawable-mdpi/weather_6.png
new file mode 100644
index 0000000..a1ae654
--- /dev/null
+++ b/core/res/res/drawable-mdpi/weather_6.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/weather_7.png b/core/res/res/drawable-mdpi/weather_7.png
new file mode 100644
index 0000000..a1ae654
--- /dev/null
+++ b/core/res/res/drawable-mdpi/weather_7.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/weather_8.png b/core/res/res/drawable-mdpi/weather_8.png
new file mode 100644
index 0000000..37a339e
--- /dev/null
+++ b/core/res/res/drawable-mdpi/weather_8.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/weather_9.png b/core/res/res/drawable-mdpi/weather_9.png
new file mode 100644
index 0000000..0a9c8c3
--- /dev/null
+++ b/core/res/res/drawable-mdpi/weather_9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/weather_na.png b/core/res/res/drawable-mdpi/weather_na.png
new file mode 100644
index 0000000..48c2879
--- /dev/null
+++ b/core/res/res/drawable-mdpi/weather_na.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lock_idle_calendar.png b/core/res/res/drawable-xhdpi/ic_lock_idle_calendar.png
new file mode 100644
index 0000000..5ae7782
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_lock_idle_calendar.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lock_profile.png b/core/res/res/drawable-xhdpi/ic_lock_profile.png
new file mode 100644
index 0000000..4c9472c
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_lock_profile.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lock_reboot.png b/core/res/res/drawable-xhdpi/ic_lock_reboot.png
new file mode 100644
index 0000000..653970f
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_lock_reboot.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lock_screenshot.png b/core/res/res/drawable-xhdpi/ic_lock_screenshot.png
new file mode 100644
index 0000000..7e4c0ee
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_lock_screenshot.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_chrome_activated.png b/core/res/res/drawable-xhdpi/ic_lockscreen_chrome_activated.png
new file mode 100644
index 0000000..ea90ef5
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_lockscreen_chrome_activated.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_chrome_normal.png b/core/res/res/drawable-xhdpi/ic_lockscreen_chrome_normal.png
new file mode 100644
index 0000000..e49b962
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_lockscreen_chrome_normal.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_google_activated.png b/core/res/res/drawable-xhdpi/ic_lockscreen_google_activated.png
index d643f83..de9eec8 100644
--- a/core/res/res/drawable-xhdpi/ic_lockscreen_google_activated.png
+++ b/core/res/res/drawable-xhdpi/ic_lockscreen_google_activated.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_google_normal.png b/core/res/res/drawable-xhdpi/ic_lockscreen_google_normal.png
index 9a9bf68..f45db74 100644
--- a/core/res/res/drawable-xhdpi/ic_lockscreen_google_normal.png
+++ b/core/res/res/drawable-xhdpi/ic_lockscreen_google_normal.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/weather_0.png b/core/res/res/drawable-xhdpi/weather_0.png
new file mode 100644
index 0000000..335af4b
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/weather_0.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/weather_1.png b/core/res/res/drawable-xhdpi/weather_1.png
new file mode 100644
index 0000000..335af4b
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/weather_1.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/weather_10.png b/core/res/res/drawable-xhdpi/weather_10.png
new file mode 100644
index 0000000..9432a13
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/weather_10.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/weather_11.png b/core/res/res/drawable-xhdpi/weather_11.png
new file mode 100644
index 0000000..3f7c5ad
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/weather_11.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/weather_12.png b/core/res/res/drawable-xhdpi/weather_12.png
new file mode 100644
index 0000000..3f7c5ad
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/weather_12.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/weather_13.png b/core/res/res/drawable-xhdpi/weather_13.png
new file mode 100644
index 0000000..3f9e500
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/weather_13.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/weather_14.png b/core/res/res/drawable-xhdpi/weather_14.png
new file mode 100644
index 0000000..3f9e500
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/weather_14.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/weather_15.png b/core/res/res/drawable-xhdpi/weather_15.png
new file mode 100644
index 0000000..2ad1e46
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/weather_15.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/weather_16.png b/core/res/res/drawable-xhdpi/weather_16.png
new file mode 100644
index 0000000..4bad358
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/weather_16.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/weather_17.png b/core/res/res/drawable-xhdpi/weather_17.png
new file mode 100644
index 0000000..6fced6c
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/weather_17.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/weather_18.png b/core/res/res/drawable-xhdpi/weather_18.png
new file mode 100644
index 0000000..aae6d11
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/weather_18.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/weather_19.png b/core/res/res/drawable-xhdpi/weather_19.png
new file mode 100644
index 0000000..d8e5e82
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/weather_19.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/weather_2.png b/core/res/res/drawable-xhdpi/weather_2.png
new file mode 100644
index 0000000..335af4b
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/weather_2.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/weather_20.png b/core/res/res/drawable-xhdpi/weather_20.png
new file mode 100644
index 0000000..73cbc39
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/weather_20.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/weather_21.png b/core/res/res/drawable-xhdpi/weather_21.png
new file mode 100644
index 0000000..800f484
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/weather_21.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/weather_22.png b/core/res/res/drawable-xhdpi/weather_22.png
new file mode 100644
index 0000000..d8e5e82
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/weather_22.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/weather_23.png b/core/res/res/drawable-xhdpi/weather_23.png
new file mode 100644
index 0000000..be446c2
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/weather_23.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/weather_24.png b/core/res/res/drawable-xhdpi/weather_24.png
new file mode 100644
index 0000000..be446c2
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/weather_24.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/weather_25.png b/core/res/res/drawable-xhdpi/weather_25.png
new file mode 100644
index 0000000..63f019a
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/weather_25.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/weather_26.png b/core/res/res/drawable-xhdpi/weather_26.png
new file mode 100644
index 0000000..3eb5734
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/weather_26.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/weather_27.png b/core/res/res/drawable-xhdpi/weather_27.png
new file mode 100644
index 0000000..abf4096
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/weather_27.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/weather_28.png b/core/res/res/drawable-xhdpi/weather_28.png
new file mode 100644
index 0000000..0cbae30
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/weather_28.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/weather_29.png b/core/res/res/drawable-xhdpi/weather_29.png
new file mode 100644
index 0000000..abf4096
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/weather_29.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/weather_3.png b/core/res/res/drawable-xhdpi/weather_3.png
new file mode 100644
index 0000000..7dda34c
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/weather_3.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/weather_30.png b/core/res/res/drawable-xhdpi/weather_30.png
new file mode 100644
index 0000000..0cbae30
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/weather_30.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/weather_31.png b/core/res/res/drawable-xhdpi/weather_31.png
new file mode 100644
index 0000000..16f2d9f
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/weather_31.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/weather_32.png b/core/res/res/drawable-xhdpi/weather_32.png
new file mode 100644
index 0000000..409373d
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/weather_32.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/weather_33.png b/core/res/res/drawable-xhdpi/weather_33.png
new file mode 100644
index 0000000..16f2d9f
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/weather_33.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/weather_34.png b/core/res/res/drawable-xhdpi/weather_34.png
new file mode 100644
index 0000000..409373d
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/weather_34.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/weather_35.png b/core/res/res/drawable-xhdpi/weather_35.png
new file mode 100644
index 0000000..445b884
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/weather_35.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/weather_36.png b/core/res/res/drawable-xhdpi/weather_36.png
new file mode 100644
index 0000000..a424ad6
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/weather_36.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/weather_37.png b/core/res/res/drawable-xhdpi/weather_37.png
new file mode 100644
index 0000000..e98c8b8
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/weather_37.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/weather_38.png b/core/res/res/drawable-xhdpi/weather_38.png
new file mode 100644
index 0000000..b47249c
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/weather_38.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/weather_39.png b/core/res/res/drawable-xhdpi/weather_39.png
new file mode 100644
index 0000000..e98c8b8
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/weather_39.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/weather_4.png b/core/res/res/drawable-xhdpi/weather_4.png
new file mode 100644
index 0000000..7dda34c
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/weather_4.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/weather_40.png b/core/res/res/drawable-xhdpi/weather_40.png
new file mode 100644
index 0000000..1505fea
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/weather_40.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/weather_41.png b/core/res/res/drawable-xhdpi/weather_41.png
new file mode 100644
index 0000000..4bad358
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/weather_41.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/weather_42.png b/core/res/res/drawable-xhdpi/weather_42.png
new file mode 100644
index 0000000..196026d
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/weather_42.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/weather_43.png b/core/res/res/drawable-xhdpi/weather_43.png
new file mode 100644
index 0000000..4bad358
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/weather_43.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/weather_44.png b/core/res/res/drawable-xhdpi/weather_44.png
new file mode 100644
index 0000000..abf4096
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/weather_44.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/weather_45.png b/core/res/res/drawable-xhdpi/weather_45.png
new file mode 100644
index 0000000..7dda34c
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/weather_45.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/weather_46.png b/core/res/res/drawable-xhdpi/weather_46.png
new file mode 100644
index 0000000..3f9e500
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/weather_46.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/weather_47.png b/core/res/res/drawable-xhdpi/weather_47.png
new file mode 100644
index 0000000..b47249c
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/weather_47.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/weather_5.png b/core/res/res/drawable-xhdpi/weather_5.png
new file mode 100644
index 0000000..aae6d11
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/weather_5.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/weather_6.png b/core/res/res/drawable-xhdpi/weather_6.png
new file mode 100644
index 0000000..aae6d11
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/weather_6.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/weather_7.png b/core/res/res/drawable-xhdpi/weather_7.png
new file mode 100644
index 0000000..aae6d11
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/weather_7.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/weather_8.png b/core/res/res/drawable-xhdpi/weather_8.png
new file mode 100644
index 0000000..1a7e699
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/weather_8.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/weather_9.png b/core/res/res/drawable-xhdpi/weather_9.png
new file mode 100644
index 0000000..0da4419
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/weather_9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/weather_na.png b/core/res/res/drawable-xhdpi/weather_na.png
new file mode 100644
index 0000000..8125ce2
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/weather_na.png
Binary files differ
diff --git a/core/res/res/layout-sw600dp/keyguard_screen_status_land.xml b/core/res/res/layout-sw600dp/keyguard_screen_status_land.xml
index c6ddd1b..c1ea69c 100644
--- a/core/res/res/layout-sw600dp/keyguard_screen_status_land.xml
+++ b/core/res/res/layout-sw600dp/keyguard_screen_status_land.xml
@@ -2,6 +2,7 @@
<!--
**
** Copyright 2010, The Android Open Source Project
+** Copyright 2012, The CyanogenMod Project (Weather, Calendar)
**
** Licensed under the Apache License, Version 2.0 (the "License")
** you may not use this file except in compliance with the License.
@@ -38,12 +39,108 @@
android:visibility="gone"
/>
+ <!-- CyanogenMod Weather Panel -->
+ <RelativeLayout
+ android:id="@+id/weather_panel"
+ android:layout_height="wrap_content"
+ android:layout_width="fill_parent"
+ android:orientation="horizontal" >
+
+ <ImageView
+ android:id="@+id/weather_image"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerHorizontal="true"
+ android:layout_centerVertical="true"
+ android:paddingLeft="8dip"
+ android:paddingRight="8dip"
+ android:src="@android:drawable/ic_dialog_alert" />
+
+ <RelativeLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerVertical="true"
+ android:layout_toLeftOf="@id/weather_image"
+ android:orientation="horizontal"
+ android:padding="4dip" >
+
+ <TextView
+ android:id="@+id/weather_city"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textSize="14sp"
+ android:textStyle="bold"
+ android:layout_alignParentRight="true"
+ android:gravity="right"
+ android:singleLine="true"
+ android:ellipsize="marquee"
+ android:textColor="?android:attr/textColorPrimary"/>
+
+ <TextView
+ android:id="@+id/weather_condition"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/weather_city"
+ android:layout_alignParentRight="true"
+ android:gravity="right"
+ android:singleLine="true"
+ android:ellipsize="marquee"
+ android:textSize="12sp"
+ android:textColor="?android:attr/textColorPrimary" />
+
+ <TextView
+ android:id="@+id/update_time"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/weather_condition"
+ android:layout_alignParentRight="true"
+ android:gravity="right"
+ android:textSize="6sp"
+ android:textColor="?android:attr/textColorSecondary" />
+
+ </RelativeLayout>
+
+ <RelativeLayout
+ android:id="@+id/weather_temps_panel"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_toRightOf="@id/weather_image"
+ android:orientation="horizontal"
+ android:layout_centerVertical="true" >
+
+ <TextView
+ android:id="@+id/weather_temp"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerHorizontal="true"
+ android:textSize="20sp"
+ android:textColor="?android:attr/textColorPrimary" />
+
+ <View
+ android:id="@+id/weather_divider"
+ android:layout_below="@id/weather_temp"
+ android:layout_width="44dip"
+ android:layout_height="1dip"
+ android:background="@android:drawable/divider_horizontal_dark" />
+
+ <TextView
+ android:id="@+id/weather_low_high"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/weather_divider"
+ android:layout_centerHorizontal="true"
+ android:paddingTop="2dip"
+ android:textSize="12sp"
+ android:textColor="?android:attr/textColorPrimary" />
+
+ </RelativeLayout>
+
+ </RelativeLayout>
+
<com.android.internal.widget.DigitalClock android:id="@+id/time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginTop="8dip"
- android:layout_marginBottom="8dip"
- >
+ android:layout_marginBottom="8dip" >
<!-- Because we can't have multi-tone fonts, we render two TextViews, one on
top of the other. Hence the redundant layout... -->
@@ -120,4 +217,69 @@
android:textColor="@color/lockscreen_owner_info"
android:visibility="invisible"
/>
+
+ <!-- CyanogenMod Calendar Panel -->
+ <LinearLayout
+ android:id="@+id/calendar_panel"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:minHeight="28dip"
+ android:layout_gravity="center_horizontal"
+ android:gravity="center_vertical"
+ android:layout_marginTop="10dip"
+ android:paddingLeft="12dip"
+ android:paddingRight="12dip" >
+
+ <ImageView
+ android:layout_width="36dp"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:gravity="center"
+ android:src="@drawable/ic_lock_idle_calendar" />
+
+ <View
+ android:layout_width="1dip"
+ android:layout_height="match_parent"
+ android:paddingTop="6dip"
+ android:paddingBottom="6dip"
+ android:background="@android:drawable/divider_horizontal_dark" />
+
+ <RelativeLayout
+ android:layout_width="0dip"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:paddingTop="6dip"
+ android:paddingBottom="6dip"
+ android:paddingLeft="4dip" >
+
+ <TextView
+ android:id="@+id/calendar_event_title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:singleLine="true"
+ android:textSize="14sp"
+ android:textColor="?android:attr/textColorPrimary"
+ android:ellipsize="marquee"
+ android:fadingEdge="horizontal" />
+
+ <TextView
+ android:id="@+id/calendar_event_details"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/calendar_event_title"
+ android:layout_alignLeft="@id/calendar_event_title"
+ android:textSize="12sp"
+ android:singleLine="true"
+ android:ellipsize="marquee"
+ android:marqueeRepeatLimit="marquee_forever"
+ android:scrollHorizontally="true"
+ android:focusable="true"
+ android:focusableInTouchMode="true"
+ android:fadingEdge="horizontal"
+ android:textColor="?android:attr/textColorSecondary" />
+
+ </RelativeLayout>
+
+ </LinearLayout>
+
</LinearLayout>
diff --git a/core/res/res/layout-sw600dp/keyguard_screen_status_port.xml b/core/res/res/layout-sw600dp/keyguard_screen_status_port.xml
index 765dc95..5929529 100644
--- a/core/res/res/layout-sw600dp/keyguard_screen_status_port.xml
+++ b/core/res/res/layout-sw600dp/keyguard_screen_status_port.xml
@@ -2,6 +2,7 @@
<!--
**
** Copyright 2010, The Android Open Source Project
+** Copyright 2012, The CyanogenMod Project (Weather, Calendar)
**
** Licensed under the Apache License, Version 2.0 (the "License")
** you may not use this file except in compliance with the License.
@@ -40,11 +41,108 @@
android:visibility="gone"
/>
+ <!-- CyanogenMod Weather Panel -->
+ <RelativeLayout
+ android:id="@+id/weather_panel"
+ android:layout_height="wrap_content"
+ android:layout_width="fill_parent"
+ android:orientation="horizontal" >
+
+ <ImageView
+ android:id="@+id/weather_image"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerHorizontal="true"
+ android:layout_centerVertical="true"
+ android:paddingLeft="8dip"
+ android:paddingRight="8dip"
+ android:src="@android:drawable/ic_dialog_alert" />
+
+ <RelativeLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerVertical="true"
+ android:layout_toLeftOf="@id/weather_image"
+ android:orientation="horizontal"
+ android:padding="4dip" >
+
+ <TextView
+ android:id="@+id/weather_city"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textSize="14sp"
+ android:textStyle="bold"
+ android:layout_alignParentRight="true"
+ android:gravity="right"
+ android:singleLine="true"
+ android:ellipsize="marquee"
+ android:textColor="?android:attr/textColorPrimary"/>
+
+ <TextView
+ android:id="@+id/weather_condition"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/weather_city"
+ android:layout_alignParentRight="true"
+ android:gravity="right"
+ android:singleLine="true"
+ android:ellipsize="marquee"
+ android:textSize="12sp"
+ android:textColor="?android:attr/textColorPrimary" />
+
+ <TextView
+ android:id="@+id/update_time"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/weather_condition"
+ android:layout_alignParentRight="true"
+ android:gravity="right"
+ android:textSize="6sp"
+ android:textColor="?android:attr/textColorSecondary" />
+
+ </RelativeLayout>
+
+ <RelativeLayout
+ android:id="@+id/weather_temps_panel"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_toRightOf="@id/weather_image"
+ android:orientation="horizontal"
+ android:layout_centerVertical="true" >
+
+ <TextView
+ android:id="@+id/weather_temp"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerHorizontal="true"
+ android:textSize="20sp"
+ android:textColor="?android:attr/textColorPrimary" />
+
+ <View
+ android:id="@+id/weather_divider"
+ android:layout_below="@id/weather_temp"
+ android:layout_width="44dip"
+ android:layout_height="1dip"
+ android:background="@android:drawable/divider_horizontal_dark" />
+
+ <TextView
+ android:id="@+id/weather_low_high"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/weather_divider"
+ android:layout_centerHorizontal="true"
+ android:paddingTop="2dip"
+ android:textSize="12sp"
+ android:textColor="?android:attr/textColorPrimary" />
+
+ </RelativeLayout>
+
+ </RelativeLayout>
+
<com.android.internal.widget.DigitalClock android:id="@+id/time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginTop="8dip"
- android:layout_marginBottom="8dip">
+ android:layout_marginBottom="8dip" >
<!-- Because we can't have multi-tone fonts, we render two TextViews, one on
top of the other. Hence the redundant layout... -->
@@ -120,4 +218,68 @@
android:visibility="invisible"
android:textColor="@color/lockscreen_owner_info"
/>
+
+ <!-- CyanogenMod Calendar Panel -->
+ <LinearLayout
+ android:id="@+id/calendar_panel"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="10dip"
+ android:minHeight="28dip"
+ android:gravity="center_vertical"
+ android:paddingLeft="12dip"
+ android:paddingRight="12dip" >
+
+ <ImageView
+ android:layout_width="36dp"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:gravity="center"
+ android:src="@drawable/ic_lock_idle_calendar" />
+
+ <View
+ android:layout_width="1dip"
+ android:layout_height="match_parent"
+ android:paddingTop="6dip"
+ android:paddingBottom="6dip"
+ android:background="@android:drawable/divider_horizontal_dark" />
+
+ <RelativeLayout
+ android:layout_width="0dip"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:paddingTop="6dip"
+ android:paddingBottom="6dip"
+ android:paddingLeft="4dip" >
+
+ <TextView
+ android:id="@+id/calendar_event_title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:singleLine="true"
+ android:textSize="14sp"
+ android:textColor="?android:attr/textColorPrimary"
+ android:ellipsize="marquee"
+ android:fadingEdge="horizontal" />
+
+ <TextView
+ android:id="@+id/calendar_event_details"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/calendar_event_title"
+ android:layout_alignLeft="@id/calendar_event_title"
+ android:textSize="12sp"
+ android:singleLine="true"
+ android:ellipsize="marquee"
+ android:marqueeRepeatLimit="marquee_forever"
+ android:scrollHorizontally="true"
+ android:focusable="true"
+ android:focusableInTouchMode="true"
+ android:fadingEdge="horizontal"
+ android:textColor="?android:attr/textColorSecondary" />
+
+ </RelativeLayout>
+
+ </LinearLayout>
+
</LinearLayout>
diff --git a/core/res/res/layout/keyguard_screen_tab_unlock.xml b/core/res/res/layout/keyguard_screen_tab_unlock.xml
index 54381ee..143e24d 100644
--- a/core/res/res/layout/keyguard_screen_tab_unlock.xml
+++ b/core/res/res/layout/keyguard_screen_tab_unlock.xml
@@ -2,6 +2,7 @@
<!--
**
** Copyright 2009, The Android Open Source Project
+** Copyright 2012, The CyanogenMod Project (Weather, Calendar)
**
** Licensed under the Apache License, Version 2.0 (the "License")
** you may not use this file except in compliance with the License.
@@ -26,6 +27,7 @@
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
+ android:id="@+id/root"
android:gravity="center_horizontal">
<com.android.internal.widget.DigitalClock android:id="@+id/time"
@@ -102,6 +104,105 @@
android:drawablePadding="4dip"
/>
+ <!-- CyanogenMod Weather Panel -->
+ <RelativeLayout
+ android:id="@+id/weather_panel"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:paddingTop="4dip" >
+
+ <ImageView
+ android:id="@+id/weather_image"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerHorizontal="true"
+ android:layout_centerVertical="true"
+ android:paddingLeft="8dip"
+ android:paddingRight="8dip"
+ android:src="@android:drawable/ic_dialog_alert" />
+
+ <RelativeLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerVertical="true"
+ android:layout_toLeftOf="@id/weather_image"
+ android:orientation="horizontal"
+ android:padding="4dip" >
+
+ <TextView
+ android:id="@+id/weather_city"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textSize="14sp"
+ android:textStyle="bold"
+ android:layout_alignParentRight="true"
+ android:gravity="right"
+ android:singleLine="true"
+ android:ellipsize="marquee"
+ android:textColor="?android:attr/textColorPrimary"/>
+
+ <TextView
+ android:id="@+id/weather_condition"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/weather_city"
+ android:layout_alignParentRight="true"
+ android:gravity="right"
+ android:singleLine="true"
+ android:ellipsize="marquee"
+ android:textSize="12sp"
+ android:textColor="?android:attr/textColorPrimary" />
+
+ <TextView
+ android:id="@+id/update_time"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:gravity="right"
+ android:layout_below="@id/weather_condition"
+ android:layout_alignParentRight="true"
+ android:textSize="6sp"
+ android:textColor="?android:attr/textColorSecondary" />
+
+ </RelativeLayout>
+
+ <RelativeLayout
+ android:id="@+id/weather_temps_panel"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_toRightOf="@id/weather_image"
+ android:orientation="horizontal"
+ android:layout_centerVertical="true" >
+
+ <TextView
+ android:id="@+id/weather_temp"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerHorizontal="true"
+ android:textSize="20sp"
+ android:textColor="?android:attr/textColorPrimary" />
+
+ <View
+ android:id="@+id/weather_divider"
+ android:layout_below="@id/weather_temp"
+ android:layout_width="44dip"
+ android:layout_height="1dip"
+ android:background="@android:drawable/divider_horizontal_dark" />
+
+ <TextView
+ android:id="@+id/weather_low_high"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/weather_divider"
+ android:layout_centerHorizontal="true"
+ android:paddingTop="2dip"
+ android:textSize="12sp"
+ android:textColor="?android:attr/textColorPrimary" />
+
+ </RelativeLayout>
+
+ </RelativeLayout>
+
<Space android:layout_gravity="fill" />
<!-- emergency call button shown when sim is PUKd and tab_selector is hidden -->
@@ -123,6 +224,68 @@
android:layout_width="match_parent"
android:layout_height="302dip">
+ <!-- CyanogenMod Calendar Panel -->
+ <LinearLayout
+ android:id="@+id/calendar_panel"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:minHeight="28dip"
+ android:gravity="center_vertical"
+ android:paddingLeft="12dip"
+ android:paddingRight="12dip" >
+
+ <ImageView
+ android:layout_width="36dp"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:gravity="center"
+ android:src="@drawable/ic_lock_idle_calendar" />
+
+ <View
+ android:layout_width="1dip"
+ android:layout_height="match_parent"
+ android:paddingTop="6dip"
+ android:paddingBottom="6dip"
+ android:background="@android:drawable/divider_horizontal_dark" />
+
+ <RelativeLayout
+ android:layout_width="0dip"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:paddingTop="6dip"
+ android:paddingBottom="6dip"
+ android:paddingLeft="4dip" >
+
+ <TextView
+ android:id="@+id/calendar_event_title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:singleLine="true"
+ android:textSize="14sp"
+ android:textColor="?android:attr/textColorPrimary"
+ android:ellipsize="marquee"
+ android:fadingEdge="horizontal" />
+
+ <TextView
+ android:id="@+id/calendar_event_details"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/calendar_event_title"
+ android:layout_alignLeft="@id/calendar_event_title"
+ android:textSize="12sp"
+ android:singleLine="true"
+ android:ellipsize="marquee"
+ android:marqueeRepeatLimit="marquee_forever"
+ android:scrollHorizontally="true"
+ android:focusable="true"
+ android:focusableInTouchMode="true"
+ android:fadingEdge="horizontal"
+ android:textColor="?android:attr/textColorSecondary" />
+
+ </RelativeLayout>
+
+ </LinearLayout>
+
<com.android.internal.widget.multiwaveview.GlowPadView
android:id="@+id/unlock_widget"
android:orientation="horizontal"
@@ -189,7 +352,7 @@
layout="@layout/keyguard_transport_control"
android:layout_row="0"
android:layout_column="0"
- android:layout_rowSpan="4"
+ android:layout_rowSpan="5"
android:layout_columnSpan="1"
android:layout_gravity="fill"
android:layout_width="0dip"
diff --git a/core/res/res/layout/keyguard_screen_tab_unlock_land.xml b/core/res/res/layout/keyguard_screen_tab_unlock_land.xml
index 7ef9d8b..b151239 100644
--- a/core/res/res/layout/keyguard_screen_tab_unlock_land.xml
+++ b/core/res/res/layout/keyguard_screen_tab_unlock_land.xml
@@ -30,8 +30,9 @@
<!-- Column 0 -->
<com.android.internal.widget.DigitalClock android:id="@+id/time"
- android:layout_marginTop="80dip"
+ android:layout_marginTop="40dip"
android:layout_marginBottom="8dip"
+ android:layout_columnSpan="3"
android:layout_gravity="end">
<!-- Because we can't have multi-tone fonts, we render two TextViews, one on
@@ -64,7 +65,7 @@
<TextView
android:id="@+id/date"
- android:layout_width="0dip"
+ android:layout_columnSpan="3"
android:layout_gravity="fill_horizontal"
android:gravity="end"
android:layout_marginTop="6dip"
@@ -76,6 +77,7 @@
<TextView
android:id="@+id/alarm_status"
+ android:layout_columnSpan="3"
android:singleLine="true"
android:ellipsize="marquee"
android:textAppearance="?android:attr/textAppearanceMedium"
@@ -87,7 +89,7 @@
<TextView
android:id="@+id/status1"
- android:layout_width="0dip"
+ android:layout_columnSpan="3"
android:layout_gravity="fill_horizontal"
android:gravity="end"
android:layout_marginTop="4dip"
@@ -98,11 +100,110 @@
android:drawablePadding="4dip"
/>
+ <!-- CyanogenMod Weather Panel -->
+ <RelativeLayout
+ android:id="@+id/weather_panel"
+ android:layout_columnSpan="3"
+ android:gravity="right"
+ android:layout_gravity="fill_horizontal"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal" >
+
+ <ImageView
+ android:id="@+id/weather_image"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerVertical="true"
+ android:paddingLeft="8dip"
+ android:paddingRight="8dip"
+ android:src="@android:drawable/ic_dialog_alert" />
+
+ <RelativeLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerVertical="true"
+ android:layout_toLeftOf="@id/weather_image"
+ android:orientation="horizontal"
+ android:padding="4dip" >
+
+ <TextView
+ android:id="@+id/weather_city"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textSize="14sp"
+ android:textStyle="bold"
+ android:layout_alignParentRight="true"
+ android:gravity="right"
+ android:singleLine="true"
+ android:ellipsize="marquee"
+ android:textColor="?android:attr/textColorPrimary"/>
+
+ <TextView
+ android:id="@+id/weather_condition"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/weather_city"
+ android:layout_alignParentRight="true"
+ android:gravity="right"
+ android:singleLine="true"
+ android:ellipsize="marquee"
+ android:textSize="12sp"
+ android:textColor="?android:attr/textColorPrimary" />
+
+ <TextView
+ android:id="@+id/update_time"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/weather_condition"
+ android:layout_alignParentRight="true"
+ android:gravity="right"
+ android:textSize="6sp"
+ android:textColor="?android:attr/textColorSecondary" />
+
+ </RelativeLayout>
+
+ <RelativeLayout
+ android:id="@+id/weather_temps_panel"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_toRightOf="@id/weather_image"
+ android:orientation="horizontal"
+ android:layout_centerVertical="true" >
+
+ <TextView
+ android:id="@+id/weather_temp"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerHorizontal="true"
+ android:textSize="20sp"
+ android:textColor="?android:attr/textColorPrimary" />
+
+ <View
+ android:id="@+id/weather_divider"
+ android:layout_below="@id/weather_temp"
+ android:layout_width="44dip"
+ android:layout_height="1dip"
+ android:background="@android:drawable/divider_horizontal_dark" />
+
+ <TextView
+ android:id="@+id/weather_low_high"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/weather_divider"
+ android:layout_centerHorizontal="true"
+ android:paddingTop="2dip"
+ android:textSize="12sp"
+ android:textColor="?android:attr/textColorPrimary" />
+
+ </RelativeLayout>
+
+ </RelativeLayout>
+
<Space android:layout_gravity="fill" />
<TextView
android:id="@+id/carrier"
- android:layout_width="0dip"
+ android:layout_columnSpan="3"
android:layout_gravity="fill_horizontal"
android:layout_marginBottom="12dip"
android:gravity="end"
@@ -131,7 +232,7 @@
<!-- Column 2 -->
<com.android.internal.widget.multiwaveview.GlowPadView
android:id="@+id/unlock_widget"
- android:layout_width="302dip"
+ android:layout_width="200dip"
android:layout_height="match_parent"
android:layout_rowSpan="7"
android:gravity="start|center_vertical"
@@ -157,7 +258,7 @@
android:layout_row="0"
android:layout_column="0"
android:layout_rowSpan="5"
- android:layout_columnSpan="1"
+ android:layout_columnSpan="3"
android:layout_gravity="fill"
android:layout_width="0dip"
android:layout_height="0dip"
diff --git a/core/res/res/values/arrays.xml b/core/res/res/values/arrays.xml
index 1e966f7..0238050 100644
--- a/core/res/res/values/arrays.xml
+++ b/core/res/res/values/arrays.xml
@@ -419,4 +419,28 @@
<item>TUV</item><!-- 8 -->
<item>WXYZ</item><!-- 9 -->
</string-array>
+
+ <!-- Defines the shutdown options shown in the reboot dialog. -->
+ <array name="shutdown_reboot_options" translatable="false">
+ <item>@string/reboot_reboot</item>
+ <item>@string/reboot_recovery</item>
+ <item>@string/reboot_bootloader</item>
+ </array>
+
+ <!-- Do not translate. Defines the shutdown actions passed to the kernel.
+ The first item should be empty for regular reboot. -->
+ <string-array name="shutdown_reboot_actions" translatable="false">
+ <item></item>
+ <item>recovery</item>
+ <item>bootloader</item>
+ </string-array>
+
+ <!-- Do not translate. Defines the mapping of notification package names
+ from the actual triggering package to the user selectable package.
+ E.g. GTalk notifications come via Google Services Framework
+ Format: [triggering package]|[user package] -->
+ <string-array name="notification_light_package_mapping" translatable="false">
+ <item>com.google.android.gsf|com.google.android.talk</item>
+ </string-array>
+
</resources>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 3b7d73a..ddd3d28 100755
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -514,6 +514,12 @@
<!-- Is the notification LED intrusive? Used to decide if there should be a disable option -->
<bool name="config_intrusiveNotificationLed">false</bool>
+ <!-- Is the battery LED intrusive? Used to decide if there should be a disable option -->
+ <bool name="config_intrusiveBatteryLed">false</bool>
+
+ <!-- Does the battery LED support multiple colors? Used to decide if the user can change the colors -->
+ <bool name="config_multiColorBatteryLed">false</bool>
+
<!-- Default value for LED off time when the battery is low on charge in miliseconds -->
<integer name="config_notificationsBatteryLedOff">2875</integer>
@@ -1000,4 +1006,19 @@
provisioning on some carriers, working around a bug (7305641)
where if the preferred is used we don't try the others. -->
<bool name="config_dontPreferApn">false</bool>
+
+ <!-- Values greater or equal to 0 will enable electronbeam screen-on
+ animation with the specified delay (in milliseconds), -1 will disable the animation -->
+ <integer name="config_screenOnAnimation">-1</integer>
+
+ <!-- True will enable the electron beam screen-off animation. -->
+ <bool name="config_screenOffAnimation">true</bool>
+
+ <!-- Timeout in MS for how long you have to long-press the back key to
+ kill the foreground app. -->
+ <integer name="config_backKillTimeout">2000</integer>
+
+ <!-- Device has a h/w rotation lock switch -->
+ <bool name="config_hasRotationLockSwitch">false</bool>
+
</resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index a5dae7e..2d6d27a 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1,28 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- This file defines the base public resources exported by the
- platform, which must always exist. -->
+ platform, which must always exist. -->
<!-- ***************************************************************
- ***************************************************************
- IMPORTANT NOTE FOR ANYONE MODIFYING THIS FILE
- READ THIS BEFORE YOU MAKE ANY CHANGES
+ ***************************************************************
+ IMPORTANT NOTE FOR ANYONE MODIFYING THIS FILE
+ READ THIS BEFORE YOU MAKE ANY CHANGES
- This file defines the binary compatibility for resources. As such,
- you must be very careful when making changes here, or you will
- completely break backwards compatibility with old applications.
+ This file defines the binary compatibility for resources. As such,
+ you must be very careful when making changes here, or you will
+ completely break backwards compatibility with old applications.
- To avoid breaking compatibility, all new resources must be placed
- at the end of the list of resources of the same type. Placing a resource
- in the middle of type will cause all following resources to be
- assigned new resource numbers, breaking compatibility.
+ To avoid breaking compatibility, all new resources must be placed
+ at the end of the list of resources of the same type. Placing a resource
+ in the middle of type will cause all following resources to be
+ assigned new resource numbers, breaking compatibility.
- ***************************************************************
- *************************************************************** -->
+ ***************************************************************
+ *************************************************************** -->
<resources>
<!-- ===============================================================
- Resources for version 1 of the platform.
- =============================================================== -->
+ Resources for version 1 of the platform.
+ =============================================================== -->
<eat-comment />
<public type="attr" name="theme" id="0x01010000" />
@@ -927,15 +927,15 @@
<public type="anim" name="decelerate_interpolator" id="0x010a0006" />
<!-- ===============================================================
- Resources added in version 2 of the platform.
- =============================================================== -->
+ Resources added in version 2 of the platform.
+ =============================================================== -->
<eat-comment />
<public type="attr" name="marqueeRepeatLimit" id="0x0101021d" />
<!-- ===============================================================
- Resources added in version 3 of the platform (Cupcake).
- =============================================================== -->
+ Resources added in version 3 of the platform (Cupcake).
+ =============================================================== -->
<eat-comment />
<public type="attr" name="windowNoDisplay" id="0x0101021e" />
@@ -1015,44 +1015,44 @@
<public type="attr" name="imeExtractExitAnimation" id="0x01010269" />
<!-- The part of the UI shown by an
- {@link android.inputmethodservice.InputMethodService} that contains the
- views for interacting with the user in extraction mode. -->
+ {@link android.inputmethodservice.InputMethodService} that contains the
+ views for interacting with the user in extraction mode. -->
<public type="id" name="extractArea" id="0x0102001c" />
<!-- The part of the UI shown by an
- {@link android.inputmethodservice.InputMethodService} that contains the
- views for displaying candidates for what the user has entered. -->
+ {@link android.inputmethodservice.InputMethodService} that contains the
+ views for displaying candidates for what the user has entered. -->
<public type="id" name="candidatesArea" id="0x0102001d" />
<!-- The part of the UI shown by an
- {@link android.inputmethodservice.InputMethodService} that contains the
- views for entering text using the screen. -->
+ {@link android.inputmethodservice.InputMethodService} that contains the
+ views for entering text using the screen. -->
<public type="id" name="inputArea" id="0x0102001e" />
<!-- Context menu ID for the "Select All" menu item to select all text
- in a text view. -->
+ in a text view. -->
<public type="id" name="selectAll" id="0x0102001f" />
<!-- Context menu ID for the "Cut" menu item to copy and delete the currently
- selected (or all) text in a text view to the clipboard. -->
+ selected (or all) text in a text view to the clipboard. -->
<public type="id" name="cut" id="0x01020020" />
<!-- Context menu ID for the "Copy" menu item to copy the currently
- selected (or all) text in a text view to the clipboard. -->
+ selected (or all) text in a text view to the clipboard. -->
<public type="id" name="copy" id="0x01020021" />
<!-- Context menu ID for the "Paste" menu item to copy the current contents
- of the clipboard into the text view. -->
+ of the clipboard into the text view. -->
<public type="id" name="paste" id="0x01020022" />
<!-- Context menu ID for the "Copy URL" menu item to copy the currently
- selected URL from the text view to the clipboard. -->
+ selected URL from the text view to the clipboard. -->
<public type="id" name="copyUrl" id="0x01020023" />
<!-- Context menu ID for the "Input Method" menu item to being up the
- input method picker dialog, allowing the user to switch to another
- input method. -->
+ input method picker dialog, allowing the user to switch to another
+ input method. -->
<public type="id" name="switchInputMethod" id="0x01020024" />
<!-- View ID of the text editor inside of an extracted text layout. -->
<public type="id" name="inputExtractEditText" id="0x01020025" />
<!-- View ID of the {@link android.inputmethodservice.KeyboardView} within
- an input method's input area. -->
+ an input method's input area. -->
<public type="id" name="keyboardView" id="0x01020026" />
<!-- View ID of a {@link android.view.View} to close a popup keyboard -->
<public type="id" name="closeButton" id="0x01020027" />
@@ -1088,8 +1088,8 @@
<public type="integer" name="config_longAnimTime" id="0x010e0002" />
<!-- ===============================================================
- Resources added in version 4 of the platform (Donut).
- =============================================================== -->
+ Resources added in version 4 of the platform (Donut).
+ =============================================================== -->
<eat-comment />
<public type="attr" name="tension" id="0x0101026a" />
@@ -1145,8 +1145,8 @@
<public type="anim" name="linear_interpolator" id="0x010a000b" />
<!-- ===============================================================
- Resources added in version 5 of the platform (Eclair).
- =============================================================== -->
+ Resources added in version 5 of the platform (Eclair).
+ =============================================================== -->
<eat-comment />
<public type="attr" name="required" id="0x0101028e" />
@@ -1191,16 +1191,16 @@
<public type="style" name="TextAppearance.SearchResult.Subtitle" id="0x01030064" />
<!-- Semi-transparent background that can be used when placing a dark
- themed UI on top of some arbitrary background (such as the
- wallpaper). This darkens the background sufficiently that the UI
- can be seen. -->
+ themed UI on top of some arbitrary background (such as the
+ wallpaper). This darkens the background sufficiently that the UI
+ can be seen. -->
<public type="drawable" name="screen_background_dark_transparent" id="0x010800a9" />
<public type="drawable" name="screen_background_light_transparent" id="0x010800aa" />
<public type="drawable" name="stat_notify_sdcard_prepare" id="0x010800ab" />
<!-- ===============================================================
- Resources added in version 6 of the platform (Eclair 2.0.1).
- =============================================================== -->
+ Resources added in version 6 of the platform (Eclair 2.0.1).
+ =============================================================== -->
<eat-comment />
<public type="attr" name="quickContactBadgeStyleWindowSmall" id="0x010102ae" />
@@ -1211,8 +1211,8 @@
<public type="attr" name="quickContactBadgeStyleSmallWindowLarge" id="0x010102b3" />
<!-- ===============================================================
- Resources added in version 7 of the platform (Eclair MR1).
- =============================================================== -->
+ Resources added in version 7 of the platform (Eclair MR1).
+ =============================================================== -->
<eat-comment />
<public type="attr" name="author" id="0x010102b4" />
@@ -1220,15 +1220,15 @@
<!-- ===============================================================
- Resources added in version 8 of the platform (Eclair MR2).
- =============================================================== -->
+ Resources added in version 8 of the platform (Eclair MR2).
+ =============================================================== -->
<eat-comment />
<public type="attr" name="expandableListViewWhiteStyle" id="0x010102b6" />
<!-- ===============================================================
- Resources added in version 8 of the platform (Froyo / 2.2)
- =============================================================== -->
+ Resources added in version 8 of the platform (Froyo / 2.2)
+ =============================================================== -->
<eat-comment />
<public type="attr" name="installLocation" id="0x010102b7" />
<public type="attr" name="vmSafeMode" id="0x010102b8" />
@@ -1243,8 +1243,8 @@
<public type="anim" name="cycle_interpolator" id="0x010a000c" />
<!-- ===============================================================
- Resources added in version 9 of the platform (Gingerbread / 2.3)
- =============================================================== -->
+ Resources added in version 9 of the platform (Gingerbread / 2.3)
+ =============================================================== -->
<eat-comment />
<public type="attr" name="logo" id="0x010102be" />
<public type="attr" name="xlargeScreens" id="0x010102bf" />
@@ -1275,8 +1275,8 @@
<public type="style" name="TextAppearance.StatusBar.EventContent.Title" id="0x01030068" />
<!-- ===============================================================
- Resources added in version 11 of the platform (Honeycomb / 3.0).
- =============================================================== -->
+ Resources added in version 11 of the platform (Honeycomb / 3.0).
+ =============================================================== -->
<eat-comment />
<public type="attr" name="allContactsName" id="0x010102cc" />
@@ -1454,22 +1454,22 @@
<!-- An interpolator where the change starts backward then flings forward. -->
<public type="interpolator" name="anticipate" id="0x010c0007" />
<!-- An interpolator where the change flings forward and overshoots the last
- value then comes back. -->
+ value then comes back. -->
<public type="interpolator" name="overshoot" id="0x010c0008" />
<!-- An interpolator where the change starts backward then flings forward and
- overshoots the target value and finally goes back to the final value. -->
+ overshoots the target value and finally goes back to the final value. -->
<public type="interpolator" name="anticipate_overshoot" id="0x010c0009" />
<!-- An interpolator where the change bounces at the end. -->
<public type="interpolator" name="bounce" id="0x010c000a" />
<!-- An interpolator where the rate of change is constant. -->
<public type="interpolator" name="linear" id="0x010c000b" />
<!-- Repeats the animation for one cycle. The rate of change follows a
- sinusoidal pattern. -->
+ sinusoidal pattern. -->
<public type="interpolator" name="cycle" id="0x010c000c" />
<public type="id" name="home" id="0x0102002c" />
<!-- Context menu ID for the "Select text..." menu item to switch to text
- selection context mode in text views. -->
+ selection context mode in text views. -->
<public type="id" name="selectTextMode" id="0x0102002d" />
<public type="dimen" name="dialog_min_width_major" id="0x01050003" />
@@ -1478,23 +1478,23 @@
<public type="dimen" name="notification_large_icon_height" id="0x01050006" />
<!-- Standard content view for a {@link android.app.ListFragment}.
- If you are implementing a subclass of ListFragment with your
- own customized content, you can include this layout in that
- content to still retain all of the standard functionality of
- the base class. -->
+ If you are implementing a subclass of ListFragment with your
+ own customized content, you can include this layout in that
+ content to still retain all of the standard functionality of
+ the base class. -->
<public type="layout" name="list_content" id="0x01090014" />
<!-- A simple ListView item layout which can contain text and support (single or multiple) item selection. -->
<public type="layout" name="simple_selectable_list_item" id="0x01090015" />
<!-- A version of {@link #simple_list_item_1} that is able to change its
- background state to indicate when it is activated (that is checked by
- a ListView). -->
+ background state to indicate when it is activated (that is checked by
+ a ListView). -->
<public type="layout" name="simple_list_item_activated_1" id="0x01090016" />
<!-- A version of {@link #simple_list_item_2} that is able to change its
- background state to indicate when it is activated (that is checked by
- a ListView). -->
+ background state to indicate when it is activated (that is checked by
+ a ListView). -->
<public type="layout" name="simple_list_item_activated_2" id="0x01090017" />
<public type="drawable" name="dialog_holo_dark_frame" id="0x010800b2" />
@@ -1642,15 +1642,15 @@
<public type="mipmap" name="sym_def_app_icon" id="0x010d0000" />
<!-- ===============================================================
- Resources added in version 12 of the platform (Honeycomb MR 1 / 3.1)
- =============================================================== -->
+ Resources added in version 12 of the platform (Honeycomb MR 1 / 3.1)
+ =============================================================== -->
<eat-comment />
<public type="attr" name="textCursorDrawable" id="0x01010362" />
<public type="attr" name="resizeMode" id="0x01010363" />
<!-- ===============================================================
- Resources added in version 13 of the platform (Honeycomb MR 2 / 3.2)
- =============================================================== -->
+ Resources added in version 13 of the platform (Honeycomb MR 2 / 3.2)
+ =============================================================== -->
<eat-comment />
<public type="attr" name="requiresSmallestWidthDp" id="0x01010364" />
<public type="attr" name="compatibleWidthLimitDp" id="0x01010365" />
@@ -1699,8 +1699,8 @@
<public type="style" name="TextAppearance.Holo.DialogWindowTitle" id="0x01030117" />
<!-- ===============================================================
- Resources added in version 14 of the platform (Ice Cream Sandwich / 4.0)
- =============================================================== -->
+ Resources added in version 14 of the platform (Ice Cream Sandwich / 4.0)
+ =============================================================== -->
<eat-comment />
<public type="attr" name="state_hovered" id="0x01010367" />
<public type="attr" name="state_drag_can_accept" id="0x01010368" />
@@ -1973,8 +1973,8 @@
<public type="color" name="holo_blue_bright" id="0x0106001b" />
<!-- ===============================================================
- Resources added in version 16 of the platform (Jelly Bean)
- =============================================================== -->
+ Resources added in version 16 of the platform (Jelly Bean)
+ =============================================================== -->
<eat-comment />
<public type="attr" name="parentActivityName" id="0x010103a7" />
<public type="attr" name="isolatedProcess" id="0x010103a9" />
@@ -2028,4 +2028,45 @@
<public type="style" name="Widget.DeviceDefault.CheckedTextView" id="0x010301db" />
<public type="style" name="Widget.DeviceDefault.Light.CheckedTextView" id="0x010301dc" />
+ <java-symbol type="string" name="weather_E" />
+ <java-symbol type="string" name="weather_N" />
+ <java-symbol type="string" name="weather_NE" />
+ <java-symbol type="string" name="weather_NW" />
+ <java-symbol type="string" name="weather_S" />
+ <java-symbol type="string" name="weather_SE" />
+ <java-symbol type="string" name="weather_SW" />
+ <java-symbol type="string" name="weather_W" />
+
+ <java-symbol type="drawable" name="ic_lock_profile" />
+ <java-symbol type="drawable" name="ic_lock_reboot" />
+ <java-symbol type="drawable" name="ic_lock_screenshot" />
+ <java-symbol type="drawable" name="weather_na" />
+ <java-symbol type="id" name="calendar_event_details" />
+ <java-symbol type="id" name="calendar_event_title" />
+ <java-symbol type="id" name="calendar_panel" />
+ <java-symbol type="id" name="update_time" />
+ <java-symbol type="id" name="weather_city" />
+ <java-symbol type="id" name="weather_condition" />
+ <java-symbol type="id" name="weather_image" />
+ <java-symbol type="id" name="weather_low_high" />
+ <java-symbol type="id" name="weather_panel" />
+ <java-symbol type="id" name="weather_temp" />
+ <java-symbol type="id" name="weather_temps_panel" />
+ <java-symbol type="string" name="global_action_choose_profile" />
+ <java-symbol type="string" name="global_action_reboot" />
+ <java-symbol type="string" name="global_actions" />
+ <java-symbol type="string" name="global_action_screenshot" />
+ <java-symbol type="string" name="weather_no_data" />
+ <java-symbol type="string" name="weather_refreshing" />
+ <java-symbol type="string" name="weather_tap_to_refresh" />
+
+ <java-symbol type="array" name="notification_light_package_mapping" />
+ <java-symbol type="array" name="shutdown_reboot_actions" />
+ <java-symbol type="array" name="shutdown_reboot_options" />
+ <java-symbol type="bool" name="config_multiColorBatteryLed" />
+ <java-symbol type="string" name="reboot_progress" />
+ <java-symbol type="string" name="reboot_system" />
+ <java-symbol type="string" name="wildcardProfile" />
+ <java-symbol type="xml" name="profile_default" />
+
</resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 9932d1e..c6285c8 100755
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -68,6 +68,23 @@
could not be performed because FDN is enabled. This will be displayed in a toast. -->
<string name="mmiFdnError">Operation is restricted to fixed dialing numbers only.</string>
+ <!-- Names of default profiles. -->
+ <string name="profileNameDefault">Default</string>
+ <string name="profileNameWork">Work</string>
+ <string name="profileNameHome">Home</string>
+ <string name="profileNameSilent">Silent</string>
+ <string name="profileNameNight">Night</string>
+
+ <!-- Names of application groups. -->
+ <string name="profileGroupPhone">Phone</string>
+ <string name="profileGroupCalendar">Calendar</string>
+ <string name="profileGroupGmail">Gmail</string>
+ <string name="profileGroupEmail">Email</string>
+ <string name="profileGroupSMS">SMS</string>
+
+ <!-- Name of wildcard profile. -->
+ <string name="wildcardProfile">Other</string>
+
<!-- Displayed when a phone feature such as call barring was activated. -->
<string name="serviceEnabled">Service was enabled.</string>
<!-- Displayed in front of the list of a set of service classes
@@ -292,6 +309,33 @@
<string name="screen_lock">Screen lock</string>
<!-- Button to turn off the phone, within the Phone Options dialog -->
<string name="power_off">Power off</string>
+
+ <!-- Button to reboot the phone, within the Phone Options dialog -->
+ <string name="reboot_system" product="tablet">Reboot tablet</string>
+ <string name="reboot_system" product="default">Reboot phone</string>
+ <!-- Reboot Progress Dialog. This is shown if the user chooses to reboot the phone. -->
+
+ <!-- label for item that screenshots in phone options dialog -->
+ <string name="global_action_screenshot">Screenshot</string>
+
+ <!-- Button to reboot the phone, within the Reboot Options dialog -->
+ <string name="reboot_reboot">Reboot</string>
+ <!-- Button to reboot the phone into recovery, within the Reboot Options dialog -->
+ <string name="reboot_recovery">Recovery</string>
+ <!-- Button to reboot the phone into bootloader, within the Reboot Options dialog -->
+ <string name="reboot_bootloader">Bootloader</string>
+ <!-- Button to reboot the phone into bootmenu, within the Reboot Options dialog -->
+ <string name="reboot_bootmenu">Bootmenu</string>
+ <!-- Button to reboot the phone into fastboot, within the Reboot Options dialog -->
+ <string name="reboot_fastboot">Fastboot</string>
+ <!-- Button to reboot the phone into download, within the Reboot Options dialog -->
+ <string name="reboot_download">Download</string>
+
+ <!-- Reboot Progress Dialog. This is shown if the user chooses to reboot the phone. -->
+ <string name="reboot_progress">Rebooting\u2026</string>
+ <!-- Reboot Confirmation Dialog. When the user chooses to reboot the phone, there will be a confirmation dialog. This is the message. -->
+ <string name="reboot_confirm">Your phone will reboot.</string>
+
<!-- Spoken description for ringer silent option. [CHAR LIMIT=NONE] -->
<string name="silent_mode_silent">Ringer off</string>
<!-- Spoken description for ringer vibrate option. [CHAR LIMIT=NONE] -->
@@ -356,7 +400,6 @@
current device state, to send as an e-mail message. It will take a little
time from starting the bug report until it is ready to be sent; please be
patient.</string>
-
<!-- label for item that enables silent mode in phone options dialog -->
<string name="global_action_toggle_silent_mode">Silent mode</string>
@@ -3990,4 +4033,77 @@
<!-- Default name of the owner user [CHAR LIMIT=20] -->
<string name="owner_name" msgid="3879126011135546571">Owner</string>
+ <!-- label for item that reboots the phone in phone options dialog -->
+ <string name="global_action_reboot">Reboot</string>
+
+ <!-- label for item that opens the profile choosing dialog -->
+ <string name="global_action_choose_profile">Profile</string>
+
+ <!-- Lock screen Weather - Weather codes -->
+ <string name="weather_0">Tornado</string>
+ <string name="weather_1">Tropical Storm</string>
+ <string name="weather_2">Hurricane</string>
+ <string name="weather_3">Severe Thunderstorms</string>
+ <string name="weather_4">Thunderstorms</string>
+ <string name="weather_5">Mixed Rain and Snow</string>
+ <string name="weather_6">Mixed Rain and Sleet</string>
+ <string name="weather_7">Mixed Snow and Sleet</string>
+ <string name="weather_8">Freezing Drizzle</string>
+ <string name="weather_9">Drizzle</string>
+ <string name="weather_10">Freezing Rain</string>
+ <string name="weather_11">Showers</string>
+ <string name="weather_12">Showers</string>
+ <string name="weather_13">Snow Flurries</string>
+ <string name="weather_14">Light Snow Showers</string>
+ <string name="weather_15">Blowing Snow</string>
+ <string name="weather_16">Snow</string>
+ <string name="weather_17">Hail</string>
+ <string name="weather_18">Sleet</string>
+ <string name="weather_19">Dust</string>
+ <string name="weather_20">Foggy</string>
+ <string name="weather_21">Haze</string>
+ <string name="weather_22">Smoky</string>
+ <string name="weather_23">Blustery</string>
+ <string name="weather_24">Windy</string>
+ <string name="weather_25">Cold</string>
+ <string name="weather_26">Cloudy</string>
+ <string name="weather_27">Mostly Cloudy</string> <!-- Night -->
+ <string name="weather_28">Mostly Cloudy</string> <!-- Day -->
+ <string name="weather_29">Partly Cloudy</string> <!-- Night -->
+ <string name="weather_30">Partly Cloudy</string> <!-- Day -->
+ <string name="weather_31">Clear</string> <!-- Night -->
+ <string name="weather_32">Sunny</string>
+ <string name="weather_33">Fair</string> <!-- Night -->
+ <string name="weather_34">Fair</string> <!-- Day -->
+ <string name="weather_35">Mixed Rain and Hail</string>
+ <string name="weather_36">Hot</string>
+ <string name="weather_37">Isolated Thunderstorms</string>
+ <string name="weather_38">Scattered Thunderstorms</string>
+ <string name="weather_39">Scattered Thunderstorms</string>
+ <string name="weather_40">Scattered Showers</string>
+ <string name="weather_41">Heavy Snow</string>
+ <string name="weather_42">Scattered Snow Showers</string>
+ <string name="weather_43">Heavy Snow</string>
+ <string name="weather_44">Partly Cloudy</string>
+ <string name="weather_45">Thundershowers</string>
+ <string name="weather_46">Snow Showers</string>
+ <string name="weather_47">Isolated Thundershowers</string>
+ <!-- Forecast unavailable -->
+ <string name="weather_3200"></string>
+
+ <!-- Lock screen Weather - Wind directions -->
+ <string name="weather_N">N</string>
+ <string name="weather_NE">NE</string>
+ <string name="weather_E">E</string>
+ <string name="weather_SE">SE</string>
+ <string name="weather_S">S</string>
+ <string name="weather_SW">SW</string>
+ <string name="weather_W">W</string>
+ <string name="weather_NW">NW</string>
+
+ <!-- Lock screen Weather - error messages -->
+ <string name="weather_no_data">No data</string>
+ <string name="weather_tap_to_refresh">Tap to refresh</string>
+ <string name="weather_refreshing">Refreshing</string>
+
</resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 68a0289..aae7c1d 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1745,6 +1745,7 @@
<!-- From Settings -->
<java-symbol type="array" name="config_mobile_hotspot_provision_app" />
<java-symbol type="bool" name="config_intrusiveNotificationLed" />
+ <java-symbol type="bool" name="config_intrusiveBatteryLed" />
<java-symbol type="dimen" name="preference_fragment_padding_bottom" />
<java-symbol type="dimen" name="preference_fragment_padding_side" />
<java-symbol type="drawable" name="expander_ic_maximized" />
diff --git a/core/res/res/xml/profile_default.xml b/core/res/res/xml/profile_default.xml
new file mode 100644
index 0000000..824a73c
--- /dev/null
+++ b/core/res/res/xml/profile_default.xml
@@ -0,0 +1,267 @@
+<profiles>
+ <profile nameres="profileNameDefault">
+ <profileGroup uuid="d393035d-ea71-4f2a-bdbd-b65f6bf298f1">
+ <sound>content://settings/system/notification_sound</sound>
+ <ringer>content://settings/system/ringtone</ringer>
+ <soundMode>DEFAULT</soundMode>
+ <ringerMode>DEFAULT</ringerMode>
+ <vibrateMode>DEFAULT</vibrateMode>
+ <lightsMode>DEFAULT</lightsMode>
+ </profileGroup>
+ <profileGroup uuid="66bc93e4-775a-4ac2-9da1-752178fcdcaf">
+ <sound>content://settings/system/notification_sound</sound>
+ <ringer>content://settings/system/ringtone</ringer>
+ <soundMode>DEFAULT</soundMode>
+ <ringerMode>DEFAULT</ringerMode>
+ <vibrateMode>DEFAULT</vibrateMode>
+ <lightsMode>DEFAULT</lightsMode>
+ </profileGroup>
+ <profileGroup uuid="d2ebb02a-5205-47c5-8e39-f55823d4082a">
+ <sound>content://settings/system/notification_sound</sound>
+ <ringer>content://settings/system/ringtone</ringer>
+ <soundMode>DEFAULT</soundMode>
+ <ringerMode>DEFAULT</ringerMode>
+ <vibrateMode>DEFAULT</vibrateMode>
+ <lightsMode>DEFAULT</lightsMode>
+ </profileGroup>
+ <profileGroup uuid="db3318cd-1964-4732-b913-1f83d73a3dea">
+ <sound>content://settings/system/notification_sound</sound>
+ <ringer>content://settings/system/ringtone</ringer>
+ <soundMode>DEFAULT</soundMode>
+ <ringerMode>DEFAULT</ringerMode>
+ <vibrateMode>DEFAULT</vibrateMode>
+ <lightsMode>DEFAULT</lightsMode>
+ </profileGroup>
+ <profileGroup uuid="da4f1e2d-0e50-4789-acd4-5ca2b53a981b">
+ <sound>content://settings/system/notification_sound</sound>
+ <ringer>content://settings/system/ringtone</ringer>
+ <soundMode>DEFAULT</soundMode>
+ <ringerMode>DEFAULT</ringerMode>
+ <vibrateMode>DEFAULT</vibrateMode>
+ <lightsMode>DEFAULT</lightsMode>
+ </profileGroup>
+ <profileGroup uuid="a126d48a-aaef-47c4-baed-7f0e44aeffe5" default="true">
+ <sound>content://settings/system/notification_sound</sound>
+ <ringer>content://settings/system/ringtone</ringer>
+ <soundMode>DEFAULT</soundMode>
+ <ringerMode>DEFAULT</ringerMode>
+ <vibrateMode>DEFAULT</vibrateMode>
+ <lightsMode>DEFAULT</lightsMode>
+ </profileGroup>
+ </profile>
+ <profile nameres="profileNameWork">
+ <profileGroup uuid="d393035d-ea71-4f2a-bdbd-b65f6bf298f1">
+ <sound>content://settings/system/notification_sound</sound>
+ <ringer>content://settings/system/ringtone</ringer>
+ <soundMode>OVERRIDE</soundMode>
+ <ringerMode>OVERRIDE</ringerMode>
+ <vibrateMode>OVERRIDE</vibrateMode>
+ <lightsMode>OVERRIDE</lightsMode>
+ </profileGroup>
+ <profileGroup uuid="66bc93e4-775a-4ac2-9da1-752178fcdcaf">
+ <sound>content://settings/system/notification_sound</sound>
+ <ringer>content://settings/system/ringtone</ringer>
+ <soundMode>SUPPRESS</soundMode>
+ <ringerMode>SUPPRESS</ringerMode>
+ <vibrateMode>OVERRIDE</vibrateMode>
+ <lightsMode>OVERRIDE</lightsMode>
+ </profileGroup>
+ <profileGroup uuid="d2ebb02a-5205-47c5-8e39-f55823d4082a">
+ <sound>content://settings/system/notification_sound</sound>
+ <ringer>content://settings/system/ringtone</ringer>
+ <soundMode>SUPPRESS</soundMode>
+ <ringerMode>SUPPRESS</ringerMode>
+ <vibrateMode>OVERRIDE</vibrateMode>
+ <lightsMode>DEFAULT</lightsMode>
+ </profileGroup>
+ <profileGroup uuid="db3318cd-1964-4732-b913-1f83d73a3dea">
+ <sound>content://settings/system/notification_sound</sound>
+ <ringer>content://settings/system/ringtone</ringer>
+ <soundMode>SUPPRESS</soundMode>
+ <ringerMode>SUPPRESS</ringerMode>
+ <vibrateMode>SUPPRESS</vibrateMode>
+ <lightsMode>SUPPRESS</lightsMode>
+ </profileGroup>
+ <profileGroup uuid="da4f1e2d-0e50-4789-acd4-5ca2b53a981b">
+ <sound>content://settings/system/notification_sound</sound>
+ <ringer>content://settings/system/ringtone</ringer>
+ <soundMode>OVERRIDE</soundMode>
+ <ringerMode>OVERRIDE</ringerMode>
+ <vibrateMode>OVERRIDE</vibrateMode>
+ <lightsMode>DEFAULT</lightsMode>
+ </profileGroup>
+ <profileGroup uuid="a126d48a-aaef-47c4-baed-7f0e44aeffe5" default="true">
+ <sound>content://settings/system/notification_sound</sound>
+ <ringer>content://settings/system/ringtone</ringer>
+ <soundMode>DEFAULT</soundMode>
+ <ringerMode>DEFAULT</ringerMode>
+ <vibrateMode>DEFAULT</vibrateMode>
+ <lightsMode>DEFAULT</lightsMode>
+ </profileGroup>
+ </profile>
+ <profile nameres="profileNameHome">
+ <profileGroup uuid="d393035d-ea71-4f2a-bdbd-b65f6bf298f1">
+ <sound>content://media/external/audio/media/11</sound>
+ <ringer>content://media/external/audio/media/5</ringer>
+ <soundMode>OVERRIDE</soundMode>
+ <ringerMode>OVERRIDE</ringerMode>
+ <vibrateMode>OVERRIDE</vibrateMode>
+ <lightsMode>DEFAULT</lightsMode>
+ </profileGroup>
+ <profileGroup uuid="66bc93e4-775a-4ac2-9da1-752178fcdcaf">
+ <sound>content://settings/system/notification_sound</sound>
+ <ringer>content://settings/system/ringtone</ringer>
+ <soundMode>OVERRIDE</soundMode>
+ <ringerMode>OVERRIDE</ringerMode>
+ <vibrateMode>OVERRIDE</vibrateMode>
+ <lightsMode>OVERRIDE</lightsMode>
+ </profileGroup>
+ <profileGroup uuid="d2ebb02a-5205-47c5-8e39-f55823d4082a">
+ <sound>content://settings/system/notification_sound</sound>
+ <ringer>content://settings/system/ringtone</ringer>
+ <soundMode>OVERRIDE</soundMode>
+ <ringerMode>OVERRIDE</ringerMode>
+ <vibrateMode>OVERRIDE</vibrateMode>
+ <lightsMode>OVERRIDE</lightsMode>
+ </profileGroup>
+ <profileGroup uuid="db3318cd-1964-4732-b913-1f83d73a3dea">
+ <sound>content://settings/system/notification_sound</sound>
+ <ringer>content://settings/system/ringtone</ringer>
+ <soundMode>SUPPRESS</soundMode>
+ <ringerMode>SUPPRESS</ringerMode>
+ <vibrateMode>OVERRIDE</vibrateMode>
+ <lightsMode>DEFAULT</lightsMode>
+ </profileGroup>
+ <profileGroup uuid="da4f1e2d-0e50-4789-acd4-5ca2b53a981b">
+ <sound>content://settings/system/notification_sound</sound>
+ <ringer>content://settings/system/ringtone</ringer>
+ <soundMode>OVERRIDE</soundMode>
+ <ringerMode>OVERRIDE</ringerMode>
+ <vibrateMode>OVERRIDE</vibrateMode>
+ <lightsMode>DEFAULT</lightsMode>
+ </profileGroup>
+ <profileGroup uuid="a126d48a-aaef-47c4-baed-7f0e44aeffe5" default="true">
+ <sound>content://settings/system/notification_sound</sound>
+ <ringer>content://settings/system/ringtone</ringer>
+ <soundMode>DEFAULT</soundMode>
+ <ringerMode>DEFAULT</ringerMode>
+ <vibrateMode>DEFAULT</vibrateMode>
+ <lightsMode>DEFAULT</lightsMode>
+ </profileGroup>
+ </profile>
+ <profile nameres="profileNameSilent">
+ <profileGroup uuid="d393035d-ea71-4f2a-bdbd-b65f6bf298f1">
+ <sound>content://settings/system/notification_sound</sound>
+ <ringer>content://settings/system/ringtone</ringer>
+ <soundMode>SUPPRESS</soundMode>
+ <ringerMode>SUPPRESS</ringerMode>
+ <vibrateMode>SUPPRESS</vibrateMode>
+ <lightsMode>DEFAULT</lightsMode>
+ </profileGroup>
+ <profileGroup uuid="66bc93e4-775a-4ac2-9da1-752178fcdcaf">
+ <sound>content://settings/system/notification_sound</sound>
+ <ringer>content://settings/system/ringtone</ringer>
+ <soundMode>SUPPRESS</soundMode>
+ <ringerMode>SUPPRESS</ringerMode>
+ <vibrateMode>DEFAULT</vibrateMode>
+ <lightsMode>DEFAULT</lightsMode>
+ </profileGroup>
+ <profileGroup uuid="d2ebb02a-5205-47c5-8e39-f55823d4082a">
+ <sound>content://settings/system/notification_sound</sound>
+ <ringer>content://settings/system/ringtone</ringer>
+ <soundMode>SUPPRESS</soundMode>
+ <ringerMode>SUPPRESS</ringerMode>
+ <vibrateMode>DEFAULT</vibrateMode>
+ <lightsMode>DEFAULT</lightsMode>
+ </profileGroup>
+ <profileGroup uuid="db3318cd-1964-4732-b913-1f83d73a3dea">
+ <sound>content://settings/system/notification_sound</sound>
+ <ringer>content://settings/system/ringtone</ringer>
+ <soundMode>SUPPRESS</soundMode>
+ <ringerMode>SUPPRESS</ringerMode>
+ <vibrateMode>DEFAULT</vibrateMode>
+ <lightsMode>DEFAULT</lightsMode>
+ </profileGroup>
+ <profileGroup uuid="da4f1e2d-0e50-4789-acd4-5ca2b53a981b">
+ <sound>content://settings/system/notification_sound</sound>
+ <ringer>content://settings/system/ringtone</ringer>
+ <soundMode>SUPPRESS</soundMode>
+ <ringerMode>SUPPRESS</ringerMode>
+ <vibrateMode>DEFAULT</vibrateMode>
+ <lightsMode>DEFAULT</lightsMode>
+ </profileGroup>
+ <profileGroup uuid="a126d48a-aaef-47c4-baed-7f0e44aeffe5" default="true">
+ <sound>content://settings/system/notification_sound</sound>
+ <ringer>content://settings/system/ringtone</ringer>
+ <soundMode>SUPPRESS</soundMode>
+ <ringerMode>SUPPRESS</ringerMode>
+ <vibrateMode>DEFAULT</vibrateMode>
+ <lightsMode>DEFAULT</lightsMode>
+ </profileGroup>
+ </profile>
+ <profile nameres="profileNameNight">
+ <profileGroup uuid="d393035d-ea71-4f2a-bdbd-b65f6bf298f1">
+ <sound>content://settings/system/notification_sound</sound>
+ <ringer>content://settings/system/ringtone</ringer>
+ <soundMode>OVERRIDE</soundMode>
+ <ringerMode>OVERRIDE</ringerMode>
+ <vibrateMode>OVERRIDE</vibrateMode>
+ <lightsMode>DEFAULT</lightsMode>
+ </profileGroup>
+ <profileGroup uuid="66bc93e4-775a-4ac2-9da1-752178fcdcaf">
+ <sound>content://settings/system/notification_sound</sound>
+ <ringer>content://settings/system/ringtone</ringer>
+ <soundMode>SUPPRESS</soundMode>
+ <ringerMode>SUPPRESS</ringerMode>
+ <vibrateMode>OVERRIDE</vibrateMode>
+ <lightsMode>SUPPRESS</lightsMode>
+ </profileGroup>
+ <profileGroup uuid="d2ebb02a-5205-47c5-8e39-f55823d4082a">
+ <sound>content://settings/system/notification_sound</sound>
+ <ringer>content://settings/system/ringtone</ringer>
+ <soundMode>SUPPRESS</soundMode>
+ <ringerMode>SUPPRESS</ringerMode>
+ <vibrateMode>SUPPRESS</vibrateMode>
+ <lightsMode>DEFAULT</lightsMode>
+ </profileGroup>
+ <profileGroup uuid="db3318cd-1964-4732-b913-1f83d73a3dea">
+ <sound>content://settings/system/notification_sound</sound>
+ <ringer>content://settings/system/ringtone</ringer>
+ <soundMode>SUPPRESS</soundMode>
+ <ringerMode>SUPPRESS</ringerMode>
+ <vibrateMode>SUPPRESS</vibrateMode>
+ <lightsMode>DEFAULT</lightsMode>
+ </profileGroup>
+ <profileGroup uuid="da4f1e2d-0e50-4789-acd4-5ca2b53a981b">
+ <sound>content://settings/system/notification_sound</sound>
+ <ringer>content://settings/system/ringtone</ringer>
+ <soundMode>SUPPRESS</soundMode>
+ <ringerMode>SUPPRESS</ringerMode>
+ <vibrateMode>OVERRIDE</vibrateMode>
+ <lightsMode>SUPPRESS</lightsMode>
+ </profileGroup>
+ <profileGroup uuid="a126d48a-aaef-47c4-baed-7f0e44aeffe5" default="true">
+ <sound>content://settings/system/notification_sound</sound>
+ <ringer>content://settings/system/ringtone</ringer>
+ <soundMode>SUPPRESS</soundMode>
+ <ringerMode>DEFAULT</ringerMode>
+ <vibrateMode>DEFAULT</vibrateMode>
+ <lightsMode>DEFAULT</lightsMode>
+ </profileGroup>
+ </profile>
+ <notificationGroup nameres="profileGroupPhone" uuid="d393035d-ea71-4f2a-bdbd-b65f6bf298f1">
+ <package>com.android.phone</package>
+ </notificationGroup>
+ <notificationGroup nameres="profileGroupCalendar" uuid="66bc93e4-775a-4ac2-9da1-752178fcdcaf">
+ <package>com.android.calendar</package>
+ </notificationGroup>
+ <notificationGroup nameres="profileGroupGmail" uuid="d2ebb02a-5205-47c5-8e39-f55823d4082a">
+ <package>com.google.android.gm</package>
+ </notificationGroup>
+ <notificationGroup nameres="profileGroupEmail" uuid="db3318cd-1964-4732-b913-1f83d73a3dea">
+ <package>com.android.email</package>
+ </notificationGroup>
+ <notificationGroup nameres="profileGroupSMS" uuid="da4f1e2d-0e50-4789-acd4-5ca2b53a981b">
+ <package>com.android.mms</package>
+ </notificationGroup>
+</profiles>
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 035b282..f55a0bb 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -19,6 +19,8 @@ package android.media;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.app.PendingIntent;
+import android.app.ProfileGroup;
+import android.app.ProfileManager;
import android.bluetooth.BluetoothDevice;
import android.content.ComponentName;
import android.content.Context;
@@ -51,6 +53,7 @@ public class AudioManager {
private final boolean mUseMasterVolume;
private final boolean mUseVolumeKeySounds;
private static String TAG = "AudioManager";
+ private final ProfileManager mProfileManager;
/**
* Broadcast intent, a hint for applications that audio is about to become
@@ -422,6 +425,7 @@ public class AudioManager {
com.android.internal.R.bool.config_useMasterVolume);
mUseVolumeKeySounds = mContext.getResources().getBoolean(
com.android.internal.R.bool.config_useVolumeKeySounds);
+ mProfileManager = (ProfileManager) context.getSystemService(Context.PROFILE_SERVICE);
}
private static IAudioService getService()
@@ -1000,6 +1004,26 @@ public class AudioManager {
* current ringer mode that can be queried via {@link #getRingerMode()}.
*/
public boolean shouldVibrate(int vibrateType) {
+ String packageName = mContext.getPackageName();
+ // Don't apply profiles for "android" context, as these could
+ // come from the NotificationManager, and originate from a real package.
+ if (!packageName.equals("android")) {
+ ProfileGroup profileGroup = mProfileManager.getActiveProfileGroup(packageName);
+ if (profileGroup != null) {
+ Log.v(TAG, "shouldVibrate, group: " + profileGroup.getUuid()
+ + " mode: " + profileGroup.getVibrateMode());
+ switch (profileGroup.getVibrateMode()) {
+ case OVERRIDE :
+ return true;
+ case SUPPRESS :
+ return false;
+ case DEFAULT :
+ // Drop through
+ }
+ }
+ } else {
+ Log.v(TAG, "Not applying override for 'android' package");
+ }
IAudioService service = getService();
try {
return service.shouldVibrate(vibrateType);
diff --git a/media/java/android/media/RingtoneManager.java b/media/java/android/media/RingtoneManager.java
index 5e18bfa..b5a672a 100644
--- a/media/java/android/media/RingtoneManager.java
+++ b/media/java/android/media/RingtoneManager.java
@@ -22,6 +22,8 @@ import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.app.Activity;
import android.content.ContentUris;
+import android.app.ProfileGroup;
+import android.app.ProfileManager;
import android.content.Context;
import android.content.res.AssetFileDescriptor;
import android.database.Cursor;
@@ -55,29 +57,29 @@ public class RingtoneManager {
// Make sure these are in sync with attrs.xml:
// <attr name="ringtoneType">
-
+
/**
* Type that refers to sounds that are used for the phone ringer.
*/
public static final int TYPE_RINGTONE = 1;
-
+
/**
* Type that refers to sounds that are used for notifications.
*/
public static final int TYPE_NOTIFICATION = 2;
-
+
/**
* Type that refers to sounds that are used for the alarm.
*/
public static final int TYPE_ALARM = 4;
-
+
/**
* All types of sounds.
*/
public static final int TYPE_ALL = TYPE_RINGTONE | TYPE_NOTIFICATION | TYPE_ALARM;
// </attr>
-
+
/**
* Activity Action: Shows a ringtone picker.
* <p>
@@ -131,7 +133,7 @@ public class RingtoneManager {
*/
public static final String EXTRA_RINGTONE_EXISTING_URI =
"android.intent.extra.ringtone.EXISTING_URI";
-
+
/**
* Given to the ringtone picker as a {@link Uri}. The {@link Uri} of the
* ringtone to play when the user attempts to preview the "Default"
@@ -144,7 +146,7 @@ public class RingtoneManager {
*/
public static final String EXTRA_RINGTONE_DEFAULT_URI =
"android.intent.extra.ringtone.DEFAULT_URI";
-
+
/**
* Given to the ringtone picker as an int. Specifies which ringtone type(s) should be
* shown in the picker. One or more of {@link #TYPE_RINGTONE},
@@ -194,7 +196,7 @@ public class RingtoneManager {
"\"" + MediaStore.Audio.Media.EXTERNAL_CONTENT_URI + "\"",
MediaStore.Audio.Media.TITLE_KEY
};
-
+
/**
* The column index (in the cursor returned by {@link #getCursor()} for the
* row ID.
@@ -215,11 +217,11 @@ public class RingtoneManager {
private Activity mActivity;
private Context mContext;
-
+
private Cursor mCursor;
private int mType = TYPE_RINGTONE;
-
+
/**
* If a column (item from this list) exists in the Cursor, its value must
* be true (value of 1) for the row to be returned.
@@ -230,7 +232,7 @@ public class RingtoneManager {
private Ringtone mPreviousRingtone;
private boolean mIncludeDrm;
-
+
/**
* Constructs a RingtoneManager. This constructor is recommended as its
* constructed instance manages cursor(s).
@@ -322,7 +324,7 @@ public class RingtoneManager {
mPreviousRingtone.stop();
}
}
-
+
/**
* Returns whether DRM ringtones will be included.
*
@@ -365,7 +367,7 @@ 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 },
MediaStore.Audio.Media.DEFAULT_SORT_ORDER);
}
@@ -401,12 +403,12 @@ public class RingtoneManager {
return getUriFromCursor(mCursor);
}
-
+
private static Uri getUriFromCursor(Cursor cursor) {
return ContentUris.withAppendedId(Uri.parse(cursor.getString(URI_COLUMN_INDEX)), cursor
.getLong(ID_COLUMN_INDEX));
}
-
+
/**
* Gets the position of a {@link Uri} within this {@link RingtoneManager}.
*
@@ -527,7 +529,7 @@ public class RingtoneManager {
columns.add(MediaStore.Audio.AudioColumns.IS_ALARM);
}
}
-
+
/**
* Constructs a where clause that consists of at least one column being 1
* (true). This is used to find all matching sounds for the given sound
@@ -539,7 +541,7 @@ public class RingtoneManager {
private static String constructBooleanTrueWhereClause(List<String> columns, boolean includeDrm) {
if (columns == null) return null;
-
+
StringBuilder sb = new StringBuilder();
sb.append("(");
@@ -565,7 +567,7 @@ public class RingtoneManager {
return sb.toString();
}
-
+
private Cursor query(Uri uri,
String[] projection,
String selection,
@@ -578,7 +580,7 @@ public class RingtoneManager {
sortOrder);
}
}
-
+
/**
* Returns a {@link Ringtone} for a given sound URI.
* <p>
@@ -606,11 +608,26 @@ public class RingtoneManager {
* @see #getRingtone(Context, Uri)
*/
private static Ringtone getRingtone(final Context context, Uri ringtoneUri, int streamType) {
+ ProfileManager pm = (ProfileManager)context.getSystemService(context.PROFILE_SERVICE);
+ ProfileGroup profileGroup = pm.getActiveProfileGroup(context.getPackageName());
+
try {
- final Ringtone r = new Ringtone(context, true);
+ Ringtone r = new Ringtone(context, true);
if (streamType >= 0) {
r.setStreamType(streamType);
}
+
+ if (profileGroup != null) {
+ switch (profileGroup.getRingerMode()) {
+ case OVERRIDE :
+ r.setUri(profileGroup.getRingerOverride());
+ return r;
+ case SUPPRESS :
+ r = null;
+ return r;
+ }
+ }
+
r.setUri(ringtoneUri);
return r;
} catch (Exception ex) {
@@ -619,7 +636,7 @@ public class RingtoneManager {
return null;
}
-
+
/**
* Gets the current default sound's {@link Uri}. This will give the actual
* sound {@link Uri}, instead of using this, most clients can use
@@ -638,7 +655,7 @@ public class RingtoneManager {
final String uriString = Settings.System.getString(context.getContentResolver(), setting);
return uriString != null ? Uri.parse(uriString) : null;
}
-
+
/**
* Sets the {@link Uri} of the default sound for a given sound type.
*
@@ -655,7 +672,7 @@ public class RingtoneManager {
Settings.System.putString(context.getContentResolver(), setting,
ringtoneUri != null ? ringtoneUri.toString() : null);
}
-
+
private static String getSettingForType(int type) {
if ((type & TYPE_RINGTONE) != 0) {
return Settings.System.RINGTONE;
@@ -667,7 +684,7 @@ public class RingtoneManager {
return null;
}
}
-
+
/**
* Returns whether the given {@link Uri} is one of the default ringtones.
*
@@ -677,7 +694,7 @@ public class RingtoneManager {
public static boolean isDefault(Uri ringtoneUri) {
return getDefaultType(ringtoneUri) != -1;
}
-
+
/**
* Returns the type of a default {@link Uri}.
*
@@ -700,7 +717,7 @@ public class RingtoneManager {
return -1;
}
}
-
+
/**
* Returns the {@link Uri} for the default ringtone of a particular type.
* Rather than returning the actual ringtone's sound {@link Uri}, this will
diff --git a/policy/src/com/android/internal/policy/impl/GlobalActions.java b/policy/src/com/android/internal/policy/impl/GlobalActions.java
index d1f8ef1..6c439cc 100644
--- a/policy/src/com/android/internal/policy/impl/GlobalActions.java
+++ b/policy/src/com/android/internal/policy/impl/GlobalActions.java
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2008 The Android Open Source Project
+ * Copyright (C) 2010-2012 CyanogenMod Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -25,6 +26,8 @@ import com.android.internal.R;
import android.app.ActivityManagerNative;
import android.app.AlertDialog;
import android.app.Dialog;
+import android.app.Profile;
+import android.app.ProfileManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
@@ -71,6 +74,17 @@ import android.widget.TextView;
import java.util.ArrayList;
import java.util.List;
+import java.util.UUID;
+
+/**
+ * Needed for takeScreenshot
+ */
+import android.content.ServiceConnection;
+import android.content.ComponentName;
+import android.os.IBinder;
+import android.os.Messenger;
+import android.os.RemoteException;
+
/**
* Helper to show the global actions dialog. Each item is an {@link Action} that
@@ -85,6 +99,7 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac
private final Context mContext;
private final WindowManagerFuncs mWindowManagerFuncs;
+
private final AudioManager mAudioManager;
private final IDreamManager mDreamManager;
@@ -103,6 +118,9 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac
private boolean mHasTelephony;
private boolean mHasVibrator;
+ private Profile mChosenProfile;
+
+
/**
* @param context everything needs a context :(
*/
@@ -242,6 +260,22 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac
mWindowManagerFuncs.shutdown(true);
}
+ public boolean showDuringKeyguard() {
+ return true;
+ }
+
+ public boolean showBeforeProvisioning() {
+ return true;
+ }
+ });
+
+ // next: reboot
+ mItems.add(
+ new SinglePressAction(R.drawable.ic_lock_reboot, R.string.global_action_reboot) {
+ public void onPress() {
+ mWindowManagerFuncs.reboot();
+ }
+
public boolean onLongPress() {
mWindowManagerFuncs.rebootSafeMode(true);
return true;
@@ -256,6 +290,43 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac
}
});
+
+ // next: profile
+ mItems.add(
+ new ProfileChooseAction() {
+ public void onPress() {
+ createProfileDialog();
+ }
+
+ public boolean onLongPress() {
+ return true;
+ }
+
+ public boolean showDuringKeyguard() {
+ return false;
+ }
+
+ public boolean showBeforeProvisioning() {
+ return false;
+ }
+ });
+
+ // next: screenshot
+ mItems.add(
+ new SinglePressAction(R.drawable.ic_lock_screenshot, R.string.global_action_screenshot) {
+ public void onPress() {
+ takeScreenshot();
+ }
+
+ public boolean showDuringKeyguard() {
+ return true;
+ }
+
+ public boolean showBeforeProvisioning() {
+ return true;
+ }
+ });
+
// next: airplane mode
mItems.add(mAirplaneModeOn);
@@ -385,11 +456,141 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac
}
}
+ private void createProfileDialog(){
+ final ProfileManager profileManager = (ProfileManager)mContext.getSystemService(Context.PROFILE_SERVICE);
+
+ final Profile[] profiles = profileManager.getProfiles();
+ UUID activeProfile = profileManager.getActiveProfile().getUuid();
+ final CharSequence[] names = new CharSequence[profiles.length];
+
+ int i=0;
+ int checkedItem = 0;
+
+ for(Profile profile : profiles) {
+ if(profile.getUuid().equals(activeProfile)) {
+ checkedItem = i;
+ mChosenProfile = profile;
+ }
+ names[i++] = profile.getName();
+ }
+
+ final AlertDialog.Builder ab = new AlertDialog.Builder(mContext);
+
+ AlertDialog dialog = ab
+ .setTitle(R.string.global_action_choose_profile)
+ .setSingleChoiceItems(names, checkedItem, new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ if (which < 0)
+ return;
+ mChosenProfile = profiles[which];
+ }
+ })
+ .setPositiveButton(com.android.internal.R.string.yes,
+ new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ profileManager.setActiveProfile(mChosenProfile.getUuid());
+ }
+ })
+ .setNegativeButton(com.android.internal.R.string.no,
+ new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ dialog.cancel();
+ }
+ }).create();
+ dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG);
+ dialog.show();
+ }
+
+ /**
+ * functions needed for taking screenhots.
+ * This leverages the built in ICS screenshot functionality
+ */
+ final Object mScreenshotLock = new Object();
+ ServiceConnection mScreenshotConnection = null;
+
+ final Runnable mScreenshotTimeout = new Runnable() {
+ @Override public void run() {
+ synchronized (mScreenshotLock) {
+ if (mScreenshotConnection != null) {
+ mContext.unbindService(mScreenshotConnection);
+ mScreenshotConnection = null;
+ }
+ }
+ }
+ };
+
+ private void takeScreenshot() {
+ synchronized (mScreenshotLock) {
+ if (mScreenshotConnection != null) {
+ return;
+ }
+ ComponentName cn = new ComponentName("com.android.systemui",
+ "com.android.systemui.screenshot.TakeScreenshotService");
+ Intent intent = new Intent();
+ intent.setComponent(cn);
+ ServiceConnection conn = new ServiceConnection() {
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ synchronized (mScreenshotLock) {
+ if (mScreenshotConnection != this) {
+ return;
+ }
+ Messenger messenger = new Messenger(service);
+ Message msg = Message.obtain(null, 1);
+ final ServiceConnection myConn = this;
+ Handler h = new Handler(mHandler.getLooper()) {
+ @Override
+ public void handleMessage(Message msg) {
+ synchronized (mScreenshotLock) {
+ if (mScreenshotConnection == myConn) {
+ mContext.unbindService(mScreenshotConnection);
+ mScreenshotConnection = null;
+ mHandler.removeCallbacks(mScreenshotTimeout);
+ }
+ }
+ }
+ };
+ msg.replyTo = new Messenger(h);
+ msg.arg1 = msg.arg2 = 0;
+
+ /* remove for the time being
+ if (mStatusBar != null && mStatusBar.isVisibleLw())
+ msg.arg1 = 1;
+ if (mNavigationBar != null && mNavigationBar.isVisibleLw())
+ msg.arg2 = 1;
+ */
+
+ /* wait for the dialog box to close */
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException ie) {
+ }
+
+ /* take the screenshot */
+ try {
+ messenger.send(msg);
+ } catch (RemoteException e) {
+ }
+ }
+ }
+ @Override
+ public void onServiceDisconnected(ComponentName name) {}
+ };
+ if (mContext.bindService(intent, conn, Context.BIND_AUTO_CREATE)) {
+ mScreenshotConnection = conn;
+ mHandler.postDelayed(mScreenshotTimeout, 10000);
+ }
+ }
+ }
+
private void prepareDialog() {
refreshSilentMode();
mAirplaneModeOn.updateState(mAirplaneState);
mAdapter.notifyDataSetChanged();
mDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
+
+ mDialog.setTitle(R.string.global_actions);
+
if (SHOW_SILENT_TOGGLE) {
IntentFilter filter = new IntentFilter(AudioManager.RINGER_MODE_CHANGED_ACTION);
mContext.registerReceiver(mRingerModeReceiver, filter);
@@ -587,6 +788,41 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac
}
/**
+ * A single press action maintains no state, just responds to a press
+ * and takes an action.
+ */
+ private abstract class ProfileChooseAction implements Action {
+ private ProfileManager mProfileManager;
+
+ protected ProfileChooseAction() {
+ mProfileManager = (ProfileManager)mContext.getSystemService(Context.PROFILE_SERVICE);
+ }
+
+ public boolean isEnabled() {
+ return true;
+ }
+
+ abstract public void onPress();
+
+ public View create(Context context, View convertView, ViewGroup parent, LayoutInflater inflater) {
+ View v = (convertView != null) ?
+ convertView :
+ inflater.inflate(R.layout.global_actions_item, parent, false);
+
+ ImageView icon = (ImageView) v.findViewById(R.id.icon);
+ TextView messageView = (TextView) v.findViewById(R.id.message);
+ TextView statusView = (TextView) v.findViewById(R.id.status);
+ statusView.setVisibility(View.VISIBLE);
+ statusView.setText(mProfileManager.getActiveProfile().getName());
+
+ icon.setImageDrawable(context.getResources().getDrawable(R.drawable.ic_lock_profile));
+ messageView.setText(R.string.global_action_choose_profile);
+
+ return v;
+ }
+ }
+
+ /**
* A toggle action knows whether it is on or off, and displays an icon
* and status message accordingly.
*/
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index d9c07f8..a48e411 100755
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -324,6 +324,13 @@ public class PhoneWindowManager implements WindowManagerPolicy {
WindowState mFocusedWindow;
IApplicationToken mFocusedApp;
+ // Behavior of volume wake
+ boolean mVolumeWakeScreen;
+
+ // Behavior of volbtn music controls
+ boolean mVolBtnMusicControls;
+ boolean mIsLongPress;
+
private static final class PointerLocationInputEventReceiver extends InputEventReceiver {
private final PointerLocationView mView;
@@ -526,6 +533,12 @@ public class PhoneWindowManager implements WindowManagerPolicy {
Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR), false, this,
UserHandle.USER_ALL);
resolver.registerContentObserver(Settings.System.getUriFor(
+ Settings.System.VOLUME_WAKE_SCREEN), false, this,
+ UserHandle.USER_ALL);
+ resolver.registerContentObserver(Settings.System.getUriFor(
+ Settings.System.VOLBTN_MUSIC_CONTROLS), false, this,
+ UserHandle.USER_ALL);
+ resolver.registerContentObserver(Settings.System.getUriFor(
Settings.System.ACCELEROMETER_ROTATION), false, this,
UserHandle.USER_ALL);
resolver.registerContentObserver(Settings.System.getUriFor(
@@ -675,6 +688,53 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
}
+ /**
+ * When a volumeup-key longpress expires, skip songs based on key press
+ */
+ Runnable mVolumeUpLongPress = new Runnable() {
+ public void run() {
+ // set the long press flag to true
+ mIsLongPress = true;
+
+ // Shamelessly copied from Kmobs LockScreen controls, works for Pandora, etc...
+ sendMediaButtonEvent(KeyEvent.KEYCODE_MEDIA_NEXT);
+ };
+ };
+
+ /**
+ * When a volumedown-key longpress expires, skip songs based on key press
+ */
+ Runnable mVolumeDownLongPress = new Runnable() {
+ public void run() {
+ // set the long press flag to true
+ mIsLongPress = true;
+
+ // Shamelessly copied from Kmobs LockScreen controls, works for Pandora, etc...
+ sendMediaButtonEvent(KeyEvent.KEYCODE_MEDIA_PREVIOUS);
+ };
+ };
+
+ private void sendMediaButtonEvent(int code) {
+ long eventtime = SystemClock.uptimeMillis();
+ Intent keyIntent = new Intent(Intent.ACTION_MEDIA_BUTTON, null);
+ KeyEvent keyEvent = new KeyEvent(eventtime, eventtime, KeyEvent.ACTION_DOWN, code, 0);
+ keyIntent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent);
+ mContext.sendOrderedBroadcast(keyIntent, null);
+ keyEvent = KeyEvent.changeAction(keyEvent, KeyEvent.ACTION_UP);
+ keyIntent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent);
+ mContext.sendOrderedBroadcast(keyIntent, null);
+ }
+
+ void handleVolumeLongPress(int keycode) {
+ mHandler.postDelayed(keycode == KeyEvent.KEYCODE_VOLUME_UP ? mVolumeUpLongPress :
+ mVolumeDownLongPress, ViewConfiguration.getLongPressTimeout());
+ }
+
+ void handleVolumeLongPressAbort() {
+ mHandler.removeCallbacks(mVolumeUpLongPress);
+ mHandler.removeCallbacks(mVolumeDownLongPress);
+ }
+
private void interceptScreenshotChord() {
if (mScreenshotChordEnabled
&& mVolumeDownKeyTriggered && mPowerKeyTriggered && !mVolumeUpKeyTriggered) {
@@ -1070,11 +1130,16 @@ public class PhoneWindowManager implements WindowManagerPolicy {
Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR,
Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_DEFAULT,
UserHandle.USER_CURRENT);
+ mVolumeWakeScreen = (Settings.System.getIntForUser(resolver,
+ Settings.System.VOLUME_WAKE_SCREEN, 0, UserHandle.USER_CURRENT) == 1);
+ mVolBtnMusicControls = (Settings.System.getIntForUser(resolver,
+ Settings.System.VOLBTN_MUSIC_CONTROLS, 1, UserHandle.USER_CURRENT) == 1);
// Configure rotation lock.
int userRotation = Settings.System.getIntForUser(resolver,
Settings.System.USER_ROTATION, Surface.ROTATION_0,
UserHandle.USER_CURRENT);
+
if (mUserRotation != userRotation) {
mUserRotation = userRotation;
updateRotation = true;
@@ -3340,7 +3405,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
final boolean down = event.getAction() == KeyEvent.ACTION_DOWN;
final boolean canceled = event.isCanceled();
- final int keyCode = event.getKeyCode();
+ int keyCode = event.getKeyCode();
final boolean isInjected = (policyFlags & WindowManagerPolicy.FLAG_INJECTED) != 0;
@@ -3356,8 +3421,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
if (keyCode == KeyEvent.KEYCODE_POWER) {
policyFlags |= WindowManagerPolicy.FLAG_WAKE;
}
- final boolean isWakeKey = (policyFlags & (WindowManagerPolicy.FLAG_WAKE
- | WindowManagerPolicy.FLAG_WAKE_DROPPED)) != 0;
+ final boolean isWakeKey = (policyFlags
+ & (WindowManagerPolicy.FLAG_WAKE | WindowManagerPolicy.FLAG_WAKE_DROPPED)) != 0;
if (DEBUG_INPUT) {
Log.d(TAG, "interceptKeyTq keycode=" + keyCode
@@ -3391,7 +3456,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
if (keyguardActive) {
// If the keyguard is showing, let it wake the device when ready.
mKeyguardMediator.onWakeKeyWhenKeyguardShowingTq(keyCode);
- } else {
+ } else if ((keyCode != KeyEvent.KEYCODE_VOLUME_UP) && (keyCode != KeyEvent.KEYCODE_VOLUME_DOWN)) {
// Otherwise, wake the device ourselves.
result |= ACTION_WAKE_UP;
}
@@ -3400,6 +3465,35 @@ public class PhoneWindowManager implements WindowManagerPolicy {
// Handle special keys.
switch (keyCode) {
+ case KeyEvent.KEYCODE_ENDCALL: {
+ result &= ~ACTION_PASS_TO_USER;
+ if (down) {
+ ITelephony telephonyService = getTelephonyService();
+ boolean hungUp = false;
+ if (telephonyService != null) {
+ try {
+ hungUp = telephonyService.endCall();
+ } catch (RemoteException ex) {
+ Log.w(TAG, "ITelephony threw RemoteException", ex);
+ }
+ }
+ interceptPowerKeyDown(!isScreenOn || hungUp);
+ } else {
+ if (interceptPowerKeyUp(canceled)) {
+ if ((mEndcallBehavior
+ & Settings.System.END_BUTTON_BEHAVIOR_HOME) != 0) {
+ if (goHome()) {
+ break;
+ }
+ }
+ if ((mEndcallBehavior
+ & Settings.System.END_BUTTON_BEHAVIOR_SLEEP) != 0) {
+ result = (result & ~ACTION_WAKE_UP) | ACTION_GO_TO_SLEEP;
+ }
+ }
+ }
+ break;
+ }
case KeyEvent.KEYCODE_VOLUME_DOWN:
case KeyEvent.KEYCODE_VOLUME_UP:
case KeyEvent.KEYCODE_VOLUME_MUTE: {
@@ -3464,45 +3558,33 @@ public class PhoneWindowManager implements WindowManagerPolicy {
Log.w(TAG, "ITelephony threw RemoteException", ex);
}
}
-
- if (isMusicActive() && (result & ACTION_PASS_TO_USER) == 0) {
- // If music is playing but we decided not to pass the key to the
- // application, handle the volume change here.
- handleVolumeKey(AudioManager.STREAM_MUSIC, keyCode);
- break;
- }
}
- break;
- }
-
- case KeyEvent.KEYCODE_ENDCALL: {
- result &= ~ACTION_PASS_TO_USER;
- if (down) {
- ITelephony telephonyService = getTelephonyService();
- boolean hungUp = false;
- if (telephonyService != null) {
- try {
- hungUp = telephonyService.endCall();
- } catch (RemoteException ex) {
- Log.w(TAG, "ITelephony threw RemoteException", ex);
- }
- }
- interceptPowerKeyDown(!isScreenOn || hungUp);
- } else {
- if (interceptPowerKeyUp(canceled)) {
- if ((mEndcallBehavior
- & Settings.System.END_BUTTON_BEHAVIOR_HOME) != 0) {
- if (goHome()) {
+ if (isMusicActive() && (result & ACTION_PASS_TO_USER) == 0) {
+ if (mVolBtnMusicControls && down && (keyCode != KeyEvent.KEYCODE_VOLUME_MUTE)) {
+ mIsLongPress = false;
+ handleVolumeLongPress(keyCode);
+ break;
+ } else {
+ if (mVolBtnMusicControls && !down) {
+ handleVolumeLongPressAbort();
+ if (mIsLongPress) {
break;
}
}
- if ((mEndcallBehavior
- & Settings.System.END_BUTTON_BEHAVIOR_SLEEP) != 0) {
- result = (result & ~ACTION_WAKE_UP) | ACTION_GO_TO_SLEEP;
+ if (!isScreenOn && !mVolumeWakeScreen) {
+ handleVolumeKey(AudioManager.STREAM_MUSIC, keyCode);
}
}
}
- break;
+ if (isScreenOn || !mVolumeWakeScreen) {
+ break;
+ } else if (keyguardActive) {
+ keyCode = KeyEvent.KEYCODE_POWER;
+ mKeyguardMediator.onWakeKeyWhenKeyguardShowingTq(keyCode);
+ } else {
+ result |= ACTION_WAKE_UP;
+ break;
+ }
}
case KeyEvent.KEYCODE_POWER: {
diff --git a/policy/src/com/android/internal/policy/impl/keyguard_obsolete/KeyguardStatusViewManager.java b/policy/src/com/android/internal/policy/impl/keyguard_obsolete/KeyguardStatusViewManager.java
index b6ffde0..d1651fc 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard_obsolete/KeyguardStatusViewManager.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard_obsolete/KeyguardStatusViewManager.java
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2011 The Android Open Source Project
+ * Copyright (C) 2012 The CyanogenMod Project (Weather, Calendar)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -29,6 +30,12 @@ import libcore.util.MutableInt;
import android.content.ContentResolver;
import android.content.Context;
+import android.content.res.Resources;
+import android.location.Criteria;
+import android.location.Location;
+import android.location.LocationManager;
+import android.os.Handler;
+import android.os.Message;
import android.provider.Settings;
import android.text.TextUtils;
import android.text.format.DateFormat;
@@ -36,8 +43,27 @@ import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.RelativeLayout;
import android.widget.TextView;
+import com.android.internal.R;
+import com.android.internal.util.weather.HttpRetriever;
+import com.android.internal.util.weather.WeatherInfo;
+import com.android.internal.util.weather.WeatherXmlParser;
+import com.android.internal.util.weather.YahooPlaceFinder;
+import com.android.internal.widget.LockPatternUtils;
+import com.android.internal.widget.TransportControlView;
+
+import org.w3c.dom.Document;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Date;
+
+import libcore.util.MutableInt;
+
/***
* Manages a number of views inside of LockScreen layouts. See below for a list of widgets
*
@@ -71,6 +97,11 @@ class KeyguardStatusViewManager implements OnClickListener {
private TextView mOwnerInfoView;
private TextView mAlarmStatusView;
private TransportControlView mTransportView;
+ private RelativeLayout mWeatherPanel, mWeatherTempsPanel;
+ private TextView mWeatherCity, mWeatherCondition, mWeatherLowHigh, mWeatherTemp, mWeatherUpdateTime;
+ private ImageView mWeatherImage;
+ private LinearLayout mCalendarPanel;
+ private TextView mCalendarEventTitle, mCalendarEventDetails;
// Top-level container view for above views
private View mContainer;
@@ -185,6 +216,32 @@ class KeyguardStatusViewManager implements OnClickListener {
mEmergencyCallButtonEnabledInScreen = emergencyButtonEnabledInScreen;
mDigitalClock = (DigitalClock) findViewById(R.id.time);
+ // Weather panel
+ mWeatherPanel = (RelativeLayout) findViewById(R.id.weather_panel);
+ mWeatherCity = (TextView) findViewById(R.id.weather_city);
+ mWeatherCondition = (TextView) findViewById(R.id.weather_condition);
+ mWeatherImage = (ImageView) findViewById(R.id.weather_image);
+ mWeatherTemp = (TextView) findViewById(R.id.weather_temp);
+ mWeatherLowHigh = (TextView) findViewById(R.id.weather_low_high);
+ mWeatherUpdateTime = (TextView) findViewById(R.id.update_time);
+ mWeatherTempsPanel = (RelativeLayout) findViewById(R.id.weather_temps_panel);
+
+ // Hide Weather panel view until we know we need to show it.
+ if (mWeatherPanel != null) {
+ mWeatherPanel.setVisibility(View.GONE);
+ mWeatherPanel.setOnClickListener(this);
+ }
+
+ // Calendar panel
+ mCalendarPanel = (LinearLayout) findViewById(R.id.calendar_panel);
+ mCalendarEventTitle = (TextView) findViewById(R.id.calendar_event_title);
+ mCalendarEventDetails = (TextView) findViewById(R.id.calendar_event_details);
+
+ // Hide calendar panel view until we know we need to show it.
+ if (mCalendarPanel != null) {
+ mCalendarPanel.setVisibility(View.GONE);
+ }
+
// Hide transport control view until we know we need to show it.
if (mTransportView != null) {
mTransportView.setVisibility(View.GONE);
@@ -204,10 +261,12 @@ class KeyguardStatusViewManager implements OnClickListener {
resetStatusInfo();
refreshDate();
updateOwnerInfo();
+ refreshWeather();
+ refreshCalendar();
// Required to get Marquee to work.
final View scrollableViews[] = { mCarrierView, mDateView, mStatus1View, mOwnerInfoView,
- mAlarmStatusView };
+ mAlarmStatusView, mCalendarEventDetails, mWeatherCity, mWeatherCondition };
for (View v : scrollableViews) {
if (v != null) {
v.setSelected(true);
@@ -215,6 +274,303 @@ class KeyguardStatusViewManager implements OnClickListener {
}
}
+ /*
+ * CyanogenMod Lock screen Weather related functionality
+ */
+ private static final String URL_YAHOO_API_WEATHER = "http://weather.yahooapis.com/forecastrss?w=%s&u=";
+ private static WeatherInfo mWeatherInfo = new WeatherInfo();
+ private static final int QUERY_WEATHER = 0;
+ private static final int UPDATE_WEATHER = 1;
+
+ private Handler mHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case QUERY_WEATHER:
+ Thread queryWeather = new Thread(new Runnable() {
+ @Override
+ public void run() {
+ LocationManager locationManager = (LocationManager) getContext().
+ getSystemService(Context.LOCATION_SERVICE);
+ final ContentResolver resolver = getContext().getContentResolver();
+ boolean useCustomLoc = Settings.System.getInt(resolver,
+ Settings.System.WEATHER_USE_CUSTOM_LOCATION, 0) == 1;
+ String customLoc = Settings.System.getString(resolver,
+ Settings.System.WEATHER_CUSTOM_LOCATION);
+ String woeid = null;
+
+ // custom location
+ if (customLoc != null && useCustomLoc) {
+ try {
+ woeid = YahooPlaceFinder.GeoCode(getContext().getApplicationContext(), customLoc);
+ if (DEBUG)
+ Log.d(TAG, "Yahoo location code for " + customLoc + " is " + woeid);
+ } catch (Exception e) {
+ Log.e(TAG, "ERROR: Could not get Location code");
+ e.printStackTrace();
+ }
+ // network location
+ } else {
+ Criteria crit = new Criteria();
+ crit.setAccuracy(Criteria.ACCURACY_COARSE);
+ String bestProvider = locationManager.getBestProvider(crit, true);
+ Location loc = null;
+ if (bestProvider != null) {
+ loc = locationManager.getLastKnownLocation(bestProvider);
+ } else {
+ loc = locationManager.getLastKnownLocation(LocationManager.PASSIVE_PROVIDER);
+ }
+ try {
+ woeid = YahooPlaceFinder.reverseGeoCode(getContext(), loc.getLatitude(),
+ loc.getLongitude());
+ if (DEBUG)
+ Log.d(TAG, "Yahoo location code for current geolocation is " + woeid);
+ } catch (Exception e) {
+ Log.e(TAG, "ERROR: Could not get Location code");
+ e.printStackTrace();
+ }
+ }
+ Message msg = Message.obtain();
+ msg.what = UPDATE_WEATHER;
+ msg.obj = woeid;
+ mHandler.sendMessage(msg);
+ }
+ });
+ queryWeather.setPriority(Thread.MIN_PRIORITY);
+ queryWeather.start();
+ break;
+ case UPDATE_WEATHER:
+ String woeid = (String) msg.obj;
+ if (woeid != null) {
+ if (DEBUG) {
+ Log.d(TAG, "Location code is " + woeid);
+ }
+ WeatherInfo w = null;
+ try {
+ w = parseXml(getDocument(woeid));
+ } catch (Exception e) {
+ }
+ if (w == null) {
+ setNoWeatherData();
+ } else {
+ setWeatherData(w);
+ mWeatherInfo = w;
+ }
+ } else {
+ if (mWeatherInfo.temp.equals(WeatherInfo.NODATA)) {
+ setNoWeatherData();
+ } else {
+ setWeatherData(mWeatherInfo);
+ }
+ }
+ break;
+ }
+ }
+ };
+
+ /**
+ * Reload the weather forecast
+ */
+ private void refreshWeather() {
+ final ContentResolver resolver = getContext().getContentResolver();
+ boolean showWeather = Settings.System.getInt(resolver,Settings.System.LOCKSCREEN_WEATHER, 0) == 1;
+
+ if (showWeather) {
+ final long interval = Settings.System.getLong(resolver,
+ Settings.System.WEATHER_UPDATE_INTERVAL, 60); // Default to hourly
+ boolean manualSync = (interval == 0);
+ if (!manualSync && (((System.currentTimeMillis() - mWeatherInfo.last_sync) / 60000) >= interval)) {
+ mHandler.sendEmptyMessage(QUERY_WEATHER);
+ } else if (manualSync && mWeatherInfo.last_sync == 0) {
+ setNoWeatherData();
+ } else {
+ setWeatherData(mWeatherInfo);
+ }
+ } else {
+ // Hide the Weather panel view
+ if (mWeatherPanel != null) {
+ mWeatherPanel.setVisibility(View.GONE);
+ }
+ }
+ }
+
+ /**
+ * Display the weather information
+ * @param w
+ */
+ private void setWeatherData(WeatherInfo w) {
+ final ContentResolver resolver = getContext().getContentResolver();
+ final Resources res = getContext().getResources();
+ boolean showLocation = Settings.System.getInt(resolver,
+ Settings.System.WEATHER_SHOW_LOCATION, 1) == 1;
+ boolean showTimestamp = Settings.System.getInt(resolver,
+ Settings.System.WEATHER_SHOW_TIMESTAMP, 1) == 1;
+ boolean invertLowhigh = Settings.System.getInt(resolver,
+ Settings.System.WEATHER_INVERT_LOWHIGH, 0) == 1;
+
+ if (mWeatherPanel != null) {
+ if (mWeatherImage != null) {
+ String conditionCode = w.condition_code;
+ String condition_filename = "weather_" + conditionCode;
+ int resID = res.getIdentifier(condition_filename, "drawable",
+ getContext().getPackageName());
+
+ if (DEBUG)
+ Log.d("Weather", "Condition:" + conditionCode + " ID:" + resID);
+
+ if (resID != 0) {
+ mWeatherImage.setImageDrawable(res.getDrawable(resID));
+ } else {
+ mWeatherImage.setImageResource(R.drawable.weather_na);
+ }
+ }
+ if (mWeatherCity != null) {
+ mWeatherCity.setText(w.city);
+ mWeatherCity.setVisibility(showLocation ? View.VISIBLE : View.GONE);
+ }
+ if (mWeatherCondition != null) {
+ mWeatherCondition.setText(w.condition);
+ mWeatherCondition.setVisibility(View.VISIBLE);
+ }
+ if (mWeatherUpdateTime != null) {
+ Date lastTime = new Date(mWeatherInfo.last_sync);
+ String date = DateFormat.getDateFormat(getContext()).format(lastTime);
+ String time = DateFormat.getTimeFormat(getContext()).format(lastTime);
+ mWeatherUpdateTime.setText(date + " " + time);
+ mWeatherUpdateTime.setVisibility(showTimestamp ? View.VISIBLE : View.GONE);
+ }
+ if (mWeatherTempsPanel != null && mWeatherTemp != null && mWeatherLowHigh != null) {
+ mWeatherTemp.setText(w.temp);
+ mWeatherLowHigh.setText(invertLowhigh ? w.high + " | " + w.low : w.low + " | " + w.high);
+ mWeatherTempsPanel.setVisibility(View.VISIBLE);
+ }
+
+ // Show the Weather panel view
+ mWeatherPanel.setVisibility(View.VISIBLE);
+ }
+ }
+
+ /**
+ * There is no data to display, display 'empty' fields and the
+ * 'Tap to reload' message
+ */
+ private void setNoWeatherData() {
+
+ if (mWeatherPanel != null) {
+ if (mWeatherImage != null) {
+ mWeatherImage.setImageResource(R.drawable.weather_na);
+ }
+ if (mWeatherCity != null) {
+ mWeatherCity.setText(R.string.weather_no_data);
+ mWeatherCity.setVisibility(View.VISIBLE);
+ }
+ if (mWeatherCondition != null) {
+ mWeatherCondition.setText(R.string.weather_tap_to_refresh);
+ }
+ if (mWeatherUpdateTime != null) {
+ mWeatherUpdateTime.setVisibility(View.GONE);
+ }
+ if (mWeatherTempsPanel != null ) {
+ mWeatherTempsPanel.setVisibility(View.GONE);
+ }
+
+ // Show the Weather panel view
+ mWeatherPanel.setVisibility(View.VISIBLE);
+ }
+ }
+
+ /**
+ * Get the weather forecast XML document for a specific location
+ * @param woeid
+ * @return
+ */
+ private Document getDocument(String woeid) {
+ try {
+ boolean celcius = Settings.System.getInt(getContext().getContentResolver(),
+ Settings.System.WEATHER_USE_METRIC, 1) == 1;
+ String urlWithDegreeUnit;
+
+ if (celcius) {
+ urlWithDegreeUnit = URL_YAHOO_API_WEATHER + "c";
+ } else {
+ urlWithDegreeUnit = URL_YAHOO_API_WEATHER + "f";
+ }
+
+ return new HttpRetriever().getDocumentFromURL(String.format(urlWithDegreeUnit, woeid));
+ } catch (IOException e) {
+ Log.e(TAG, "Error querying Yahoo weather");
+ }
+
+ return null;
+ }
+
+ /**
+ * Parse the weather XML document
+ * @param wDoc
+ * @return
+ */
+ private WeatherInfo parseXml(Document wDoc) {
+ try {
+ return new WeatherXmlParser(getContext()).parseWeatherResponse(wDoc);
+ } catch (Exception e) {
+ Log.e(TAG, "Error parsing Yahoo weather XML document");
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ /*
+ * CyanogenMod Lock screen Calendar related functionality
+ */
+
+ private void refreshCalendar() {
+ if (mCalendarPanel != null) {
+ final ContentResolver resolver = getContext().getContentResolver();
+ String[] nextCalendar = null;
+ boolean visible = false; // Assume we are not showing the view
+
+ // Load the settings
+ boolean lockCalendar = (Settings.System.getInt(resolver,
+ Settings.System.LOCKSCREEN_CALENDAR, 0) == 1);
+ String[] calendars = parseStoredValue(Settings.System.getString(
+ resolver, Settings.System.LOCKSCREEN_CALENDARS));
+ boolean lockCalendarRemindersOnly = (Settings.System.getInt(resolver,
+ Settings.System.LOCKSCREEN_CALENDAR_REMINDERS_ONLY, 0) == 1);
+ long lockCalendarLookahead = Settings.System.getLong(resolver,
+ Settings.System.LOCKSCREEN_CALENDAR_LOOKAHEAD, 10800000);
+
+ if (lockCalendar) {
+ nextCalendar = mLockPatternUtils.getNextCalendarAlarm(lockCalendarLookahead,
+ calendars, lockCalendarRemindersOnly);
+ if (nextCalendar[0] != null && mCalendarEventTitle != null) {
+ mCalendarEventTitle.setText(nextCalendar[0].toString());
+ if (nextCalendar[1] != null && mCalendarEventDetails != null) {
+ mCalendarEventDetails.setText(nextCalendar[1]);
+ }
+ visible = true;
+ }
+ }
+
+ mCalendarPanel.setVisibility(visible ? View.VISIBLE : View.GONE);
+ }
+ }
+
+ /**
+ * Split the MultiSelectListPreference string based on a separator of ',' and
+ * stripping off the start [ and the end ]
+ * @param val
+ * @return
+ */
+ private static String[] parseStoredValue(String val) {
+ if (val == null || val.isEmpty())
+ return null;
+ else {
+ // Strip off the start [ and the end ] before splitting
+ val = val.substring(1, val.length() -1);
+ return (val.split(","));
+ }
+ }
+
private boolean inWidgetMode() {
return mTransportView != null && mTransportView.getVisibility() == View.VISIBLE;
}
@@ -657,6 +1013,16 @@ class KeyguardStatusViewManager implements OnClickListener {
public void onClick(View v) {
if (v == mEmergencyCallButton) {
mCallback.takeEmergencyCallAction();
+ } else if (v == mWeatherPanel) {
+ // Indicate we are refreshing
+ if (mWeatherCondition != null) {
+ mWeatherCondition.setText(R.string.weather_refreshing);
+ }
+
+ mCallback.pokeWakelock();
+ if (!mHandler.hasMessages(QUERY_WEATHER)) {
+ mHandler.sendEmptyMessage(QUERY_WEATHER);
+ }
}
}
diff --git a/policy/src/com/android/internal/policy/impl/keyguard_obsolete/KeyguardViewMediator.java b/policy/src/com/android/internal/policy/impl/keyguard_obsolete/KeyguardViewMediator.java
index 3de1428..bf43199 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard_obsolete/KeyguardViewMediator.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard_obsolete/KeyguardViewMediator.java
@@ -25,6 +25,8 @@ import com.android.internal.widget.LockPatternUtils;
import android.app.ActivityManagerNative;
import android.app.AlarmManager;
import android.app.PendingIntent;
+import android.app.Profile;
+import android.app.ProfileManager;
import android.app.StatusBarManager;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
@@ -248,6 +250,8 @@ public class KeyguardViewMediator implements KeyguardViewCallback {
private int mUnlockSoundId;
private int mLockSoundStreamId;
+ private ProfileManager mProfileManager;
+
/**
* The volume applied to the lock/unlock sounds.
*/
@@ -369,6 +373,7 @@ public class KeyguardViewMediator implements KeyguardViewCallback {
mWakeAndHandOff.setReferenceCounted(false);
mContext.registerReceiver(mBroadcastReceiver, new IntentFilter(DELAYED_KEYGUARD_ACTION));
+ mProfileManager = (ProfileManager) context.getSystemService(Context.PROFILE_SERVICE);
mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
@@ -434,11 +439,21 @@ public class KeyguardViewMediator implements KeyguardViewCallback {
mScreenOn = false;
if (DEBUG) Log.d(TAG, "onScreenTurnedOff(" + why + ")");
- // Lock immediately based on setting if secure (user has a pin/pattern/password).
- // This also "locks" the device when not secure to provide easy access to the
- // camera while preventing unwanted input.
- final boolean lockImmediately =
- mLockPatternUtils.getPowerButtonInstantlyLocks() || !mLockPatternUtils.isSecure();
+ // Prepare for handling Lock/Slide lock delay and timeout
+ boolean lockImmediately = false;
+ final ContentResolver cr = mContext.getContentResolver();
+ boolean separateSlideLockTimeoutEnabled = Settings.System.getInt(cr,
+ Settings.System.SCREEN_LOCK_SLIDE_DELAY_TOGGLE, 0) == 1;
+ if (mLockPatternUtils.isSecure()) {
+ // Lock immediately based on setting if secure (user has a pin/pattern/password)
+ // This is retained as-is to ensue AOSP security integrity is maintained
+ lockImmediately = mLockPatternUtils.getPowerButtonInstantlyLocks();
+ } else {
+ // Unless a separate slide lock timeout is enabled, this "locks" the device when
+ // not secure to provide easy access to the camera while preventing unwanted input
+ lockImmediately = separateSlideLockTimeoutEnabled ? false
+ : mLockPatternUtils.getPowerButtonInstantlyLocks();
+ }
if (mExitSecureCallback != null) {
if (DEBUG) Log.d(TAG, "pending exit secure callback cancelled");
@@ -457,7 +472,6 @@ public class KeyguardViewMediator implements KeyguardViewCallback {
// to enable it a little bit later (i.e, give the user a chance
// to turn the screen back on within a certain window without
// having to unlock the screen)
- final ContentResolver cr = mContext.getContentResolver();
// From DisplaySettings
long displayTimeout = Settings.System.getInt(cr, SCREEN_OFF_TIMEOUT,
@@ -468,17 +482,33 @@ public class KeyguardViewMediator implements KeyguardViewCallback {
Settings.Secure.LOCK_SCREEN_LOCK_AFTER_TIMEOUT,
KEYGUARD_LOCK_AFTER_DELAY_DEFAULT);
+ // From CyanogenMod specific Settings
+ int slideLockTimeoutDelay = (why == WindowManagerPolicy.OFF_BECAUSE_OF_TIMEOUT ? Settings.System
+ .getInt(cr, Settings.System.SCREEN_LOCK_SLIDE_TIMEOUT_DELAY,
+ KEYGUARD_LOCK_AFTER_DELAY_DEFAULT) : Settings.System.getInt(cr,
+ Settings.System.SCREEN_LOCK_SLIDE_SCREENOFF_DELAY, 0));
+
// From DevicePolicyAdmin
final long policyTimeout = mLockPatternUtils.getDevicePolicyManager()
.getMaximumTimeToLock(null);
+ if (DEBUG) Log.d(TAG, "Security lock screen timeout delay is " + lockAfterTimeout
+ + " ms; slide lock screen timeout delay is "
+ + slideLockTimeoutDelay
+ + " ms; Separate slide lock delay settings considered: "
+ + separateSlideLockTimeoutEnabled
+ + "; Policy timeout is "
+ + policyTimeout
+ + " ms");
+
long timeout;
if (policyTimeout > 0) {
// policy in effect. Make sure we don't go beyond policy limit.
displayTimeout = Math.max(displayTimeout, 0); // ignore negative values
timeout = Math.min(policyTimeout - displayTimeout, lockAfterTimeout);
} else {
- timeout = lockAfterTimeout;
+ // Not sure lockAfterTimeout is needed any more but keeping it for AOSP compatibility
+ timeout = separateSlideLockTimeoutEnabled ? slideLockTimeoutDelay : lockAfterTimeout;
}
if (timeout <= 0) {
@@ -708,6 +738,13 @@ public class KeyguardViewMediator implements KeyguardViewCallback {
return;
}
+ // if the current profile has disabled us, don't show
+ if (!lockedOrMissing
+ && mProfileManager.getActiveProfile().getScreenLockMode() == Profile.LockMode.DISABLE) {
+ if (DEBUG) Log.d(TAG, "doKeyguard: not showing because of profile override");
+ return;
+ }
+
if (DEBUG) Log.d(TAG, "doKeyguard: showing the lock screen");
showLocked();
}
diff --git a/services/java/com/android/server/BatteryService.java b/services/java/com/android/server/BatteryService.java
index dbffa97..537d69f 100644
--- a/services/java/com/android/server/BatteryService.java
+++ b/services/java/com/android/server/BatteryService.java
@@ -24,6 +24,9 @@ import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.database.ContentObserver;
+import android.graphics.Color;
import android.os.BatteryManager;
import android.os.Binder;
import android.os.FileUtils;
@@ -44,7 +47,7 @@ import java.io.FileDescriptor;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
-
+import java.util.Calendar;
/**
* <p>BatteryService monitors the charging status, and charge level of the device
@@ -140,10 +143,21 @@ public final class BatteryService extends Binder {
private boolean mUpdatesStopped;
private Led mLed;
+ private boolean mLightEnabled;
+ private boolean mLedPulseEnabled;
+ private int mBatteryLowARGB;
+ private int mBatteryMediumARGB;
+ private int mBatteryFullARGB;
+ private boolean mMultiColorLed;
private boolean mSentLowBatteryBroadcast = false;
private native void native_update();
+ // Quiet hours support
+ private boolean mQuietHoursEnabled = false;
+ private int mQuietHoursStart = 0;
+ private int mQuietHoursEnd = 0;
+ private boolean mQuietHoursDim = true;
public BatteryService(Context context, LightsService lights) {
mContext = context;
@@ -168,6 +182,9 @@ public final class BatteryService extends Binder {
"DEVPATH=/devices/virtual/switch/invalid_charger");
}
+ SettingsObserver observer = new SettingsObserver(new Handler());
+ observer.observe();
+
// set initial status
synchronized (mLock) {
updateLocked();
@@ -672,6 +689,10 @@ public final class BatteryService extends Binder {
}
};
+ private synchronized void updateLedPulse() {
+ mLed.updateLightsLocked();
+ }
+
private final class Led {
private final LightsService.Light mBatteryLight;
@@ -684,12 +705,17 @@ public final class BatteryService extends Binder {
public Led(Context context, LightsService lights) {
mBatteryLight = lights.getLight(LightsService.LIGHT_ID_BATTERY);
- mBatteryLowARGB = context.getResources().getInteger(
+ mBatteryLowARGB = mContext.getResources().getInteger(
com.android.internal.R.integer.config_notificationsBatteryLowARGB);
- mBatteryMediumARGB = context.getResources().getInteger(
+ mBatteryMediumARGB = mContext.getResources().getInteger(
com.android.internal.R.integer.config_notificationsBatteryMediumARGB);
- mBatteryFullARGB = context.getResources().getInteger(
+ mBatteryFullARGB = mContext.getResources().getInteger(
com.android.internal.R.integer.config_notificationsBatteryFullARGB);
+
+ // Does the Device support changing battery LED colors?
+ mMultiColorLed = context.getResources().getBoolean(
+ com.android.internal.R.bool.config_multiColorBatteryLed);
+
mBatteryLedOn = context.getResources().getInteger(
com.android.internal.R.integer.config_notificationsBatteryLedOn);
mBatteryLedOff = context.getResources().getInteger(
@@ -702,28 +728,143 @@ public final class BatteryService extends Binder {
public void updateLightsLocked() {
final int level = mBatteryLevel;
final int status = mBatteryStatus;
- if (level < mLowBatteryWarningLevel) {
+
+ if (!mLightEnabled) {
+ // No lights if explicitly disabled
+ mBatteryLight.turnOff();
+ } else if (inQuietHours() && mQuietHoursDim) {
+ if (mLedPulseEnabled && level < mLowBatteryWarningLevel &&
+ status != BatteryManager.BATTERY_STATUS_CHARGING) {
+ // The battery is low, the device is not charging and the low battery pulse
+ // is enabled - ignore Quiet Hours
+ mBatteryLight.setFlashing(mBatteryLowARGB, LightsService.LIGHT_FLASH_TIMED,
+ mBatteryLedOn, mBatteryLedOff);
+ } else {
+ // No lights if in Quiet Hours and battery not low
+ mBatteryLight.turnOff();
+ }
+ } else if (level < mLowBatteryWarningLevel) {
if (status == BatteryManager.BATTERY_STATUS_CHARGING) {
- // Solid red when battery is charging
+ // Battery is charging and low
mBatteryLight.setColor(mBatteryLowARGB);
- } else {
- // Flash red when battery is low and not charging
+ } else if (mLedPulseEnabled) {
+ // Battery is low and not charging
mBatteryLight.setFlashing(mBatteryLowARGB, LightsService.LIGHT_FLASH_TIMED,
mBatteryLedOn, mBatteryLedOff);
+ } else {
+ // "Pulse low battery light" is disabled, no lights.
+ mBatteryLight.turnOff();
}
} else if (status == BatteryManager.BATTERY_STATUS_CHARGING
- || status == BatteryManager.BATTERY_STATUS_FULL) {
+ || status == BatteryManager.BATTERY_STATUS_FULL) {
if (status == BatteryManager.BATTERY_STATUS_FULL || level >= 90) {
- // Solid green when full or charging and nearly full
+ // Battery is full or charging and nearly full
mBatteryLight.setColor(mBatteryFullARGB);
} else {
- // Solid orange when charging and halfway full
+ // Battery is charging and halfway full
mBatteryLight.setColor(mBatteryMediumARGB);
}
} else {
- // No lights if not charging and not low
+ //No lights if not charging and not low
mBatteryLight.turnOff();
}
}
}
+
+ class SettingsObserver extends ContentObserver {
+ SettingsObserver(Handler handler) {
+ super(handler);
+ }
+
+ void observe() {
+ ContentResolver resolver = mContext.getContentResolver();
+
+ // Battery light enabled
+ resolver.registerContentObserver(Settings.System.getUriFor(
+ Settings.System.BATTERY_LIGHT_ENABLED), false, this);
+
+ // Low battery pulse
+ resolver.registerContentObserver(Settings.System.getUriFor(
+ Settings.System.BATTERY_LIGHT_PULSE), false, this);
+
+ // Light colors
+ if (mMultiColorLed) {
+ // Register observer if we have a multi color led
+ resolver.registerContentObserver(Settings.System.getUriFor(
+ Settings.System.BATTERY_LIGHT_LOW_COLOR), false, this);
+ resolver.registerContentObserver(Settings.System.getUriFor(
+ Settings.System.BATTERY_LIGHT_MEDIUM_COLOR), false, this);
+ resolver.registerContentObserver(Settings.System.getUriFor(
+ Settings.System.BATTERY_LIGHT_FULL_COLOR), false, this);
+ }
+
+ // Quiet Hours
+ resolver.registerContentObserver(Settings.System.getUriFor(
+ Settings.System.QUIET_HOURS_ENABLED), false, this);
+ resolver.registerContentObserver(Settings.System.getUriFor(
+ Settings.System.QUIET_HOURS_START), false, this);
+ resolver.registerContentObserver(Settings.System.getUriFor(
+ Settings.System.QUIET_HOURS_END), false, this);
+ resolver.registerContentObserver(Settings.System.getUriFor(
+ Settings.System.QUIET_HOURS_DIM), false, this);
+
+ update();
+ }
+
+ @Override public void onChange(boolean selfChange) {
+ update();
+ }
+
+ public void update() {
+ ContentResolver resolver = mContext.getContentResolver();
+ Resources res = mContext.getResources();
+
+ // Battery light enabled
+ mLightEnabled = Settings.System.getInt(resolver,
+ Settings.System.BATTERY_LIGHT_ENABLED, 1) != 0;
+
+ // Low battery pulse
+ mLedPulseEnabled = Settings.System.getInt(resolver,
+ Settings.System.BATTERY_LIGHT_PULSE, 1) != 0;
+
+ // Light colors
+ mBatteryLowARGB = Settings.System.getInt(resolver,
+ Settings.System.BATTERY_LIGHT_LOW_COLOR,
+ res.getInteger(com.android.internal.R.integer.config_notificationsBatteryLowARGB));
+ mBatteryMediumARGB = Settings.System.getInt(resolver,
+ Settings.System.BATTERY_LIGHT_MEDIUM_COLOR,
+ res.getInteger(com.android.internal.R.integer.config_notificationsBatteryMediumARGB));
+ mBatteryFullARGB = Settings.System.getInt(resolver,
+ Settings.System.BATTERY_LIGHT_FULL_COLOR,
+ res.getInteger(com.android.internal.R.integer.config_notificationsBatteryFullARGB));
+
+ // Quiet Hours
+ mQuietHoursEnabled = Settings.System.getInt(resolver,
+ Settings.System.QUIET_HOURS_ENABLED, 0) != 0;
+ mQuietHoursStart = Settings.System.getInt(resolver,
+ Settings.System.QUIET_HOURS_START, 0);
+ mQuietHoursEnd = Settings.System.getInt(resolver,
+ Settings.System.QUIET_HOURS_END, 0);
+ mQuietHoursDim = Settings.System.getInt(resolver,
+ Settings.System.QUIET_HOURS_DIM, 0) != 0;
+
+ updateLedPulse();
+ }
+ }
+
+ private boolean inQuietHours() {
+ if (mQuietHoursEnabled && (mQuietHoursStart != mQuietHoursEnd)) {
+ // Get the date in "quiet hours" format.
+ Calendar calendar = Calendar.getInstance();
+ int minutes = calendar.get(Calendar.HOUR_OF_DAY) * 60 + calendar.get(Calendar.MINUTE);
+ if (mQuietHoursEnd < mQuietHoursStart) {
+ // Starts at night, ends in the morning.
+ return (minutes > mQuietHoursStart) || (minutes < mQuietHoursEnd);
+ } else {
+ return (minutes > mQuietHoursStart) && (minutes < mQuietHoursEnd);
+ }
+ }
+ return false;
+ }
+
}
diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java
index c9ff595..b11432d 100644
--- a/services/java/com/android/server/InputMethodManagerService.java
+++ b/services/java/com/android/server/InputMethodManagerService.java
@@ -397,6 +397,13 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
Settings.Secure.ENABLED_INPUT_METHODS), false, this);
resolver.registerContentObserver(Settings.Secure.getUriFor(
Settings.Secure.SELECTED_INPUT_METHOD_SUBTYPE), false, this);
+ resolver.registerContentObserver(Settings.System.getUriFor(
+ Settings.System.STATUS_BAR_IME_SWITCHER),
+ false, new ContentObserver(mHandler) {
+ public void onChange(boolean selfChange) {
+ updateFromSettingsLocked();
+ }
+ });
}
@Override public void onChange(boolean selfChange) {
@@ -844,8 +851,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
mStatusBar = statusBar;
statusBar.setIconVisibility("ime", false);
updateImeWindowStatusLocked();
- mShowOngoingImeSwitcherForPhones = mRes.getBoolean(
- com.android.internal.R.bool.show_ongoing_ime_switcher);
if (mShowOngoingImeSwitcherForPhones) {
mWindowManagerService.setOnHardKeyboardStatusChangeListener(
mHardKeyboardListener);
@@ -1597,6 +1602,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
mCurMethodId = null;
unbindCurrentMethodLocked(true, false);
}
+ mShowOngoingImeSwitcherForPhones = Settings.System.getInt(mContext.getContentResolver(),
+ Settings.System.STATUS_BAR_IME_SWITCHER, 1) == 1;
}
/* package */ void setInputMethodLocked(String id, int subtypeId) {
diff --git a/services/java/com/android/server/NotificationManagerService.java b/services/java/com/android/server/NotificationManagerService.java
index f3a38f0..af49135 100755
--- a/services/java/com/android/server/NotificationManagerService.java
+++ b/services/java/com/android/server/NotificationManagerService.java
@@ -27,7 +27,12 @@ import android.app.IActivityManager;
import android.app.INotificationManager;
import android.app.ITransientNotification;
import android.app.Notification;
+import android.app.NotificationGroup;
+import android.app.NotificationManager;
import android.app.PendingIntent;
+import android.app.Profile;
+import android.app.ProfileGroup;
+import android.app.ProfileManager;
import android.app.StatusBarManager;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
@@ -44,6 +49,7 @@ import android.media.IAudioService;
import android.media.IRingtonePlayer;
import android.net.Uri;
import android.os.Binder;
+import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
@@ -81,7 +87,10 @@ import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.HashMap;
import java.util.HashSet;
+import java.util.Calendar;
+import java.util.Map;
import libcore.io.IoUtils;
@@ -134,10 +143,13 @@ public class NotificationManagerService extends INotificationManager.Stub
private IAudioService mAudioService;
private Vibrator mVibrator;
- // for enabling and disabling notification pulse behavior
+ // for enabling and disabling notification pulse behaviour
private boolean mScreenOn = true;
+ private boolean mWasScreenOn = false;
private boolean mInCall = false;
private boolean mNotificationPulseEnabled;
+ private HashMap<String, NotificationLedValues> mNotificationPulseCustomLedValues;
+ private Map<String, String> mPackageNameMappings;
private final ArrayList<NotificationRecord> mNotificationList =
new ArrayList<NotificationRecord>();
@@ -147,6 +159,18 @@ public class NotificationManagerService extends INotificationManager.Stub
private ArrayList<NotificationRecord> mLights = new ArrayList<NotificationRecord>();
private NotificationRecord mLedNotification;
+ private boolean mQuietHoursEnabled = false;
+ // Minutes from midnight when quiet hours begin.
+ private int mQuietHoursStart = 0;
+ // Minutes from midnight when quiet hours end.
+ private int mQuietHoursEnd = 0;
+ // Don't play sounds.
+ private boolean mQuietHoursMute = true;
+ // Don't vibrate.
+ private boolean mQuietHoursStill = true;
+ // Dim LED if hardware supports it.
+ private boolean mQuietHoursDim = true;
+
// Notification control database. For now just contains disabled packages.
private AtomicFile mPolicyFile;
private HashSet<String> mBlockedPackages = new HashSet<String>();
@@ -402,6 +426,12 @@ public class NotificationManagerService extends INotificationManager.Stub
}
}
+ class NotificationLedValues {
+ public int color;
+ public int onMS;
+ public int offMS;
+ }
+
private StatusBarManagerService.NotificationCallbacks mNotificationCallbacks
= new StatusBarManagerService.NotificationCallbacks() {
@@ -553,6 +583,8 @@ public class NotificationManagerService extends INotificationManager.Stub
mScreenOn = true;
} else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
mScreenOn = false;
+ mWasScreenOn = true;
+ updateLightsLocked();
} else if (action.equals(TelephonyManager.ACTION_PHONE_STATE_CHANGED)) {
mInCall = (intent.getStringExtra(TelephonyManager.EXTRA_STATE).equals(
TelephonyManager.EXTRA_STATE_OFFHOOK));
@@ -569,8 +601,8 @@ public class NotificationManagerService extends INotificationManager.Stub
}
};
- class SettingsObserver extends ContentObserver {
- SettingsObserver(Handler handler) {
+ class LEDSettingsObserver extends ContentObserver {
+ LEDSettingsObserver(Handler handler) {
super(handler);
}
@@ -578,24 +610,96 @@ public class NotificationManagerService extends INotificationManager.Stub
ContentResolver resolver = mContext.getContentResolver();
resolver.registerContentObserver(Settings.System.getUriFor(
Settings.System.NOTIFICATION_LIGHT_PULSE), false, this);
+ resolver.registerContentObserver(Settings.System.getUriFor(
+ Settings.System.NOTIFICATION_LIGHT_PULSE_DEFAULT_COLOR), false, this);
+ resolver.registerContentObserver(Settings.System.getUriFor(
+ Settings.System.NOTIFICATION_LIGHT_PULSE_DEFAULT_LED_ON), false, this);
+ resolver.registerContentObserver(Settings.System.getUriFor(
+ Settings.System.NOTIFICATION_LIGHT_PULSE_DEFAULT_LED_OFF), false, this);
+ resolver.registerContentObserver(Settings.System.getUriFor(
+ Settings.System.NOTIFICATION_LIGHT_PULSE_CUSTOM_ENABLE), false, this);
+ resolver.registerContentObserver(Settings.System.getUriFor(
+ Settings.System.NOTIFICATION_LIGHT_PULSE_CUSTOM_VALUES), false, this);
update();
}
@Override public void onChange(boolean selfChange) {
update();
+ updateNotificationPulse();
}
public void update() {
ContentResolver resolver = mContext.getContentResolver();
- boolean pulseEnabled = Settings.System.getInt(resolver,
- Settings.System.NOTIFICATION_LIGHT_PULSE, 0) != 0;
- if (mNotificationPulseEnabled != pulseEnabled) {
- mNotificationPulseEnabled = pulseEnabled;
- updateNotificationPulse();
+ // LED enabled
+ mNotificationPulseEnabled = Settings.System.getInt(resolver,
+ Settings.System.NOTIFICATION_LIGHT_PULSE, 0) != 0;
+
+ // LED default color
+ mDefaultNotificationColor = Settings.System.getInt(resolver,
+ Settings.System.NOTIFICATION_LIGHT_PULSE_DEFAULT_COLOR, mDefaultNotificationColor);
+
+ // LED default on MS
+ mDefaultNotificationLedOn = Settings.System.getInt(resolver,
+ Settings.System.NOTIFICATION_LIGHT_PULSE_DEFAULT_LED_ON, mDefaultNotificationLedOn);
+
+ // LED default off MS
+ mDefaultNotificationLedOff = Settings.System.getInt(resolver,
+ Settings.System.NOTIFICATION_LIGHT_PULSE_DEFAULT_LED_OFF, mDefaultNotificationLedOff);
+
+ // LED custom notification colors
+ mNotificationPulseCustomLedValues.clear();
+ if (Settings.System.getInt(resolver,
+ Settings.System.NOTIFICATION_LIGHT_PULSE_CUSTOM_ENABLE, 0) != 0) {
+ parseNotificationPulseCustomValuesString(Settings.System.getString(resolver,
+ Settings.System.NOTIFICATION_LIGHT_PULSE_CUSTOM_VALUES));
}
}
}
+ class QuietHoursSettingsObserver extends ContentObserver {
+ QuietHoursSettingsObserver(Handler handler) {
+ super(handler);
+ }
+
+ void observe() {
+ ContentResolver resolver = mContext.getContentResolver();
+ resolver.registerContentObserver(Settings.System.getUriFor(
+ Settings.System.QUIET_HOURS_ENABLED), false, this);
+ resolver.registerContentObserver(Settings.System.getUriFor(
+ Settings.System.QUIET_HOURS_START), false, this);
+ resolver.registerContentObserver(Settings.System.getUriFor(
+ Settings.System.QUIET_HOURS_END), false, this);
+ resolver.registerContentObserver(Settings.System.getUriFor(
+ Settings.System.QUIET_HOURS_MUTE), false, this);
+ resolver.registerContentObserver(Settings.System.getUriFor(
+ Settings.System.QUIET_HOURS_STILL), false, this);
+ resolver.registerContentObserver(Settings.System.getUriFor(
+ Settings.System.QUIET_HOURS_DIM), false, this);
+ update();
+ }
+
+ @Override public void onChange(boolean selfChange) {
+ update();
+ updateNotificationPulse();
+ }
+
+ public void update() {
+ ContentResolver resolver = mContext.getContentResolver();
+ mQuietHoursEnabled = Settings.System.getInt(resolver,
+ Settings.System.QUIET_HOURS_ENABLED, 0) != 0;
+ mQuietHoursStart = Settings.System.getInt(resolver,
+ Settings.System.QUIET_HOURS_START, 0);
+ mQuietHoursEnd = Settings.System.getInt(resolver,
+ Settings.System.QUIET_HOURS_END, 0);
+ mQuietHoursMute = Settings.System.getInt(resolver,
+ Settings.System.QUIET_HOURS_MUTE, 0) != 0;
+ mQuietHoursStill = Settings.System.getInt(resolver,
+ Settings.System.QUIET_HOURS_STILL, 0) != 0;
+ mQuietHoursDim = Settings.System.getInt(resolver,
+ Settings.System.QUIET_HOURS_DIM, 0) != 0;
+ }
+ }
+
NotificationManagerService(Context context, StatusBarManagerService statusBar,
LightsService lights)
{
@@ -622,6 +726,15 @@ public class NotificationManagerService extends INotificationManager.Stub
mDefaultNotificationLedOff = resources.getInteger(
com.android.internal.R.integer.config_defaultNotificationLedOff);
+ mNotificationPulseCustomLedValues = new HashMap<String, NotificationLedValues>();
+
+ mPackageNameMappings = new HashMap<String, String>();
+ for(String mapping : resources.getStringArray(
+ com.android.internal.R.array.notification_light_package_mapping)) {
+ String[] map = mapping.split("\\|");
+ mPackageNameMappings.put(map[0], map[1]);
+ }
+
// Don't start allowing notifications until the setup wizard has run once.
// After that, including subsequent boots, init with notifications turned on.
// This works on the first boot because the setup wizard will toggle this
@@ -649,8 +762,10 @@ public class NotificationManagerService extends INotificationManager.Stub
IntentFilter sdFilter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
mContext.registerReceiver(mIntentReceiver, sdFilter);
- SettingsObserver observer = new SettingsObserver(mHandler);
- observer.observe();
+ LEDSettingsObserver ledObserver = new LEDSettingsObserver(mHandler);
+ ledObserver.observe();
+ QuietHoursSettingsObserver qhObserver = new QuietHoursSettingsObserver(mHandler);
+ qhObserver.observe();
}
void systemReady() {
@@ -965,6 +1080,8 @@ public class NotificationManagerService extends INotificationManager.Stub
}
synchronized (mNotificationList) {
+ final boolean inQuietHours = inQuietHours();
+
NotificationRecord r = new NotificationRecord(pkg, tag, id,
callingUid, callingPid, userId,
score,
@@ -1040,6 +1157,16 @@ public class NotificationManagerService extends INotificationManager.Stub
}
}
+ try {
+ final ProfileManager profileManager =
+ (ProfileManager) mContext.getSystemService(Context.PROFILE_SERVICE);
+
+ ProfileGroup group = profileManager.getActiveProfileGroup(pkg);
+ notification = group.processNotification(notification);
+ } catch(Throwable th) {
+ Log.e(TAG, "An error occurred profiling the notification.", th);
+ }
+
// If we're not supposed to beep, vibrate, etc. then don't.
if (((mDisabledNotifications & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) == 0)
&& (!(old != null
@@ -1053,7 +1180,8 @@ public class NotificationManagerService extends INotificationManager.Stub
// sound
final boolean useDefaultSound =
(notification.defaults & Notification.DEFAULT_SOUND) != 0;
- if (useDefaultSound || notification.sound != null) {
+ if (!(inQuietHours && mQuietHoursMute)
+ && (useDefaultSound || notification.sound != null)) {
Uri uri;
if (useDefaultSound) {
uri = Settings.System.DEFAULT_NOTIFICATION_URI;
@@ -1096,8 +1224,8 @@ public class NotificationManagerService extends INotificationManager.Stub
final boolean useDefaultVibrate =
(notification.defaults & Notification.DEFAULT_VIBRATE) != 0
|| convertSoundToVibration;
-
- if ((useDefaultVibrate || notification.vibrate != null)
+ if (!(inQuietHours && mQuietHoursStill)
+ && (useDefaultVibrate || notification.vibrate != null)
&& !(audioManager.getRingerMode() == AudioManager.RINGER_MODE_SILENT)) {
mVibrateNotification = r;
@@ -1131,6 +1259,21 @@ public class NotificationManagerService extends INotificationManager.Stub
idOut[0] = id;
}
+ private boolean inQuietHours() {
+ if (mQuietHoursEnabled && (mQuietHoursStart != mQuietHoursEnd)) {
+ // Get the date in "quiet hours" format.
+ Calendar calendar = Calendar.getInstance();
+ int minutes = calendar.get(Calendar.HOUR_OF_DAY) * 60 + calendar.get(Calendar.MINUTE);
+ if (mQuietHoursEnd < mQuietHoursStart) {
+ // Starts at night, ends in the morning.
+ return (minutes > mQuietHoursStart) || (minutes < mQuietHoursEnd);
+ } else {
+ return (minutes > mQuietHoursStart) && (minutes < mQuietHoursEnd);
+ }
+ }
+ return false;
+ }
+
private void sendAccessibilityEvent(Notification notification, CharSequence packageName) {
AccessibilityManager manager = AccessibilityManager.getInstance(mContext);
if (!manager.isEnabled()) {
@@ -1376,17 +1519,45 @@ public class NotificationManagerService extends INotificationManager.Stub
}
}
- // Don't flash while we are in a call or screen is on
- if (mLedNotification == null || mInCall || mScreenOn) {
+ boolean wasScreenOn = mWasScreenOn;
+ mWasScreenOn = false;
+
+ if (mLedNotification == null) {
+ mNotificationLight.turnOff();
+ return;
+ }
+
+ // We can assume that if the user turned the screen off while there was
+ // still an active notification then they wanted to keep the notification
+ // for later. In this case we shouldn't flash the notification light.
+ // For special notifications that automatically turn the screen on (such
+ // as missed calls), we use this flag to force the notification light
+ // even if the screen was turned off.
+ boolean forceWithScreenOff = (mLedNotification.notification.flags &
+ Notification.FLAG_FORCE_LED_SCREEN_OFF) != 0;
+
+ // Don't flash while we are in a call, screen is on or we are in quiet hours with light dimmed
+ if (mInCall || mScreenOn || (inQuietHours() && mQuietHoursDim) || (wasScreenOn && !forceWithScreenOff)) {
mNotificationLight.turnOff();
} else {
- int ledARGB = mLedNotification.notification.ledARGB;
- int ledOnMS = mLedNotification.notification.ledOnMS;
- int ledOffMS = mLedNotification.notification.ledOffMS;
- if ((mLedNotification.notification.defaults & Notification.DEFAULT_LIGHTS) != 0) {
- ledARGB = mDefaultNotificationColor;
- ledOnMS = mDefaultNotificationLedOn;
- ledOffMS = mDefaultNotificationLedOff;
+ int ledARGB;
+ int ledOnMS;
+ int ledOffMS;
+ NotificationLedValues ledValues = getLedValuesForNotification(mLedNotification);
+ if (ledValues != null) {
+ ledARGB = ledValues.color != 0 ? ledValues.color : mDefaultNotificationColor;
+ ledOnMS = ledValues.onMS >= 0 ? ledValues.onMS : mDefaultNotificationLedOn;
+ ledOffMS = ledValues.offMS >= 0 ? ledValues.offMS : mDefaultNotificationLedOn;
+ } else {
+ if ((mLedNotification.notification.defaults & Notification.DEFAULT_LIGHTS) != 0) {
+ ledARGB = mDefaultNotificationColor;
+ ledOnMS = mDefaultNotificationLedOn;
+ ledOffMS = mDefaultNotificationLedOff;
+ } else {
+ ledARGB = mLedNotification.notification.ledARGB;
+ ledOnMS = mLedNotification.notification.ledOnMS;
+ ledOffMS = mLedNotification.notification.ledOffMS;
+ }
}
if (mNotificationPulseEnabled) {
// pulse repeatedly
@@ -1396,6 +1567,47 @@ public class NotificationManagerService extends INotificationManager.Stub
}
}
+ private void parseNotificationPulseCustomValuesString(String customLedValuesString) {
+ if (TextUtils.isEmpty(customLedValuesString)) {
+ return;
+ }
+
+ for (String packageValuesString : customLedValuesString.split("\\|")) {
+ String[] packageValues = packageValuesString.split("=");
+ if (packageValues.length != 2) {
+ Log.e(TAG, "Error parsing custom led values for unknown package");
+ continue;
+ }
+ String packageName = packageValues[0];
+ String[] values = packageValues[1].split(";");
+ if (values.length != 3) {
+ Log.e(TAG, "Error parsing custom led values '" + packageValues[1] + "' for " + packageName);
+ continue;
+ }
+ NotificationLedValues ledValues = new NotificationLedValues();
+ try {
+ ledValues.color = Integer.parseInt(values[0]);
+ ledValues.onMS = Integer.parseInt(values[1]);
+ ledValues.offMS = Integer.parseInt(values[2]);
+ } catch (Exception e) {
+ Log.e(TAG, "Error parsing custom led values '" + packageValues[1] + "' for " + packageName);
+ continue;
+ }
+ mNotificationPulseCustomLedValues.put(packageName, ledValues);
+ }
+ }
+
+ private NotificationLedValues getLedValuesForNotification(NotificationRecord ledNotification) {
+ return mNotificationPulseCustomLedValues.get(mapPackage(ledNotification.pkg));
+ }
+
+ private String mapPackage(String pkg) {
+ if(!mPackageNameMappings.containsKey(pkg)) {
+ return pkg;
+ }
+ return mPackageNameMappings.get(pkg);
+ }
+
// lock on mNotificationList
private int indexOfNotificationLocked(String pkg, String tag, int id, int userId)
{
diff --git a/services/java/com/android/server/ProfileManagerService.java b/services/java/com/android/server/ProfileManagerService.java
new file mode 100644
index 0000000..aa769a5
--- /dev/null
+++ b/services/java/com/android/server/ProfileManagerService.java
@@ -0,0 +1,550 @@
+/*
+ * Copyright (c) 2011, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlPullParserFactory;
+
+import android.app.IProfileManager;
+import android.app.NotificationGroup;
+import android.app.Profile;
+import android.app.ProfileGroup;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.res.XmlResourceParser;
+import android.os.RemoteException;
+import android.text.TextUtils;
+import android.util.Log;
+import android.os.ParcelUuid;
+
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+
+/** {@hide} */
+public class ProfileManagerService extends IProfileManager.Stub {
+ // Enable the below for detailed logging of this class
+ private static final boolean LOCAL_LOGV = false;
+ /**
+ * <p>Broadcast Action: A new profile has been selected. This can be triggered by the user
+ * or by calls to the ProfileManagerService / Profile.</p>
+ * @hide
+ */
+ public static final String INTENT_ACTION_PROFILE_SELECTED = "android.intent.action.PROFILE_SELECTED";
+
+ public static final String PERMISSION_CHANGE_SETTINGS = "android.permission.WRITE_SETTINGS";
+
+ private static final String PROFILE_FILENAME = "/data/system/profiles.xml";
+
+ private static final String TAG = "ProfileService";
+
+ private Map<UUID, Profile> mProfiles;
+
+ // Match UUIDs and names, used for reverse compatibility
+ private Map<String, UUID> mProfileNames;
+
+ private Map<UUID, NotificationGroup> mGroups;
+
+ private Profile mActiveProfile;
+
+ // Well-known UUID of the wildcard group
+ private static final UUID mWildcardUUID = UUID.fromString("a126d48a-aaef-47c4-baed-7f0e44aeffe5");
+ private NotificationGroup mWildcardGroup;
+
+ private Context mContext;
+ private boolean mDirty;
+
+ private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+
+ if (action.equals(Intent.ACTION_LOCALE_CHANGED)) {
+ persistIfDirty();
+ initialize();
+ } else if (action.equals(Intent.ACTION_SHUTDOWN)) {
+ persistIfDirty();
+ }
+ }
+ };
+
+ public ProfileManagerService(Context context) {
+ mContext = context;
+
+ mWildcardGroup = new NotificationGroup(
+ context.getString(com.android.internal.R.string.wildcardProfile),
+ com.android.internal.R.string.wildcardProfile,
+ mWildcardUUID);
+
+ initialize();
+
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(Intent.ACTION_LOCALE_CHANGED);
+ filter.addAction(Intent.ACTION_SHUTDOWN);
+ mContext.registerReceiver(mIntentReceiver, filter);
+ }
+
+ private void initialize() {
+ initialize(false);
+ }
+
+ private void initialize(boolean skipFile) {
+ mProfiles = new HashMap<UUID, Profile>();
+ mProfileNames = new HashMap<String, UUID>();
+ mGroups = new HashMap<UUID, NotificationGroup>();
+ mDirty = false;
+
+ boolean init = skipFile;
+
+ if (! skipFile) {
+ try {
+ loadFromFile();
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ } catch (XmlPullParserException e) {
+ init = true;
+ } catch (IOException e) {
+ init = true;
+ }
+ }
+
+ if (init) {
+ try {
+ initialiseStructure();
+ } catch (Throwable ex) {
+ Log.e(TAG, "Error loading xml from resource: ", ex);
+ }
+ }
+ }
+
+ @Override
+ public void resetAll() {
+ enforceChangePermissions();
+ initialize(true);
+ }
+
+ @Override
+ @Deprecated
+ public boolean setActiveProfileByName(String profileName) throws RemoteException, SecurityException {
+ if (mProfileNames.containsKey(profileName)) {
+ if (LOCAL_LOGV) Log.v(TAG, "setActiveProfile(String) found profile name in mProfileNames.");
+ return setActiveProfile(mProfiles.get(mProfileNames.get(profileName)), true);
+ } else {
+ // Since profileName could not be casted into a UUID, we can call it a string.
+ Log.w(TAG, "Unable to find profile to set active, based on string: " + profileName);
+ return false;
+ }
+ }
+
+ @Override
+ public boolean setActiveProfile(ParcelUuid profileParcelUuid) throws RemoteException, SecurityException {
+ UUID profileUuid = profileParcelUuid.getUuid();
+ if(mProfiles.containsKey(profileUuid)){
+ if (LOCAL_LOGV) Log.v(TAG, "setActiveProfileByUuid(ParcelUuid) found profile UUID in mProfileNames.");
+ return setActiveProfile(mProfiles.get(profileUuid), true);
+ } else {
+ Log.e(TAG, "Cannot set active profile to: " + profileUuid.toString() + " - does not exist.");
+ return false;
+ }
+ }
+
+ private boolean setActiveProfile(UUID profileUuid, boolean doinit) throws RemoteException {
+ if(mProfiles.containsKey(profileUuid)){
+ if (LOCAL_LOGV) Log.v(TAG, "setActiveProfile(UUID, boolean) found profile UUID in mProfiles.");
+ return setActiveProfile(mProfiles.get(profileUuid), doinit);
+ } else {
+ Log.e(TAG, "Cannot set active profile to: " + profileUuid.toString() + " - does not exist.");
+ return false;
+ }
+ }
+
+ private boolean setActiveProfile(Profile newActiveProfile, boolean doinit) throws RemoteException {
+ /*
+ * NOTE: Since this is not a public function, and all public functions
+ * take either a string or a UUID, the active profile should always be
+ * in the collection. If writing another setActiveProfile which receives
+ * a Profile object, run enforceChangePermissions, add the profile to the
+ * list, and THEN add it.
+ */
+
+ try {
+ enforceChangePermissions();
+ Log.d(TAG, "Set active profile to: " + newActiveProfile.getUuid().toString() + " - " + newActiveProfile.getName());
+ Profile lastProfile = mActiveProfile;
+ mActiveProfile = newActiveProfile;
+ mDirty = true;
+ if (doinit) {
+ if (LOCAL_LOGV) Log.v(TAG, "setActiveProfile(Profile, boolean) - Running init");
+
+ /*
+ * We need to clear the caller's identity in order to
+ * - allow the profile switch to execute actions not included in the caller's permissions
+ * - broadcast INTENT_ACTION_PROFILE_SELECTED
+ */
+ long token = clearCallingIdentity();
+
+ // Call profile's "doSelect"
+ mActiveProfile.doSelect(mContext);
+
+ // Notify other applications of newly selected profile.
+ Intent broadcast = new Intent(INTENT_ACTION_PROFILE_SELECTED);
+ broadcast.putExtra("name", mActiveProfile.getName());
+ broadcast.putExtra("uuid", mActiveProfile.getUuid().toString());
+ broadcast.putExtra("lastName", lastProfile.getName());
+ broadcast.putExtra("lastUuid", lastProfile.getUuid().toString());
+ mContext.sendBroadcast(broadcast);
+
+ restoreCallingIdentity(token);
+ persistIfDirty();
+ }
+ return true;
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ return false;
+ }
+ }
+
+ @Override
+ public boolean addProfile(Profile profile) throws RemoteException, SecurityException {
+ enforceChangePermissions();
+ addProfileInternal(profile);
+ persistIfDirty();
+ return true;
+ }
+
+ private void addProfileInternal(Profile profile) {
+ // Make sure this profile has all of the correct groups.
+ for (NotificationGroup group : mGroups.values()) {
+ ensureGroupInProfile(profile, group, false);
+ }
+ ensureGroupInProfile(profile, mWildcardGroup, true);
+ mProfiles.put(profile.getUuid(), profile);
+ mProfileNames.put(profile.getName(), profile.getUuid());
+ mDirty = true;
+ }
+
+ private void ensureGroupInProfile(Profile profile, NotificationGroup group, boolean defaultGroup) {
+ if (profile.getProfileGroup(group.getUuid()) != null) {
+ return;
+ }
+
+ /* enforce a matchup between profile and notification group, which not only
+ * works by UUID, but also by name for backwards compatibility */
+ for (ProfileGroup pg : profile.getProfileGroups()) {
+ if (pg.matches(group, defaultGroup)) {
+ return;
+ }
+ }
+
+ /* didn't find any, create new group */
+ profile.addProfileGroup(new ProfileGroup(group.getUuid(), defaultGroup));
+ }
+
+ @Override
+ @Deprecated
+ public Profile getProfileByName(String profileName) throws RemoteException {
+ if (mProfileNames.containsKey(profileName)) {
+ return mProfiles.get(mProfileNames.get(profileName));
+ } else if (mProfiles.containsKey(UUID.fromString((profileName)))) {
+ return mProfiles.get(UUID.fromString(profileName));
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ public Profile getProfile(ParcelUuid profileParcelUuid) {
+ UUID profileUuid = profileParcelUuid.getUuid();
+ return getProfile(profileUuid);
+ }
+
+ public Profile getProfile(UUID profileUuid) {
+ // use primary UUID first
+ if (mProfiles.containsKey(profileUuid)) {
+ return mProfiles.get(profileUuid);
+ }
+ // if no match was found: try secondary UUID
+ for (Profile p : mProfiles.values()) {
+ for (UUID uuid : p.getSecondaryUuids()) {
+ if (profileUuid.equals(uuid)) {
+ return p;
+ }
+ }
+ }
+ // nothing found
+ return null;
+ }
+
+ @Override
+ public Profile[] getProfiles() throws RemoteException {
+ Profile[] tmpArr = mProfiles.values().toArray(new Profile[mProfiles.size()]);
+ Arrays.sort(tmpArr);
+ return tmpArr;
+ }
+
+ @Override
+ public Profile getActiveProfile() throws RemoteException {
+ return mActiveProfile;
+ }
+
+ @Override
+ public boolean removeProfile(Profile profile) throws RemoteException, SecurityException {
+ enforceChangePermissions();
+ if (mProfileNames.remove(profile.getName()) != null && mProfiles.remove(profile.getUuid()) != null) {
+ mDirty = true;
+ persistIfDirty();
+ return true;
+ } else{
+ return false;
+ }
+ }
+
+ @Override
+ public void updateProfile(Profile profile) throws RemoteException, SecurityException {
+ enforceChangePermissions();
+ Profile old = mProfiles.get(profile.getUuid());
+ if (old != null) {
+ mProfileNames.remove(old.getName());
+ mProfileNames.put(profile.getName(), profile.getUuid());
+ mProfiles.put(profile.getUuid(), profile);
+ /* no need to set mDirty, if the profile was actually changed,
+ * it's marked as dirty by itself */
+ persistIfDirty();
+
+ // Also update we changed the active profile
+ if (mActiveProfile != null && mActiveProfile.getUuid().equals(profile.getUuid())) {
+ setActiveProfile(profile, true);
+ }
+ }
+ }
+
+ @Override
+ public boolean profileExists(ParcelUuid profileUuid) throws RemoteException {
+ return mProfiles.containsKey(profileUuid.getUuid());
+ }
+
+ @Override
+ public boolean profileExistsByName(String profileName) throws RemoteException {
+ for (Map.Entry<String, UUID> entry : mProfileNames.entrySet()) {
+ if (entry.getKey().equalsIgnoreCase(profileName)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public boolean notificationGroupExistsByName(String notificationGroupName) throws RemoteException {
+ for (NotificationGroup group : mGroups.values()) {
+ if (group.getName().equalsIgnoreCase(notificationGroupName)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public NotificationGroup[] getNotificationGroups() throws RemoteException {
+ return mGroups.values().toArray(new NotificationGroup[mGroups.size()]);
+ }
+
+ @Override
+ public void addNotificationGroup(NotificationGroup group) throws RemoteException, SecurityException {
+ enforceChangePermissions();
+ addNotificationGroupInternal(group);
+ persistIfDirty();
+ }
+
+ private void addNotificationGroupInternal(NotificationGroup group) {
+ if (mGroups.put(group.getUuid(), group) == null) {
+ // If the above is true, then the ProfileGroup shouldn't exist in
+ // the profile. Ensure it is added.
+ for (Profile profile : mProfiles.values()) {
+ ensureGroupInProfile(profile, group, false);
+ }
+ }
+ mDirty = true;
+ }
+
+ @Override
+ public void removeNotificationGroup(NotificationGroup group) throws RemoteException, SecurityException {
+ enforceChangePermissions();
+ mDirty |= (mGroups.remove(group.getUuid()) != null);
+ // Remove the corresponding ProfileGroup from all the profiles too if
+ // they use it.
+ for (Profile profile : mProfiles.values()) {
+ profile.removeProfileGroup(group.getUuid());
+ }
+ persistIfDirty();
+ }
+
+ @Override
+ public void updateNotificationGroup(NotificationGroup group) throws RemoteException, SecurityException {
+ enforceChangePermissions();
+ NotificationGroup old = mGroups.get(group.getUuid());
+ if (old != null) {
+ mGroups.put(group.getUuid(), group);
+ /* no need to set mDirty, if the group was actually changed,
+ * it's marked as dirty by itself */
+ persistIfDirty();
+ }
+ }
+
+ @Override
+ public NotificationGroup getNotificationGroupForPackage(String pkg) throws RemoteException {
+ for (NotificationGroup group : mGroups.values()) {
+ if (group.hasPackage(pkg)) {
+ return group;
+ }
+ }
+ return null;
+ }
+
+ private void loadFromFile() throws RemoteException, XmlPullParserException, IOException {
+ XmlPullParserFactory xppf = XmlPullParserFactory.newInstance();
+ XmlPullParser xpp = xppf.newPullParser();
+ FileReader fr = new FileReader(PROFILE_FILENAME);
+ xpp.setInput(fr);
+ loadXml(xpp, mContext);
+ fr.close();
+ persistIfDirty();
+ }
+
+ private void loadXml(XmlPullParser xpp, Context context) throws
+ XmlPullParserException, IOException, RemoteException {
+ int event = xpp.next();
+ String active = null;
+ while (event != XmlPullParser.END_TAG || !"profiles".equals(xpp.getName())) {
+ if (event == XmlPullParser.START_TAG) {
+ String name = xpp.getName();
+ if (name.equals("active")) {
+ active = xpp.nextText();
+ Log.d(TAG, "Found active: " + active);
+ } else if (name.equals("profile")) {
+ Profile prof = Profile.fromXml(xpp, context);
+ addProfileInternal(prof);
+ // Failsafe if no active found
+ if (active == null) {
+ active = prof.getUuid().toString();
+ }
+ } else if (name.equals("notificationGroup")) {
+ NotificationGroup ng = NotificationGroup.fromXml(xpp, context);
+ addNotificationGroupInternal(ng);
+ }
+ } else if (event == XmlPullParser.END_DOCUMENT) {
+ throw new IOException("Premature end of file while reading " + PROFILE_FILENAME);
+ }
+ event = xpp.next();
+ }
+ // Don't do initialisation on startup. The AudioManager doesn't exist yet
+ // and besides, the volume settings will have survived the reboot.
+ try {
+ // Try / catch block to detect if XML file needs to be upgraded.
+ setActiveProfile(UUID.fromString(active), false);
+ } catch (IllegalArgumentException e) {
+ if (mProfileNames.containsKey(active)) {
+ setActiveProfile(mProfileNames.get(active), false);
+ } else {
+ // Final fail-safe: We must have SOME profile active.
+ // If we couldn't select one by now, we'll pick the first in the set.
+ setActiveProfile(mProfiles.values().iterator().next(), false);
+ }
+ // This is a hint that we probably just upgraded the XML file. Save changes.
+ mDirty = true;
+ }
+ }
+
+ private void initialiseStructure() throws RemoteException, XmlPullParserException, IOException {
+ XmlResourceParser xml = mContext.getResources().getXml(
+ com.android.internal.R.xml.profile_default);
+ try {
+ loadXml(xml, mContext);
+ mDirty = true;
+ persistIfDirty();
+ } finally {
+ xml.close();
+ }
+ }
+
+ private String getXmlString() throws RemoteException {
+ StringBuilder builder = new StringBuilder();
+ builder.append("<profiles>\n<active>");
+ builder.append(TextUtils.htmlEncode(getActiveProfile().getUuid().toString()));
+ builder.append("</active>\n");
+
+ for (Profile p : mProfiles.values()) {
+ p.getXmlString(builder, mContext);
+ }
+ for (NotificationGroup g : mGroups.values()) {
+ g.getXmlString(builder, mContext);
+ }
+ builder.append("</profiles>\n");
+ return builder.toString();
+ }
+
+ @Override
+ public NotificationGroup getNotificationGroup(ParcelUuid uuid) throws RemoteException {
+ if (uuid.getUuid().equals(mWildcardGroup.getUuid())) {
+ return mWildcardGroup;
+ }
+ return mGroups.get(uuid.getUuid());
+ }
+
+ private synchronized void persistIfDirty() {
+ boolean dirty = mDirty;
+ if (!dirty) {
+ for (Profile profile : mProfiles.values()) {
+ if (profile.isDirty()) {
+ dirty = true;
+ break;
+ }
+ }
+ }
+ if (!dirty) {
+ for (NotificationGroup group : mGroups.values()) {
+ if (group.isDirty()) {
+ dirty = true;
+ break;
+ }
+ }
+ }
+ if (dirty) {
+ try {
+ Log.d(TAG, "Saving profile data...");
+ FileWriter fw = new FileWriter(PROFILE_FILENAME);
+ fw.write(getXmlString());
+ fw.close();
+ Log.d(TAG, "Save completed.");
+ mDirty = false;
+ } catch (Throwable e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ private void enforceChangePermissions() throws SecurityException {
+ mContext.enforceCallingOrSelfPermission(PERMISSION_CHANGE_SETTINGS,
+ "You do not have permissions to change the Profile Manager.");
+ }
+}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 894c4d0..3dd22b0 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -346,6 +346,7 @@ class ServerThread extends Thread {
StatusBarManagerService statusBar = null;
InputMethodManagerService imm = null;
AppWidgetService appWidget = null;
+ ProfileManagerService profile = null;
NotificationManagerService notification = null;
WallpaperManagerService wallpaper = null;
LocationManagerService location = null;
@@ -553,6 +554,14 @@ class ServerThread extends Thread {
}
try {
+ Slog.i(TAG, "Profile Manager");
+ profile = new ProfileManagerService(context);
+ ServiceManager.addService(Context.PROFILE_SERVICE, profile);
+ } catch (Throwable e) {
+ Slog.e(TAG, "Failure starting Profile Manager", e);
+ }
+
+ try {
Slog.i(TAG, "Notification Manager");
notification = new NotificationManagerService(context, statusBar, lights);
ServiceManager.addService(Context.NOTIFICATION_SERVICE, notification);
diff --git a/services/java/com/android/server/VibratorService.java b/services/java/com/android/server/VibratorService.java
index df91dec..64cae1d 100755
--- a/services/java/com/android/server/VibratorService.java
+++ b/services/java/com/android/server/VibratorService.java
@@ -39,6 +39,7 @@ import android.provider.Settings.SettingNotFoundException;
import android.util.Slog;
import android.view.InputDevice;
+import java.util.Calendar;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.ListIterator;
@@ -164,6 +165,29 @@ public class VibratorService extends IVibratorService.Stub
return doVibratorExists();
}
+ private boolean inQuietHours() {
+ boolean quietHoursEnabled = Settings.System.getInt(mContext.getContentResolver(),
+ Settings.System.QUIET_HOURS_ENABLED, 0) != 0;
+ int quietHoursStart = Settings.System.getInt(mContext.getContentResolver(),
+ Settings.System.QUIET_HOURS_START, 0);
+ int quietHoursEnd = Settings.System.getInt(mContext.getContentResolver(),
+ Settings.System.QUIET_HOURS_END, 0);
+ boolean quietHoursHaptic = Settings.System.getInt(mContext.getContentResolver(),
+ Settings.System.QUIET_HOURS_HAPTIC, 0) != 0;
+ if (quietHoursEnabled && quietHoursHaptic && (quietHoursStart != quietHoursEnd)) {
+ // Get the date in "quiet hours" format.
+ Calendar calendar = Calendar.getInstance();
+ int minutes = calendar.get(Calendar.HOUR_OF_DAY) * 60 + calendar.get(Calendar.MINUTE);
+ if (quietHoursEnd < quietHoursStart) {
+ // Starts at night, ends in the morning.
+ return (minutes > quietHoursStart) || (minutes < quietHoursEnd);
+ } else {
+ return (minutes > quietHoursStart) && (minutes < quietHoursEnd);
+ }
+ }
+ return false;
+ }
+
public void vibrate(long milliseconds, IBinder token) {
if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.VIBRATE)
!= PackageManager.PERMISSION_GRANTED) {
@@ -174,7 +198,7 @@ public class VibratorService extends IVibratorService.Stub
// timeout of 0 or negative. This will ensure that a vibration has
// either a timeout of > 0 or a non-null pattern.
if (milliseconds <= 0 || (mCurrentVibration != null
- && mCurrentVibration.hasLongerTimeout(milliseconds))) {
+ && mCurrentVibration.hasLongerTimeout(milliseconds)) || inQuietHours()) {
// Ignore this vibration since the current vibration will play for
// longer than milliseconds.
return;
@@ -204,6 +228,9 @@ public class VibratorService extends IVibratorService.Stub
!= PackageManager.PERMISSION_GRANTED) {
throw new SecurityException("Requires VIBRATE permission");
}
+ if (inQuietHours()) {
+ return;
+ }
int uid = Binder.getCallingUid();
// so wakelock calls will succeed
long identity = Binder.clearCallingIdentity();
diff --git a/services/java/com/android/server/power/ShutdownThread.java b/services/java/com/android/server/power/ShutdownThread.java
index c7f7390..1aa1fb0 100644
--- a/services/java/com/android/server/power/ShutdownThread.java
+++ b/services/java/com/android/server/power/ShutdownThread.java
@@ -47,6 +47,7 @@ import com.android.internal.telephony.ITelephony;
import android.util.Log;
import android.view.WindowManager;
+import android.view.KeyEvent;
public final class ShutdownThread extends Thread {
// constants
@@ -129,22 +130,63 @@ public final class ShutdownThread extends Thread {
if (sConfirmDialog != null) {
sConfirmDialog.dismiss();
}
- sConfirmDialog = new AlertDialog.Builder(context)
- .setTitle(mRebootSafeMode
- ? com.android.internal.R.string.reboot_safemode_title
- : com.android.internal.R.string.power_off)
- .setMessage(resourceId)
- .setPositiveButton(com.android.internal.R.string.yes, new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int which) {
- beginShutdownSequence(context);
- }
- })
- .setNegativeButton(com.android.internal.R.string.no, null)
- .create();
+ if (mReboot && !mRebootSafeMode){
+ sConfirmDialog = new AlertDialog.Builder(context)
+ .setIcon(android.R.drawable.ic_dialog_alert)
+ .setTitle(com.android.internal.R.string.reboot_system)
+ .setSingleChoiceItems(com.android.internal.R.array.shutdown_reboot_options, 0, new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ if (which < 0)
+ return;
+
+ String actions[] = context.getResources().getStringArray(com.android.internal.R.array.shutdown_reboot_actions);
+
+ if (actions != null && which < actions.length)
+ mRebootReason = actions[which];
+ }
+ })
+ .setPositiveButton(com.android.internal.R.string.yes, new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ mReboot = true;
+ beginShutdownSequence(context);
+ }
+ })
+ .setNegativeButton(com.android.internal.R.string.no, new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ mReboot = false;
+ dialog.cancel();
+ }
+ })
+ .create();
+ sConfirmDialog.setOnKeyListener(new DialogInterface.OnKeyListener() {
+ public boolean onKey (DialogInterface dialog, int keyCode, KeyEvent event) {
+ if (keyCode == KeyEvent.KEYCODE_BACK) {
+ mReboot = false;
+ dialog.cancel();
+ }
+ return true;
+ }
+ });
+ } else {
+ sConfirmDialog = new AlertDialog.Builder(context)
+ .setTitle(mRebootSafeMode
+ ? com.android.internal.R.string.reboot_safemode_title
+ : com.android.internal.R.string.power_off)
+ .setMessage(resourceId)
+ .setPositiveButton(com.android.internal.R.string.yes, new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ beginShutdownSequence(context);
+ }
+ })
+ .setNegativeButton(com.android.internal.R.string.no, null)
+ .create();
+ }
+
closer.dialog = sConfirmDialog;
sConfirmDialog.setOnDismissListener(closer);
sConfirmDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
sConfirmDialog.show();
+
} else {
beginShutdownSequence(context);
}
@@ -213,8 +255,13 @@ public final class ShutdownThread extends Thread {
// throw up an indeterminate system dialog to indicate radio is
// shutting down.
ProgressDialog pd = new ProgressDialog(context);
- pd.setTitle(context.getText(com.android.internal.R.string.power_off));
- pd.setMessage(context.getText(com.android.internal.R.string.shutdown_progress));
+ if (mReboot) {
+ pd.setTitle(context.getText(com.android.internal.R.string.reboot_system));
+ pd.setMessage(context.getText(com.android.internal.R.string.reboot_progress));
+ } else {
+ pd.setTitle(context.getText(com.android.internal.R.string.power_off));
+ pd.setMessage(context.getText(com.android.internal.R.string.shutdown_progress));
+ }
pd.setIndeterminate(true);
pd.setCancelable(false);
pd.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
@@ -294,7 +341,7 @@ public final class ShutdownThread extends Thread {
}
Log.i(TAG, "Sending shutdown broadcast...");
-
+
// First send the high-level shut down broadcast.
mActionDone = false;
mContext.sendOrderedBroadcastAsUser(new Intent(Intent.ACTION_SHUTDOWN),
@@ -314,9 +361,9 @@ public final class ShutdownThread extends Thread {
}
}
}
-
+
Log.i(TAG, "Shutting down activity manager...");
-
+
final IActivityManager am =
ActivityManagerNative.asInterface(ServiceManager.checkService("activity"));
if (am != null) {
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index 51edb44..38233d0 100755
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -5430,6 +5430,12 @@ public class WindowManagerService extends IWindowManager.Stub
mInputManager.setInputFilter(filter);
}
+ // Called by window manager policy. Not exposed externally.
+ @Override
+ public void reboot() {
+ ShutdownThread.reboot(mContext, null, true);
+ }
+
public void setCurrentUser(final int newUserId) {
synchronized (mWindowMap) {
mCurrentUserId = newUserId;