summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Android.mk17
-rw-r--r--CleanSpec.mk9
-rw-r--r--cmds/bootanimation/Android.mk23
-rw-r--r--cmds/bootanimation/BootAnimation.cpp369
-rw-r--r--cmds/bootanimation/BootAnimation.h14
-rw-r--r--cmds/bootanimation/bootanimation_main.cpp3
-rw-r--r--cmds/content/src/com/android/commands/content/Content.java24
-rw-r--r--cmds/idmap/create.cpp44
-rw-r--r--cmds/idmap/idmap.cpp72
-rw-r--r--cmds/idmap/idmap.h5
-rw-r--r--cmds/idmap/inspect.cpp15
-rw-r--r--cmds/idmap/scan.cpp102
-rw-r--r--cmds/input/src/com/android/commands/input/Input.java1
-rw-r--r--cmds/media/src/com/android/commands/media/Media.java20
-rwxr-xr-xcmds/pm/pm1
-rw-r--r--cmds/screencap/screencap.cpp22
-rw-r--r--cmds/settings/Android.mk1
-rw-r--r--cmds/settings/src/com/android/commands/settings/SettingsCmd.java94
-rw-r--r--cmds/tm/Android.mk15
-rw-r--r--cmds/tm/MODULE_LICENSE_APACHE20
-rw-r--r--cmds/tm/NOTICE190
-rw-r--r--cmds/tm/src/com/android/commands/tm/Tm.java201
-rwxr-xr-xcmds/tm/tm6
-rw-r--r--core/java/android/accounts/AccountManager.java26
-rw-r--r--core/java/android/app/ActivityManager.java37
-rw-r--r--core/java/android/app/ActivityManagerNative.java28
-rw-r--r--core/java/android/app/ActivityThread.java69
-rw-r--r--core/java/android/app/AlarmManager.java8
-rw-r--r--core/java/android/app/AppOpsManager.java375
-rw-r--r--core/java/android/app/ApplicationPackageManager.java82
-rw-r--r--core/java/android/app/ComposedIconInfo.aidl19
-rw-r--r--core/java/android/app/ComposedIconInfo.java149
-rw-r--r--core/java/android/app/ContextImpl.java74
-rw-r--r--core/java/android/app/IActivityManager.java8
-rw-r--r--core/java/android/app/IAlarmManager.aidl2
-rw-r--r--core/java/android/app/IWallpaperManager.aidl19
-rw-r--r--core/java/android/app/IWallpaperManagerCallback.aidl5
-rw-r--r--core/java/android/app/IconPackHelper.java1057
-rw-r--r--core/java/android/app/Instrumentation.java7
-rw-r--r--core/java/android/app/LoadedApk.java5
-rw-r--r--core/java/android/app/Notification.java7
-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/ResourcesManager.java467
-rw-r--r--core/java/android/app/SystemServiceRegistry.java11
-rw-r--r--core/java/android/app/WallpaperManager.java202
-rw-r--r--core/java/android/app/admin/DevicePolicyManager.java20
-rw-r--r--core/java/android/app/admin/IDevicePolicyManager.aidl2
-rwxr-xr-x[-rw-r--r--]core/java/android/bluetooth/BluetoothA2dpSink.java83
-rw-r--r--core/java/android/bluetooth/BluetoothAdapter.java142
-rw-r--r--core/java/android/bluetooth/BluetoothAvrcpController.java87
-rw-r--r--core/java/android/bluetooth/BluetoothAvrcpInfo.aidl34
-rw-r--r--core/java/android/bluetooth/BluetoothAvrcpInfo.java306
-rwxr-xr-x[-rw-r--r--]core/java/android/bluetooth/BluetoothClass.java17
-rw-r--r--core/java/android/bluetooth/BluetoothDevice.java21
-rw-r--r--core/java/android/bluetooth/BluetoothDevicePicker.java8
-rw-r--r--core/java/android/bluetooth/BluetoothDun.java296
-rw-r--r--core/java/android/bluetooth/BluetoothHeadset.java115
-rw-r--r--core/java/android/bluetooth/BluetoothHeadsetClient.java19
-rw-r--r--core/java/android/bluetooth/BluetoothHidDevice.java502
-rw-r--r--core/java/android/bluetooth/BluetoothHidDeviceAppConfiguration.aidl21
-rw-r--r--core/java/android/bluetooth/BluetoothHidDeviceAppConfiguration.java72
-rw-r--r--core/java/android/bluetooth/BluetoothHidDeviceAppQosSettings.aidl21
-rw-r--r--core/java/android/bluetooth/BluetoothHidDeviceAppQosSettings.java99
-rw-r--r--core/java/android/bluetooth/BluetoothHidDeviceAppSdpSettings.aidl21
-rw-r--r--core/java/android/bluetooth/BluetoothHidDeviceAppSdpSettings.java82
-rw-r--r--core/java/android/bluetooth/BluetoothHidDeviceCallback.java128
-rw-r--r--core/java/android/bluetooth/BluetoothInputDevice.java61
-rw-r--r--core/java/android/bluetooth/BluetoothProfile.java12
-rw-r--r--core/java/android/bluetooth/BluetoothSocket.java56
-rw-r--r--core/java/android/bluetooth/IBluetooth.aidl8
-rwxr-xr-x[-rw-r--r--]core/java/android/bluetooth/IBluetoothA2dpSink.aidl3
-rw-r--r--core/java/android/bluetooth/IBluetoothAvrcpController.aidl8
-rw-r--r--core/java/android/bluetooth/IBluetoothDun.aidl45
-rw-r--r--core/java/android/bluetooth/IBluetoothHidDevice.aidl39
-rw-r--r--core/java/android/bluetooth/IBluetoothHidDeviceCallback.aidl33
-rw-r--r--core/java/android/bluetooth/IBluetoothInputDevice.aidl8
-rw-r--r--core/java/android/bluetooth/IBluetoothManager.aidl6
-rw-r--r--core/java/android/content/BroadcastReceiver.java12
-rw-r--r--core/java/android/content/ContentResolver.java5
-rw-r--r--core/java/android/content/Context.java33
-rw-r--r--core/java/android/content/ContextWrapper.java21
-rw-r--r--core/java/android/content/Intent.java141
-rw-r--r--core/java/android/content/ThemeVersion.java75
-rw-r--r--core/java/android/content/pm/ActivityInfo.java13
-rw-r--r--core/java/android/content/pm/ApplicationInfo.java20
-rw-r--r--core/java/android/content/pm/BaseThemeInfo.java111
-rw-r--r--core/java/android/content/pm/IPackageManager.aidl10
-rw-r--r--core/java/android/content/pm/PackageInfo.java48
-rw-r--r--core/java/android/content/pm/PackageInfoLite.java3
-rw-r--r--core/java/android/content/pm/PackageItemInfo.java14
-rw-r--r--core/java/android/content/pm/PackageManager.java95
-rw-r--r--core/java/android/content/pm/PackageParser.java241
-rw-r--r--core/java/android/content/pm/PackageUserState.java6
-rw-r--r--core/java/android/content/pm/PermissionInfo.java11
-rw-r--r--core/java/android/content/pm/ThemeInfo.aidl3
-rw-r--r--core/java/android/content/pm/ThemeInfo.java65
-rw-r--r--core/java/android/content/pm/ThemeUtils.java735
-rw-r--r--core/java/android/content/res/AssetManager.java227
-rw-r--r--core/java/android/content/res/CompatibilityInfo.java3
-rw-r--r--core/java/android/content/res/Configuration.java94
-rw-r--r--core/java/android/content/res/IThemeChangeListener.aidl22
-rw-r--r--core/java/android/content/res/IThemeProcessingListener.aidl21
-rw-r--r--core/java/android/content/res/IThemeService.aidl43
-rw-r--r--core/java/android/content/res/Resources.java176
-rw-r--r--core/java/android/content/res/ResourcesKey.java19
-rw-r--r--core/java/android/content/res/ThemeChangeRequest.aidl19
-rw-r--r--core/java/android/content/res/ThemeChangeRequest.java307
-rw-r--r--core/java/android/content/res/ThemeConfig.java599
-rw-r--r--core/java/android/content/res/ThemeManager.java316
-rw-r--r--core/java/android/database/sqlite/SQLiteConnection.java2
-rw-r--r--core/java/android/hardware/Camera.java1523
-rw-r--r--core/java/android/hardware/SystemSensorManager.java2
-rw-r--r--core/java/android/hardware/camera2/legacy/RequestThreadManager.java3
-rw-r--r--core/java/android/hardware/camera2/legacy/SurfaceTextureRenderer.java14
-rw-r--r--core/java/android/inputmethodservice/InputMethodService.java34
-rw-r--r--core/java/android/net/ConnectivityManager.java25
-rw-r--r--core/java/android/net/IConnectivityManager.aidl5
-rw-r--r--core/java/android/net/INetworkManagementEventObserver.aidl7
-rw-r--r--core/java/android/net/wimax/WimaxHelper.java188
-rw-r--r--core/java/android/nfc/cardemulation/ApduServiceInfo.java20
-rw-r--r--core/java/android/os/Environment.java11
-rw-r--r--core/java/android/os/IDeviceIdleController.aidl1
-rw-r--r--core/java/android/os/IPowerManager.aidl10
-rw-r--r--core/java/android/os/PowerManager.java82
-rw-r--r--core/java/android/os/PowerManagerInternal.java7
-rw-r--r--core/java/android/os/Process.java7
-rw-r--r--core/java/android/os/RecoverySystem.java43
-rw-r--r--core/java/android/os/UserManager.java14
-rw-r--r--core/java/android/os/storage/DiskInfo.java6
-rw-r--r--core/java/android/os/storage/IMountService.java39
-rw-r--r--core/java/android/os/storage/StorageVolume.java13
-rw-r--r--core/java/android/preference/DialogPreference.java29
-rwxr-xr-x[-rw-r--r--]core/java/android/preference/MultiSelectListPreference.java17
-rw-r--r--core/java/android/preference/Preference.java10
-rw-r--r--core/java/android/preference/PreferenceFragment.java3
-rw-r--r--core/java/android/preference/PreferenceGroup.java9
-rw-r--r--core/java/android/preference/RingtonePreference.java28
-rw-r--r--core/java/android/provider/Browser.java6
-rw-r--r--core/java/android/provider/CalendarContract.java8
-rw-r--r--core/java/android/provider/CallLog.java4
-rw-r--r--core/java/android/provider/ContactsContract.java17
-rw-r--r--core/java/android/provider/Settings.java399
-rw-r--r--core/java/android/provider/ThemesContract.java731
-rw-r--r--core/java/android/service/dreams/DreamManagerInternal.java5
-rw-r--r--core/java/android/service/dreams/IDreamManager.aidl3
-rw-r--r--core/java/android/service/gesture/EdgeGestureManager.java205
-rw-r--r--core/java/android/service/gesture/IEdgeGestureActivationListener.aidl14
-rw-r--r--core/java/android/service/gesture/IEdgeGestureHostCallback.aidl20
-rw-r--r--core/java/android/service/gesture/IEdgeGestureService.aidl20
-rw-r--r--core/java/android/service/gesture/IGestureService.aidl11
-rw-r--r--core/java/android/service/gesture/package.html5
-rw-r--r--core/java/android/speech/SpeechRecognizer.java1
-rw-r--r--core/java/android/text/TextUtils.java12
-rwxr-xr-xcore/java/android/text/format/DateFormat.java29
-rw-r--r--core/java/android/text/method/MetaKeyKeyListener.java31
-rw-r--r--core/java/android/util/DisplayMetrics.java37
-rw-r--r--core/java/android/util/NativeTextHelper.java92
-rw-r--r--core/java/android/util/SeempLog.java758
-rw-r--r--core/java/android/view/Display.java3
-rw-r--r--core/java/android/view/DisplayInfo.java3
-rw-r--r--core/java/android/view/IWindowManager.aidl18
-rw-r--r--core/java/android/view/IWindowSession.aidl10
-rw-r--r--core/java/android/view/InputDevice.java13
-rw-r--r--core/java/android/view/KeyEvent.java6
-rw-r--r--core/java/android/view/SurfaceControl.java39
-rw-r--r--core/java/android/view/View.java9
-rw-r--r--core/java/android/view/ViewConfiguration.java2
-rw-r--r--core/java/android/view/Window.java35
-rw-r--r--core/java/android/view/WindowManager.java70
-rw-r--r--core/java/android/view/WindowManagerImpl.java2
-rw-r--r--core/java/android/view/WindowManagerPolicy.java11
-rw-r--r--core/java/android/view/WindowManagerPolicyControl.java451
-rw-r--r--core/java/android/webkit/WebChromeClient.java4
-rw-r--r--core/java/android/webkit/WebViewFactory.java17
-rw-r--r--core/java/android/widget/AbsSeekBar.java9
-rw-r--r--core/java/android/widget/FastScroller.java1
-rw-r--r--core/java/android/widget/OverScroller.java5
-rw-r--r--core/java/android/widget/RemoteViews.java12
-rw-r--r--core/java/android/widget/Scroller.java7
-rw-r--r--core/java/android/widget/TextClock.java1
-rw-r--r--core/java/android/widget/Toast.java14
-rw-r--r--core/java/com/android/internal/app/IAppOpsService.aidl8
-rw-r--r--core/java/com/android/internal/app/PlatLogoActivity.java9
-rw-r--r--core/java/com/android/internal/app/ResolverActivity.java16
-rw-r--r--core/java/com/android/internal/logging/MetricsConstants.java1
-rw-r--r--core/java/com/android/internal/os/DeviceKeyHandler.java26
-rw-r--r--core/java/com/android/internal/os/ZygoteConnection.java10
-rw-r--r--core/java/com/android/internal/policy/PhoneWindow.java260
-rw-r--r--core/java/com/android/internal/util/cm/ActionUtils.java149
-rw-r--r--core/java/com/android/internal/util/cm/ImageUtils.java332
-rw-r--r--core/java/com/android/internal/util/cm/PowerMenuConstants.java50
-rw-r--r--core/java/com/android/internal/util/cm/SpamFilter.java65
-rw-r--r--core/java/com/android/internal/util/cm/palette/ColorCutQuantizer.java449
-rw-r--r--core/java/com/android/internal/util/cm/palette/ColorHistogram.java127
-rw-r--r--core/java/com/android/internal/util/cm/palette/ColorUtils.java232
-rw-r--r--core/java/com/android/internal/util/cm/palette/Palette.java688
-rw-r--r--core/java/com/android/internal/util/gesture/EdgeGesturePosition.java42
-rw-r--r--core/java/com/android/internal/util/gesture/EdgeServiceConstants.java82
-rw-r--r--core/java/com/android/internal/view/RotationPolicy.java46
-rw-r--r--core/java/com/android/internal/widget/ILockSettings.aidl1
-rw-r--r--core/java/com/android/internal/widget/LockPatternUtils.java11
-rw-r--r--core/java/com/android/server/net/BaseNetworkObserver.java5
-rw-r--r--core/java/org/codeaurora/camera/Android.mk30
-rw-r--r--core/java/org/codeaurora/camera/ExtendedFace.java211
-rw-r--r--core/java/org/codeaurora/camera/org.codeaurora.camera.xml35
-rw-r--r--core/jni/Android.mk1
-rw-r--r--core/jni/AndroidRuntime.cpp2
-rw-r--r--core/jni/android/opengl/util.cpp4
-rw-r--r--core/jni/android_hardware_Camera.cpp183
-rw-r--r--core/jni/android_media_AudioFormat.h32
-rw-r--r--core/jni/android_opengl_GLES20.cpp148
-rw-r--r--core/jni/android_util_AssetManager.cpp191
-rw-r--r--core/jni/android_util_Binder.cpp2
-rw-r--r--core/jni/android_util_Process.cpp37
-rw-r--r--core/jni/android_util_SeempLog.cpp210
-rw-r--r--core/jni/android_view_SurfaceControl.cpp41
-rw-r--r--core/jni/com_android_internal_content_NativeLibraryHelper.cpp47
-rw-r--r--core/jni/com_android_internal_os_Zygote.cpp4
-rw-r--r--core/res/AndroidManifest.xml139
-rw-r--r--core/res/res/anim/last_app_in.xml41
-rw-r--r--core/res/res/anim/last_app_out.xml41
-rw-r--r--core/res/res/anim/lock_screen_wallpaper_exit_noop.xml32
-rw-r--r--core/res/res/drawable-hdpi/ic_launcher_android.pngbin6870 -> 3418 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_lock_power_reboot_alpha.pngbin0 -> 1645 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_lock_profile_alpha.pngbin0 -> 3919 bytes
-rw-r--r--core/res/res/drawable-hdpi/perm_group_security.pngbin0 -> 1554 bytes
-rw-r--r--core/res/res/drawable-hdpi/stat_sys_upload_anim1.pngbin681 -> 634 bytes
-rw-r--r--core/res/res/drawable-hdpi/stat_sys_upload_anim2.pngbin634 -> 681 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_launcher_android.pngbin3779 -> 2206 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_lock_power_reboot_alpha.pngbin0 -> 3374 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_lock_profile_alpha.pngbin0 -> 3517 bytes
-rw-r--r--core/res/res/drawable-mdpi/perm_group_security.pngbin0 -> 1277 bytes
-rw-r--r--core/res/res/drawable-mdpi/stat_sys_upload_anim1.pngbin577 -> 545 bytes
-rw-r--r--core/res/res/drawable-mdpi/stat_sys_upload_anim2.pngbin545 -> 577 bytes
-rw-r--r--core/res/res/drawable-nodpi/platlogo_cm.xml55
-rw-r--r--core/res/res/drawable-nodpi/stat_sys_adb.xml41
-rw-r--r--core/res/res/drawable-xhdpi/ic_launcher_android.pngbin11082 -> 4842 bytes
-rw-r--r--core/res/res/drawable-xhdpi/ic_lock_power_reboot_alpha.pngbin0 -> 1558 bytes
-rw-r--r--core/res/res/drawable-xhdpi/ic_lock_profile_alpha.pngbin0 -> 4208 bytes
-rw-r--r--core/res/res/drawable-xhdpi/perm_group_security.pngbin0 -> 1633 bytes
-rw-r--r--core/res/res/drawable-xhdpi/stat_sys_upload_anim1.pngbin814 -> 759 bytes
-rw-r--r--core/res/res/drawable-xhdpi/stat_sys_upload_anim2.pngbin759 -> 814 bytes
-rw-r--r--core/res/res/drawable-xxhdpi/ic_launcher_android.pngbin0 -> 7718 bytes
-rw-r--r--core/res/res/drawable-xxhdpi/ic_lock_power_reboot_alpha.pngbin0 -> 17728 bytes
-rw-r--r--core/res/res/drawable-xxhdpi/ic_lock_profile_alpha.pngbin0 -> 2019 bytes
-rw-r--r--core/res/res/drawable-xxhdpi/perm_group_security.pngbin0 -> 1761 bytes
-rwxr-xr-xcore/res/res/drawable-xxhdpi/stat_sys_upload_anim1.pngbin641 -> 624 bytes
-rwxr-xr-xcore/res/res/drawable-xxhdpi/stat_sys_upload_anim2.pngbin624 -> 641 bytes
-rw-r--r--core/res/res/drawable-xxxhdpi/ic_launcher_android.pngbin0 -> 10486 bytes
-rw-r--r--core/res/res/drawable/ic_lock_lock.xml2
-rw-r--r--core/res/res/drawable/ic_lock_power_reboot.xml33
-rw-r--r--core/res/res/drawable/ic_lock_profile.xml19
-rw-r--r--core/res/res/drawable/ic_lock_screenshot.xml27
-rw-r--r--core/res/res/drawable/ic_lock_settings.xml27
-rw-r--r--core/res/res/drawable/ic_lock_user.xml27
-rw-r--r--core/res/res/drawable/ic_zen_important.xml25
-rw-r--r--core/res/res/drawable/ic_zen_none.xml25
-rw-r--r--core/res/res/drawable/progress_large.xml4
-rw-r--r--core/res/res/drawable/progress_large_white.xml4
-rw-r--r--core/res/res/drawable/progress_medium.xml4
-rw-r--r--core/res/res/drawable/progress_medium_white.xml4
-rw-r--r--core/res/res/drawable/progress_small.xml4
-rw-r--r--core/res/res/drawable/progress_small_titlebar.xml4
-rw-r--r--core/res/res/drawable/progress_small_white.xml4
-rw-r--r--core/res/res/drawable/search_spinner.xml4
-rw-r--r--core/res/res/drawable/stat_notify_privacy_guard.xml11
-rw-r--r--core/res/res/layout/app_permission_item.xml2
-rw-r--r--core/res/res/layout/chooser_grid.xml6
-rw-r--r--core/res/res/layout/global_actions_silent_mode.xml38
-rw-r--r--core/res/res/layout/immersive_mode_cling.xml10
-rw-r--r--core/res/res/layout/notification_material_action.xml2
-rw-r--r--core/res/res/layout/notification_template_material_big_picture.xml2
-rw-r--r--core/res/res/layout/permission_confirmation_dialog.xml69
-rw-r--r--core/res/res/layout/preference_list_fragment.xml1
-rw-r--r--core/res/res/layout/resolver_different_item_header.xml3
-rw-r--r--core/res/res/layout/resolver_list.xml7
-rw-r--r--core/res/res/layout/resolver_list_with_default.xml15
-rw-r--r--core/res/res/layout/transient_notification.xml19
-rw-r--r--core/res/res/values-ast-rES/donottranslate-maps.xml26
-rw-r--r--core/res/res/values-ku-rIQ/donottranslate-maps.xml26
-rw-r--r--core/res/res/values-lb-rLU/donottranslate-maps.xml26
-rw-r--r--core/res/res/values-mcc204-mnc02/config.xml25
-rw-r--r--core/res/res/values-mcc214-mnc32/config.xml25
-rw-r--r--core/res/res/values-mcc219-mnc02/config.xml3
-rw-r--r--core/res/res/values-mcc222-mnc07/config.xml25
-rw-r--r--core/res/res/values-mcc232-mnc03/config.xml25
-rw-r--r--core/res/res/values-mcc232-mnc05/config.xml25
-rw-r--r--core/res/res/values-mcc232-mnc10/config.xml25
-rw-r--r--core/res/res/values-mcc232-mnc11/config.xml25
-rw-r--r--core/res/res/values-mcc232-mnc12/config.xml26
-rw-r--r--core/res/res/values-mcc234-mnc01/config.xml25
-rw-r--r--core/res/res/values-mcc240-mnc10/config.xml26
-rw-r--r--core/res/res/values-mcc244-mnc21/config.xml25
-rw-r--r--core/res/res/values-mcc260-mnc06/config.xml27
-rw-r--r--core/res/res/values-mcc268-mnc04/config.xml25
-rw-r--r--core/res/res/values-mcc268-mnc07/config.xml25
-rw-r--r--core/res/res/values-mcc272-mnc05/config.xml25
-rw-r--r--core/res/res/values-mcc272-mnc11/config.xml25
-rwxr-xr-xcore/res/res/values-mcc310-mnc004/config.xml7
-rw-r--r--core/res/res/values-mcc310-mnc008/config.xml33
-rw-r--r--core/res/res/values-mcc310-mnc009/config.xml33
-rwxr-xr-xcore/res/res/values-mcc311-mnc480/config.xml6
-rw-r--r--core/res/res/values-mcc404-mnc55/config.xml25
-rw-r--r--core/res/res/values-zh-rCN/strings.xml7
-rw-r--r--core/res/res/values-zh-rHK/strings.xml4
-rw-r--r--core/res/res/values/attrs.xml3
-rw-r--r--core/res/res/values/attrs_manifest.xml5
-rw-r--r--core/res/res/values/bools.xml4
-rw-r--r--core/res/res/values/cm_arrays.xml191
-rw-r--r--core/res/res/values/cm_colors.xml10
-rw-r--r--core/res/res/values/cm_strings.xml209
-rw-r--r--core/res/res/values/cm_symbols.xml101
-rw-r--r--core/res/res/values/config.xml242
-rw-r--r--core/res/res/values/customize.xml36
-rw-r--r--core/res/res/values/dimens.xml13
-rw-r--r--core/res/res/values/qcom_strings.xml23
-rwxr-xr-xcore/res/res/values/qcom_symbols.xml42
-rw-r--r--core/res/res/values/strings.xml18
-rw-r--r--core/res/res/values/symbols.xml91
-rw-r--r--core/res/res/xml/sms_short_codes.xml3
-rw-r--r--core/tests/coretests/src/android/content/pm/PackageManagerTests.java5
-rw-r--r--data/sounds/AllAudio.mk151
-rw-r--r--data/sounds/AudioPackage10.mk1
-rw-r--r--data/sounds/AudioPackage11.mk1
-rw-r--r--data/sounds/AudioPackage6.mk1
-rw-r--r--data/sounds/AudioPackage7.mk5
-rw-r--r--data/sounds/AudioPackage7alt.mk1
-rw-r--r--data/sounds/AudioPackage8.mk6
-rw-r--r--data/sounds/AudioPackage9.mk1
-rw-r--r--data/sounds/Ring_Digital_02.oggbin21007 -> 23084 bytes
-rw-r--r--data/sounds/alarms/ogg/Fermium.oggbin117227 -> 0 bytes
-rw-r--r--data/sounds/alarms/ogg/Hassium.oggbin147068 -> 0 bytes
-rw-r--r--data/sounds/alarms/ogg/Nobelium.oggbin176792 -> 0 bytes
-rw-r--r--data/sounds/alarms/ogg/Plutonium.oggbin103252 -> 0 bytes
-rw-r--r--data/sounds/alarms/ogg/Promethium.oggbin112676 -> 0 bytes
-rw-r--r--data/sounds/notifications/ogg/Tejat.oggbin15866 -> 0 bytes
-rw-r--r--data/sounds/notifications/ogg/Tejat_proc48.oggbin16804 -> 0 bytes
-rw-r--r--data/sounds/ringtones/boosted/Andromeda.oggbin0 -> 32226 bytes
-rw-r--r--data/sounds/ringtones/boosted/Aquila.oggbin0 -> 27984 bytes
-rw-r--r--data/sounds/ringtones/boosted/ArgoNavis.oggbin0 -> 110271 bytes
-rw-r--r--data/sounds/ringtones/boosted/Atria.oggbin0 -> 114813 bytes
-rw-r--r--data/sounds/ringtones/boosted/BOOTES.oggbin0 -> 27490 bytes
-rw-r--r--data/sounds/ringtones/boosted/Backroad.oggbin0 -> 42934 bytes
-rw-r--r--data/sounds/ringtones/boosted/BeatPlucker.oggbin0 -> 42453 bytes
-rw-r--r--data/sounds/ringtones/boosted/BentleyDubs.oggbin0 -> 41734 bytes
-rw-r--r--data/sounds/ringtones/boosted/Big_Easy.oggbin0 -> 51996 bytes
-rw-r--r--data/sounds/ringtones/boosted/BirdLoop.oggbin0 -> 64319 bytes
-rw-r--r--data/sounds/ringtones/boosted/Bollywood.oggbin0 -> 48634 bytes
-rw-r--r--data/sounds/ringtones/boosted/BussaMove.oggbin0 -> 56058 bytes
-rw-r--r--data/sounds/ringtones/boosted/CASSIOPEIA.oggbin0 -> 39017 bytes
-rw-r--r--data/sounds/ringtones/boosted/Cairo.oggbin0 -> 40518 bytes
-rw-r--r--data/sounds/ringtones/boosted/Callisto.oggbin0 -> 199132 bytes
-rw-r--r--data/sounds/ringtones/boosted/Calypso_Steel.oggbin0 -> 43574 bytes
-rw-r--r--data/sounds/ringtones/boosted/CanisMajor.oggbin0 -> 29708 bytes
-rw-r--r--data/sounds/ringtones/boosted/CaribbeanIce.oggbin0 -> 45530 bytes
-rw-r--r--data/sounds/ringtones/boosted/Carina.oggbin0 -> 16831 bytes
-rw-r--r--data/sounds/ringtones/boosted/Centaurus.oggbin0 -> 35438 bytes
-rw-r--r--data/sounds/ringtones/boosted/Champagne_Edition.oggbin0 -> 44115 bytes
-rw-r--r--data/sounds/ringtones/boosted/Club_Cubano.oggbin0 -> 43424 bytes
-rw-r--r--data/sounds/ringtones/boosted/CrayonRock.oggbin0 -> 47044 bytes
-rw-r--r--data/sounds/ringtones/boosted/CrazyDream.oggbin0 -> 330530 bytes
-rw-r--r--data/sounds/ringtones/boosted/CurveBall.oggbin0 -> 46713 bytes
-rw-r--r--data/sounds/ringtones/boosted/Cygnus.oggbin0 -> 34853 bytes
-rw-r--r--data/sounds/ringtones/boosted/DancinFool.oggbin0 -> 66666 bytes
-rw-r--r--data/sounds/ringtones/boosted/Dione.oggbin0 -> 176464 bytes
-rw-r--r--data/sounds/ringtones/boosted/DonMessWivIt.oggbin0 -> 59273 bytes
-rw-r--r--data/sounds/ringtones/boosted/Draco.oggbin0 -> 39586 bytes
-rw-r--r--data/sounds/ringtones/boosted/DreamTheme.oggbin0 -> 240708 bytes
-rw-r--r--data/sounds/ringtones/boosted/Eastern_Sky.oggbin0 -> 61338 bytes
-rw-r--r--data/sounds/ringtones/boosted/Enter_the_Nexus.oggbin0 -> 72388 bytes
-rw-r--r--data/sounds/ringtones/boosted/Eridani.oggbin0 -> 40739 bytes
-rw-r--r--data/sounds/ringtones/boosted/EtherShake.oggbin0 -> 45162 bytes
-rw-r--r--data/sounds/ringtones/boosted/FreeFlight.oggbin0 -> 115787 bytes
-rw-r--r--data/sounds/ringtones/boosted/FriendlyGhost.oggbin0 -> 56574 bytes
-rw-r--r--data/sounds/ringtones/boosted/Funk_Yall.oggbin0 -> 49568 bytes
-rw-r--r--data/sounds/ringtones/boosted/GameOverGuitar.oggbin0 -> 58236 bytes
-rw-r--r--data/sounds/ringtones/boosted/Ganymede.oggbin0 -> 72422 bytes
-rw-r--r--data/sounds/ringtones/boosted/Gimme_Mo_Town.oggbin0 -> 47052 bytes
-rw-r--r--data/sounds/ringtones/boosted/Girtab.oggbin0 -> 45473 bytes
-rw-r--r--data/sounds/ringtones/boosted/Glacial_Groove.oggbin0 -> 54179 bytes
-rw-r--r--data/sounds/ringtones/boosted/Growl.oggbin0 -> 66830 bytes
-rw-r--r--data/sounds/ringtones/boosted/HalfwayHome.oggbin0 -> 76373 bytes
-rw-r--r--data/sounds/ringtones/boosted/Hydra.oggbin0 -> 30862 bytes
-rw-r--r--data/sounds/ringtones/boosted/InsertCoin.oggbin0 -> 23013 bytes
-rw-r--r--data/sounds/ringtones/boosted/Kuma.oggbin0 -> 177560 bytes
-rw-r--r--data/sounds/ringtones/boosted/LoopyLounge.oggbin0 -> 52891 bytes
-rw-r--r--data/sounds/ringtones/boosted/LoveFlute.oggbin0 -> 49109 bytes
-rw-r--r--data/sounds/ringtones/boosted/Luna.oggbin0 -> 58928 bytes
-rw-r--r--data/sounds/ringtones/boosted/Lyra.oggbin0 -> 54307 bytes
-rw-r--r--data/sounds/ringtones/boosted/Machina.oggbin0 -> 44844 bytes
-rw-r--r--data/sounds/ringtones/boosted/MidEvilJaunt.oggbin0 -> 44691 bytes
-rw-r--r--data/sounds/ringtones/boosted/MildlyAlarming.oggbin0 -> 40270 bytes
-rw-r--r--data/sounds/ringtones/boosted/Nairobi.oggbin0 -> 44799 bytes
-rw-r--r--data/sounds/ringtones/boosted/Nassau.oggbin0 -> 51368 bytes
-rw-r--r--data/sounds/ringtones/boosted/NewPlayer.oggbin0 -> 21735 bytes
-rw-r--r--data/sounds/ringtones/boosted/No_Limits.oggbin0 -> 41815 bytes
-rw-r--r--data/sounds/ringtones/boosted/Noises2.oggbin0 -> 47466 bytes
-rw-r--r--data/sounds/ringtones/boosted/Noises3.oggbin0 -> 34872 bytes
-rw-r--r--data/sounds/ringtones/boosted/Oberon.oggbin0 -> 225583 bytes
-rw-r--r--data/sounds/ringtones/boosted/OrganDub.oggbin0 -> 43489 bytes
-rw-r--r--data/sounds/ringtones/boosted/Orion.oggbin0 -> 59789 bytes
-rw-r--r--data/sounds/ringtones/boosted/Paradise_Island.oggbin0 -> 44273 bytes
-rw-r--r--data/sounds/ringtones/boosted/Pegasus.oggbin0 -> 105036 bytes
-rw-r--r--data/sounds/ringtones/boosted/Perseus.oggbin0 -> 134971 bytes
-rw-r--r--data/sounds/ringtones/boosted/Phobos.oggbin0 -> 60295 bytes
-rw-r--r--data/sounds/ringtones/boosted/Playa.oggbin0 -> 63529 bytes
-rw-r--r--data/sounds/ringtones/boosted/Pyxis.oggbin0 -> 312897 bytes
-rw-r--r--data/sounds/ringtones/boosted/Rasalas.oggbin0 -> 188609 bytes
-rw-r--r--data/sounds/ringtones/boosted/Revelation.oggbin0 -> 57781 bytes
-rw-r--r--data/sounds/ringtones/boosted/Rigel.oggbin0 -> 35914 bytes
-rw-r--r--data/sounds/ringtones/boosted/Ring_Classic_02.oggbin0 -> 58622 bytes
-rw-r--r--data/sounds/ringtones/boosted/Ring_Digital_02.oggbin0 -> 22135 bytes
-rw-r--r--data/sounds/ringtones/boosted/Ring_Synth_02.oggbin0 -> 56839 bytes
-rw-r--r--data/sounds/ringtones/boosted/Ring_Synth_04.oggbin0 -> 47616 bytes
-rw-r--r--data/sounds/ringtones/boosted/Road_Trip.oggbin0 -> 68361 bytes
-rw-r--r--data/sounds/ringtones/boosted/RomancingTheTone.oggbin0 -> 50717 bytes
-rw-r--r--data/sounds/ringtones/boosted/Safari.oggbin0 -> 44597 bytes
-rw-r--r--data/sounds/ringtones/boosted/Savannah.oggbin0 -> 46778 bytes
-rw-r--r--data/sounds/ringtones/boosted/Scarabaeus.oggbin0 -> 117105 bytes
-rw-r--r--data/sounds/ringtones/boosted/Sceptrum.oggbin0 -> 345388 bytes
-rw-r--r--data/sounds/ringtones/boosted/Sedna.oggbin0 -> 101878 bytes
-rw-r--r--data/sounds/ringtones/boosted/Seville.oggbin0 -> 51230 bytes
-rw-r--r--data/sounds/ringtones/boosted/Shes_All_That.oggbin0 -> 44712 bytes
-rw-r--r--data/sounds/ringtones/boosted/SilkyWay.oggbin0 -> 44214 bytes
-rw-r--r--data/sounds/ringtones/boosted/SitarVsSitar.oggbin0 -> 42256 bytes
-rw-r--r--data/sounds/ringtones/boosted/Solarium.oggbin0 -> 105357 bytes
-rw-r--r--data/sounds/ringtones/boosted/SpringyJalopy.oggbin0 -> 43939 bytes
-rw-r--r--data/sounds/ringtones/boosted/Steppin_Out.oggbin0 -> 45934 bytes
-rw-r--r--data/sounds/ringtones/boosted/Terminated.oggbin0 -> 54774 bytes
-rw-r--r--data/sounds/ringtones/boosted/Testudo.oggbin0 -> 92599 bytes
-rw-r--r--data/sounds/ringtones/boosted/Themos.oggbin0 -> 185452 bytes
-rw-r--r--data/sounds/ringtones/boosted/Third_Eye.oggbin0 -> 43181 bytes
-rw-r--r--data/sounds/ringtones/boosted/Thunderfoot.oggbin0 -> 52633 bytes
-rw-r--r--data/sounds/ringtones/boosted/Titania.oggbin0 -> 340948 bytes
-rw-r--r--data/sounds/ringtones/boosted/Triton.oggbin0 -> 236564 bytes
-rw-r--r--data/sounds/ringtones/boosted/TwirlAway.oggbin0 -> 39204 bytes
-rw-r--r--data/sounds/ringtones/boosted/Umbriel.oggbin0 -> 127862 bytes
-rw-r--r--data/sounds/ringtones/boosted/UrsaMinor.oggbin0 -> 186873 bytes
-rw-r--r--data/sounds/ringtones/boosted/VeryAlarmed.oggbin0 -> 47201 bytes
-rw-r--r--data/sounds/ringtones/boosted/Vespa.oggbin0 -> 27836 bytes
-rw-r--r--data/sounds/ringtones/boosted/World.oggbin0 -> 42440 bytes
-rw-r--r--data/sounds/ringtones/boosted/Zeta.oggbin0 -> 95474 bytes
-rw-r--r--graphics/java/android/graphics/Bitmap.java1
-rw-r--r--graphics/java/android/graphics/FontListConverter.java220
-rw-r--r--graphics/java/android/graphics/FontListParser.java79
-rw-r--r--graphics/java/android/graphics/LegacyFontListParser.java187
-rw-r--r--graphics/java/android/graphics/Typeface.java183
-rw-r--r--graphics/java/android/graphics/drawable/Drawable.java2
-rw-r--r--graphics/tests/localtests/Android.mk18
-rw-r--r--graphics/tests/localtests/src/android/graphics/FontListConverterTest.java280
-rw-r--r--graphics/tests/localtests/src/android/graphics/TypefaceTestSuite.java27
-rw-r--r--include/SeempLog.h51
-rw-r--r--include/androidfw/AssetManager.h39
-rw-r--r--include/androidfw/AttributeFinder.h7
-rw-r--r--include/androidfw/ResourceTypes.h24
-rw-r--r--include/private/time_genoff.h87
-rw-r--r--include/storage/IMountService.h1
-rw-r--r--libs/androidfw/AssetManager.cpp402
-rw-r--r--libs/androidfw/ResourceTypes.cpp467
-rw-r--r--libs/androidfw/tests/Android.mk4
-rw-r--r--libs/androidfw/tests/Idmap_test.cpp2
-rw-r--r--libs/androidfw/tests/PackageIdOverride_test.cpp60
-rw-r--r--libs/androidfw/tests/ThemesBags_test.cpp169
-rw-r--r--libs/androidfw/tests/ThemesIdmap_test.cpp133
-rw-r--r--libs/androidfw/tests/data/app/R.h9
-rw-r--r--libs/androidfw/tests/data/app/app_arsc.h101
-rw-r--r--libs/androidfw/tests/data/app/res/values/values.xml15
-rw-r--r--libs/androidfw/tests/data/bags/AndroidManifest.xml21
-rw-r--r--libs/androidfw/tests/data/bags/R.h26
-rw-r--r--libs/androidfw/tests/data/bags/bags_arsc.h88
-rwxr-xr-xlibs/androidfw/tests/data/bags/build6
-rw-r--r--libs/androidfw/tests/data/bags/res/values/values.xml24
-rw-r--r--libs/androidfw/tests/data/basic/basic_arsc.h203
-rw-r--r--libs/androidfw/tests/data/basic/res/drawable/drawable1.pngbin0 -> 69 bytes
-rw-r--r--libs/androidfw/tests/data/basic/res/values/values.xml3
-rw-r--r--libs/androidfw/tests/data/cm/app/AndroidManifest.xml19
-rw-r--r--libs/androidfw/tests/data/cm/app/R.h31
-rw-r--r--libs/androidfw/tests/data/cm/app/app_arsc.h91
-rwxr-xr-xlibs/androidfw/tests/data/cm/app/build6
-rw-r--r--libs/androidfw/tests/data/cm/app/res/values/values.xml22
-rw-r--r--libs/androidfw/tests/data/cm/bags/AndroidManifest.xml21
-rw-r--r--libs/androidfw/tests/data/cm/bags/R.h26
-rw-r--r--libs/androidfw/tests/data/cm/bags/bags_arsc.h88
-rwxr-xr-xlibs/androidfw/tests/data/cm/bags/build6
-rw-r--r--libs/androidfw/tests/data/cm/bags/res/values/values.xml24
-rw-r--r--libs/androidfw/tests/data/cm/basic/AndroidManifest.xml21
-rw-r--r--libs/androidfw/tests/data/cm/basic/R.h68
-rw-r--r--libs/androidfw/tests/data/cm/basic/basic_arsc.h194
-rwxr-xr-xlibs/androidfw/tests/data/cm/basic/build11
-rw-r--r--libs/androidfw/tests/data/cm/basic/res/drawable/drawable1.pngbin0 -> 69 bytes
-rw-r--r--libs/androidfw/tests/data/cm/basic/res/layout-fr-sw600dp/main.xml3
-rw-r--r--libs/androidfw/tests/data/cm/basic/res/layout/main.xml3
-rw-r--r--libs/androidfw/tests/data/cm/basic/res/values-de/values.xml5
-rw-r--r--libs/androidfw/tests/data/cm/basic/res/values-fr/values.xml5
-rw-r--r--libs/androidfw/tests/data/cm/basic/res/values-sv/values.xml4
-rw-r--r--libs/androidfw/tests/data/cm/basic/res/values/values.xml29
-rw-r--r--libs/androidfw/tests/data/cm/basic/split_de_fr_arsc.h92
-rw-r--r--libs/androidfw/tests/data/cm/overlay/AndroidManifest.xml21
-rwxr-xr-xlibs/androidfw/tests/data/cm/overlay/build6
-rw-r--r--libs/androidfw/tests/data/cm/overlay/overlay_arsc.h103
-rw-r--r--libs/androidfw/tests/data/cm/overlay/res/drawable/drawable1.pngbin0 -> 69 bytes
-rw-r--r--libs/androidfw/tests/data/cm/overlay/res/values/values.xml12
-rw-r--r--libs/androidfw/tests/data/cm/override/AndroidManifest.xml21
-rw-r--r--libs/androidfw/tests/data/cm/override/R.h16
-rwxr-xr-xlibs/androidfw/tests/data/cm/override/build6
-rw-r--r--libs/androidfw/tests/data/cm/override/override_arsc.h53
-rw-r--r--libs/androidfw/tests/data/cm/override/res/values/values.xml4
-rw-r--r--libs/androidfw/tests/data/cm/system/AndroidManifest.xml19
-rw-r--r--libs/androidfw/tests/data/cm/system/R.h26
-rwxr-xr-xlibs/androidfw/tests/data/cm/system/build6
-rw-r--r--libs/androidfw/tests/data/cm/system/res/values/filler.xml168
-rw-r--r--libs/androidfw/tests/data/cm/system/res/values/themes.xml21
-rw-r--r--libs/androidfw/tests/data/cm/system/system_arsc.h538
-rw-r--r--libs/androidfw/tests/data/overlay/overlay_arsc.h86
-rw-r--r--libs/androidfw/tests/data/overlay/res/drawable/drawable1.pngbin0 -> 69 bytes
-rw-r--r--libs/androidfw/tests/data/overlay/res/values/values.xml4
-rw-r--r--libs/androidfw/tests/data/override/AndroidManifest.xml21
-rw-r--r--libs/androidfw/tests/data/override/R.h16
-rwxr-xr-xlibs/androidfw/tests/data/override/build6
-rw-r--r--libs/androidfw/tests/data/override/override_arsc.h53
-rw-r--r--libs/androidfw/tests/data/override/res/values/values.xml4
-rw-r--r--libs/androidfw/tests/data/system/R.h7
-rw-r--r--libs/androidfw/tests/data/system/res/values/filler.xml168
-rw-r--r--libs/androidfw/tests/data/system/res/values/themes.xml8
-rw-r--r--libs/androidfw/tests/data/system/system_arsc.h525
-rw-r--r--libs/hwui/FontRenderer.cpp8
-rw-r--r--libs/hwui/FontRenderer.h2
-rw-r--r--libs/hwui/OpenGLRenderer.cpp16
-rw-r--r--libs/hwui/PathCache.cpp7
-rw-r--r--libs/hwui/PathCache.h1
-rw-r--r--libs/hwui/SpotShadow.cpp2
-rw-r--r--libs/hwui/font/Font.cpp2
-rw-r--r--libs/storage/IMountService.cpp18
-rw-r--r--location/java/android/location/GeoFenceParams.aidl23
-rw-r--r--location/java/android/location/GeoFenceParams.java132
-rw-r--r--[-rwxr-xr-x]location/java/android/location/IGeoFenceListener.aidl (renamed from core/java/android/bluetooth/IBluetoothProfileServiceConnection.aidl)20
-rw-r--r--location/java/android/location/IGeoFencer.aidl33
-rw-r--r--location/java/android/location/LocationManager.java17
-rw-r--r--media/java/android/media/AudioFormat.java64
-rw-r--r--media/java/android/media/AudioManager.java101
-rw-r--r--media/java/android/media/AudioRecord.java30
-rw-r--r--media/java/android/media/AudioSystem.java8
-rw-r--r--media/java/android/media/CamcorderProfile.java75
-rw-r--r--media/java/android/media/ClosedCaptionRenderer.java6
-rw-r--r--media/java/android/media/EncoderCapabilities.java9
-rw-r--r--media/java/android/media/IAudioService.aidl17
-rw-r--r--media/java/android/media/IRemoteControlClient.aidl5
-rw-r--r--media/java/android/media/MediaCodecInfo.java7
-rw-r--r--media/java/android/media/MediaFile.java32
-rw-r--r--media/java/android/media/MediaHTTPConnection.java55
-rw-r--r--media/java/android/media/MediaMetadataEditor.java4
-rw-r--r--media/java/android/media/MediaPlayer.java17
-rw-r--r--media/java/android/media/MediaRecorder.java24
-rw-r--r--media/java/android/media/MediaScanner.java16
-rw-r--r--media/java/android/media/RemoteControlClient.java203
-rw-r--r--media/java/android/media/RemoteController.java186
-rw-r--r--media/java/android/media/RingtoneManager.java10
-rw-r--r--media/java/android/media/ToneGenerator.java13
-rw-r--r--media/java/android/media/session/ISession.aidl4
-rw-r--r--media/java/android/media/session/ISessionCallback.aidl3
-rw-r--r--media/java/android/media/session/ISessionController.aidl3
-rw-r--r--media/java/android/media/session/ISessionControllerCallback.aidl4
-rw-r--r--media/java/android/media/session/MediaController.java114
-rw-r--r--media/java/android/media/session/MediaSession.java141
-rw-r--r--media/java/android/media/session/MediaSessionLegacyHelper.java21
-rw-r--r--media/java/android/mtp/MtpServer.java5
-rw-r--r--media/jni/android_media_MediaPlayer.cpp202
-rw-r--r--media/jni/android_media_MediaProfiles.cpp17
-rw-r--r--media/jni/android_media_MediaRecorder.cpp14
-rw-r--r--media/jni/android_mtp_MtpServer.cpp13
-rw-r--r--media/jni/audioeffect/android_media_AudioEffect.cpp9
-rw-r--r--media/jni/audioeffect/android_media_Visualizer.cpp1
-rw-r--r--obex/javax/obex/ClientOperation.java51
-rw-r--r--obex/javax/obex/ClientSession.java8
-rw-r--r--obex/javax/obex/ObexHelper.java28
-rw-r--r--obex/javax/obex/ObexSession.java2
-rw-r--r--obex/javax/obex/ServerOperation.java25
-rw-r--r--obex/javax/obex/ServerSession.java18
-rw-r--r--packages/CaptivePortalLogin/AndroidManifest.xml4
-rw-r--r--packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java37
-rw-r--r--packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java1
-rw-r--r--packages/DocumentsUI/res/layout/activity.xml2
-rw-r--r--packages/DocumentsUI/res/layout/item_doc_grid.xml6
-rw-r--r--packages/DocumentsUI/res/values/cm_colors.xml23
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java6
-rw-r--r--packages/Keyguard/Android.mk2
-rw-r--r--packages/Keyguard/res/values/strings.xml11
-rw-r--r--packages/Keyguard/src/com/android/keyguard/CarrierText.java108
-rw-r--r--packages/Keyguard/src/com/android/keyguard/KeyguardPINView.java38
-rw-r--r--packages/Keyguard/src/com/android/keyguard/KeyguardSimPinView.java93
-rw-r--r--packages/Keyguard/src/com/android/keyguard/KeyguardSimPukView.java7
-rw-r--r--packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java25
-rw-r--r--packages/Keyguard/src/com/android/keyguard/NumPadKey.java39
-rw-r--r--packages/PrintSpooler/res/values-zh-rCN/arrays.xml37
-rw-r--r--packages/PrintSpooler/src/com/android/printspooler/renderer/PdfManipulationService.java5
-rw-r--r--packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java16
-rw-r--r--packages/SettingsLib/res/drawable-hdpi/activities_icon.pngbin0 -> 2399 bytes
-rw-r--r--packages/SettingsLib/res/drawable-mdpi/activities_icon.pngbin0 -> 1702 bytes
-rw-r--r--packages/SettingsLib/res/drawable-xhdpi/activities_icon.pngbin0 -> 2999 bytes
-rw-r--r--packages/SettingsLib/res/drawable-xxhdpi/activities_icon.pngbin0 -> 4977 bytes
-rw-r--r--packages/SettingsLib/res/drawable-xxxhdpi/activities_icon.pngbin0 -> 7498 bytes
-rw-r--r--packages/SettingsLib/res/values/cm_dimens.xml19
-rw-r--r--packages/SettingsLib/res/values/cm_strings.xml26
-rw-r--r--packages/SettingsLib/res/values/strings.xml6
-rw-r--r--[-rwxr-xr-x]packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java34
-rwxr-xr-xpackages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpSinkProfile.java223
-rwxr-xr-x[-rw-r--r--]packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothDeviceFilter.java4
-rwxr-xr-xpackages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java2
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java27
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/DunServerProfile.java162
-rwxr-xr-x[-rw-r--r--]packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothAdapter.java4
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java57
-rwxr-xr-xpackages/SettingsLib/src/com/android/settingslib/bluetooth/PbapServerProfile.java9
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/cm/ShortcutPickHelper.java326
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java11
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java2
-rw-r--r--packages/SettingsProvider/Android.mk2
-rw-r--r--packages/SettingsProvider/res/values/defaults.xml19
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java233
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java41
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java5
-rw-r--r--packages/Shell/AndroidManifest.xml5
-rw-r--r--packages/Shell/res/values/cm_strings.xml20
-rw-r--r--packages/Shell/src/com/android/shell/BugreportReceiver.java15
-rw-r--r--packages/SystemUI/Android.mk7
-rw-r--r--packages/SystemUI/AndroidManifest.xml26
-rw-r--r--packages/SystemUI/AndroidManifest_cm.xml46
-rwxr-xr-xpackages/SystemUI/res/drawable-hdpi/ic_mini_settings.pngbin0 -> 192 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/ic_notification_overlay.9.pngbin749 -> 385 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/ic_sysbar_add.pngbin0 -> 536 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/ic_sysbar_add_land.pngbin0 -> 532 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/ic_sysbar_add_side.pngbin0 -> 992 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_side.pngbin0 -> 1300 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-hdpi/ic_sysbar_ime_left.pngbin0 -> 1284 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-hdpi/ic_sysbar_ime_right.pngbin0 -> 1307 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/ic_sysbar_menu_big.pngbin0 -> 744 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/ic_sysbar_menu_big_land.pngbin0 -> 744 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/ic_sysbar_recent_side.pngbin0 -> 1226 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/ic_sysbar_search.pngbin0 -> 1042 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/ic_sysbar_search_land.pngbin0 -> 1016 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/ic_sysbar_search_side.pngbin0 -> 1440 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_notify_image.pngbin846 -> 0 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_notify_image_error.pngbin1112 -> 0 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_data_idle_1x.pngbin0 -> 1699 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_data_idle_3g.pngbin0 -> 1732 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_data_idle_4g.pngbin0 -> 1698 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_data_idle_e.pngbin0 -> 1581 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_data_idle_g.pngbin0 -> 1599 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_data_idle_h.pngbin0 -> 1557 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_data_in_1x.pngbin0 -> 1804 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_data_in_3g.pngbin0 -> 1861 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_data_in_4g.pngbin0 -> 1793 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_data_in_e.pngbin0 -> 1752 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_data_in_g.pngbin0 -> 1760 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_data_in_h.pngbin0 -> 1742 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_data_inandout_4g.pngbin0 -> 1817 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_data_inandout_e.pngbin0 -> 1863 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_data_inandout_h.pngbin0 -> 1858 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_data_inout_1x.pngbin0 -> 1901 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_data_inout_3g.pngbin0 -> 1911 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_data_inout_g.pngbin0 -> 1874 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_data_out_1x.pngbin0 -> 1786 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_data_out_3g.pngbin0 -> 1891 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_data_out_4g.pngbin0 -> 1796 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_data_out_e.pngbin0 -> 1772 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_data_out_g.pngbin0 -> 1781 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_data_out_h.pngbin0 -> 1758 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_no_sim_1.pngbin0 -> 1142 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_0_fully_sim1_4g.pngbin0 -> 1418 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_0_fully_sim1_hp.pngbin0 -> 1156 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_0_fully_sim2_4g.pngbin0 -> 1423 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_0_fully_sim2_hp.pngbin0 -> 1157 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_0_sim1_4g.pngbin0 -> 1418 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_0_sim1_hp.pngbin0 -> 1156 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_0_sim2_4g.pngbin0 -> 1423 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_0_sim2_hp.pngbin0 -> 1157 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_1_fully_sim1_4g.pngbin0 -> 1441 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_1_fully_sim1_hp.pngbin0 -> 1190 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_1_fully_sim2_4g.pngbin0 -> 1447 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_1_fully_sim2_hp.pngbin0 -> 1192 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_1_sim1_4g.pngbin0 -> 1429 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_1_sim1_hp.pngbin0 -> 1177 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_1_sim2_4g.pngbin0 -> 1437 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_1_sim2_hp.pngbin0 -> 1180 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_2_fully_sim1_4g.pngbin0 -> 1435 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_2_fully_sim1_hp.pngbin0 -> 1189 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_2_fully_sim2_4g.pngbin0 -> 1441 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_2_fully_sim2_hp.pngbin0 -> 1190 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_2_sim1_4g.pngbin0 -> 1426 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_2_sim1_hp.pngbin0 -> 1179 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_2_sim2_4g.pngbin0 -> 1431 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_2_sim2_hp.pngbin0 -> 1178 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_3_fully_sim1_4g.pngbin0 -> 1425 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_3_fully_sim1_hp.pngbin0 -> 1176 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_3_fully_sim2_4g.pngbin0 -> 1425 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_3_fully_sim2_hp.pngbin0 -> 1180 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_3_sim1_4g.pngbin0 -> 1405 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_3_sim1_hp.pngbin0 -> 1167 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_3_sim2_4g.pngbin0 -> 1408 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_3_sim2_hp.pngbin0 -> 1170 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_4_fully_sim1_4g.pngbin0 -> 1420 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_4_fully_sim1_hp.pngbin0 -> 1144 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_4_fully_sim2_4g.pngbin0 -> 1426 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_4_fully_sim2_hp.pngbin0 -> 1144 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_4_sim1_4g.pngbin0 -> 1347 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_4_sim1_hp.pngbin0 -> 1142 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_4_sim2_4g.pngbin0 -> 1348 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_4_sim2_hp.pngbin0 -> 1147 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_2g.pngbin0 -> 1445 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_2g_default.pngbin0 -> 1645 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_2g_default_fully.pngbin0 -> 1645 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_2g_default_fully_roam.pngbin0 -> 1703 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_2g_default_roam.pngbin0 -> 1703 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_2g_fully.pngbin0 -> 1445 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_4g.pngbin0 -> 1372 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_4g_default.pngbin0 -> 1630 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_4g_default_fully.pngbin0 -> 1630 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_4g_default_fully_roam.pngbin0 -> 3356 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_4g_default_roam.pngbin0 -> 1497 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_4g_fully.pngbin0 -> 1372 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_default_fully_roam.pngbin0 -> 3333 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_default_roam.pngbin0 -> 3333 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_e.pngbin0 -> 1491 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_e_fully.pngbin0 -> 1491 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_e_fully_roam.pngbin0 -> 1566 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_e_roam.pngbin0 -> 1558 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_fully_sim1_4g.pngbin0 -> 1426 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_fully_sim1_hp.pngbin0 -> 1166 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_fully_sim2_4g.pngbin0 -> 1428 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_fully_sim2_hp.pngbin0 -> 1169 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_gsm.pngbin0 -> 1293 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_gsm_fully.pngbin0 -> 1293 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_sim1_4g.pngbin0 -> 1428 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_sim1_hp.pngbin0 -> 1166 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_sim2_4g.pngbin0 -> 1430 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_sim2_hp.pngbin0 -> 1169 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_2g.pngbin0 -> 1487 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_2g_default.pngbin0 -> 1817 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_2g_default_fully.pngbin0 -> 1717 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_2g_default_fully_roam.pngbin0 -> 1774 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_2g_default_roam.pngbin0 -> 1873 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_2g_fully.pngbin0 -> 1508 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_4g.pngbin0 -> 1415 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_4g_default.pngbin0 -> 1806 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_4g_default_fully.pngbin0 -> 1706 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_4g_default_fully_roam.pngbin0 -> 3420 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_4g_default_roam.pngbin0 -> 3509 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_4g_fully.pngbin0 -> 1417 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_default_fully_roam.pngbin0 -> 3401 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_default_roam.pngbin0 -> 3495 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_e.pngbin0 -> 1635 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_e_fully.pngbin0 -> 1556 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_e_fully_roam.pngbin0 -> 1622 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_e_roam.pngbin0 -> 1704 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_fully_sim1_4g.pngbin0 -> 1464 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_fully_sim1_hp.pngbin0 -> 1201 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_fully_sim2_4g.pngbin0 -> 1464 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_fully_sim2_hp.pngbin0 -> 1203 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_gsm.pngbin0 -> 1336 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_gsm_fully.pngbin0 -> 1334 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_sim1_4g.pngbin0 -> 1452 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_sim1_hp.pngbin0 -> 1189 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_sim2_4g.pngbin0 -> 1453 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_sim2_hp.pngbin0 -> 1190 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_2g.pngbin0 -> 1515 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_2g_default.pngbin0 -> 1919 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_2g_default_fully.pngbin0 -> 1765 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_2g_default_fully_roam.pngbin0 -> 1824 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_2g_default_roam.pngbin0 -> 1975 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_2g_fully.pngbin0 -> 1542 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_4g.pngbin0 -> 1459 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_4g_default.pngbin0 -> 1911 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_4g_default_fully.pngbin0 -> 1753 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_4g_default_fully_roam.pngbin0 -> 3482 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_4g_default_roam.pngbin0 -> 3648 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_4g_fully.pngbin0 -> 1470 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_default_fully_roam.pngbin0 -> 3460 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_default_roam.pngbin0 -> 3634 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_e.pngbin0 -> 1767 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_e_fully.pngbin0 -> 1605 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_e_fully_roam.pngbin0 -> 1677 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_e_roam.pngbin0 -> 1819 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_fully_sim1_4g.pngbin0 -> 1457 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_fully_sim1_hp.pngbin0 -> 1201 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_fully_sim2_4g.pngbin0 -> 1459 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_fully_sim2_hp.pngbin0 -> 1202 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_gsm.pngbin0 -> 1366 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_gsm_fully.pngbin0 -> 1379 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_sim1_4g.pngbin0 -> 1445 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_sim1_hp.pngbin0 -> 1189 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_sim2_4g.pngbin0 -> 1448 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_sim2_hp.pngbin0 -> 1191 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2g_in.pngbin0 -> 1276 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2g_inout.pngbin0 -> 1253 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2g_no.pngbin0 -> 1281 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2g_out.pngbin0 -> 1271 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_2g.pngbin0 -> 1538 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_2g_default.pngbin0 -> 1996 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_2g_default_fully.pngbin0 -> 1782 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_2g_default_fully_roam.pngbin0 -> 1840 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_2g_default_roam.pngbin0 -> 2059 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_2g_fully.pngbin0 -> 1583 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_4g.pngbin0 -> 1477 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_4g_default.pngbin0 -> 1983 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_4g_default_fully.pngbin0 -> 1772 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_4g_default_fully_roam.pngbin0 -> 3497 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_4g_default_roam.pngbin0 -> 3741 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_4g_fully.pngbin0 -> 1502 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_default_fully_roam.pngbin0 -> 3484 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_default_roam.pngbin0 -> 3726 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_e.pngbin0 -> 1833 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_e_fully.pngbin0 -> 1626 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_e_fully_roam.pngbin0 -> 1692 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_e_roam.pngbin0 -> 1894 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_fully_sim1_4g.pngbin0 -> 1444 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_fully_sim1_hp.pngbin0 -> 1184 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_fully_sim2_4g.pngbin0 -> 1447 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_fully_sim2_hp.pngbin0 -> 1188 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_gsm.pngbin0 -> 1394 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_gsm_fully.pngbin0 -> 1412 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_sim1_4g.pngbin0 -> 1428 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_sim1_hp.pngbin0 -> 1180 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_sim2_4g.pngbin0 -> 1433 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_sim2_hp.pngbin0 -> 1176 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_2g.pngbin0 -> 1555 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_2g_default.pngbin0 -> 2058 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_2g_default_fully.pngbin0 -> 1794 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_2g_default_fully_roam.pngbin0 -> 1855 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_2g_default_roam.pngbin0 -> 2125 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_2g_fully.pngbin0 -> 1564 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_4g.pngbin0 -> 1493 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_4g_default.pngbin0 -> 2049 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_4g_default_fully.pngbin0 -> 1781 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_4g_default_fully_roam.pngbin0 -> 3511 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_4g_default_roam.pngbin0 -> 1874 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_4g_fully.pngbin0 -> 1488 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_default_fully_roam.pngbin0 -> 3496 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_default_roam.pngbin0 -> 3693 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_e.pngbin0 -> 1890 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_e_fully.pngbin0 -> 1632 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_e_fully_roam.pngbin0 -> 1704 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_e_roam.pngbin0 -> 1952 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_fully_sim1_4g.pngbin0 -> 1412 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_fully_sim1_hp.pngbin0 -> 1144 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_fully_sim2_4g.pngbin0 -> 1415 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_fully_sim2_hp.pngbin0 -> 1152 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_gsm.pngbin0 -> 1410 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_gsm_fully.pngbin0 -> 1405 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_sim1_4g.pngbin0 -> 1381 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_sim1_hp.pngbin0 -> 1155 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_sim2_4g.pngbin0 -> 1377 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_sim2_hp.pngbin0 -> 1152 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-hdpi/stat_sys_signal_4g_in.pngbin0 -> 1269 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-hdpi/stat_sys_signal_4g_inout.pngbin0 -> 1247 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-hdpi/stat_sys_signal_4g_no.pngbin0 -> 1276 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-hdpi/stat_sys_signal_4g_out.pngbin0 -> 1273 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_signal_hp_in.pngbin0 -> 1205 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_signal_hp_inout.pngbin0 -> 1184 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_signal_hp_no.pngbin0 -> 1197 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_signal_hp_out.pngbin0 -> 1194 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_signal_in.pngbin0 -> 431 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_signal_null_1.pngbin0 -> 1650 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_signal_out.pngbin0 -> 424 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_in.pngbin0 -> 418 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_inout.pngbin0 -> 505 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_out.pngbin0 -> 416 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/ic_mini_settings.pngbin0 -> 133 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/ic_notification_overlay.9.pngbin507 -> 267 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/ic_qs_signal_2g.pngbin0 -> 1236 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/ic_qs_signal_full_2g.pngbin0 -> 1239 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/ic_qs_signal_full_hp.pngbin0 -> 1268 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/ic_qs_signal_hp.pngbin0 -> 1254 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/ic_sysbar_add.pngbin0 -> 321 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/ic_sysbar_add_land.pngbin0 -> 320 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/ic_sysbar_add_side.pngbin0 -> 1083 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_side.pngbin0 -> 1177 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/ic_sysbar_ime_left.pngbin0 -> 1213 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/ic_sysbar_ime_right.pngbin0 -> 1218 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/ic_sysbar_menu_big.pngbin0 -> 487 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/ic_sysbar_menu_big_land.pngbin0 -> 479 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/ic_sysbar_recent_side.pngbin0 -> 1151 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/ic_sysbar_search.pngbin0 -> 650 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/ic_sysbar_search_land.pngbin0 -> 641 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/ic_sysbar_search_side.pngbin0 -> 1266 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_notify_image.pngbin691 -> 0 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_notify_image_error.pngbin850 -> 0 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_no_sim_1.pngbin0 -> 1034 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_0_fully_sim1_4g.pngbin0 -> 1674 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_0_fully_sim1_hp.pngbin0 -> 1650 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_0_fully_sim2_4g.pngbin0 -> 1692 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_0_fully_sim2_hp.pngbin0 -> 1658 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_0_sim1_4g.pngbin0 -> 1674 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_0_sim1_hp.pngbin0 -> 1640 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_0_sim2_4g.pngbin0 -> 1692 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_0_sim2_hp.pngbin0 -> 1658 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_1_fully_sim1_4g.pngbin0 -> 1686 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_1_fully_sim1_hp.pngbin0 -> 1657 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_1_fully_sim2_4g.pngbin0 -> 1706 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_1_fully_sim2_hp.pngbin0 -> 1675 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_1_sim1_4g.pngbin0 -> 1633 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_1_sim1_hp.pngbin0 -> 1606 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_1_sim2_4g.pngbin0 -> 1652 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_1_sim2_hp.pngbin0 -> 1629 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_2_fully_sim1_4g.pngbin0 -> 1693 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_2_fully_sim1_hp.pngbin0 -> 1657 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_2_fully_sim2_4g.pngbin0 -> 1710 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_2_fully_sim2_hp.pngbin0 -> 1677 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_2_sim1_4g.pngbin0 -> 1594 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_2_sim1_hp.pngbin0 -> 1591 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_2_sim2_4g.pngbin0 -> 1611 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_2_sim2_hp.pngbin0 -> 1609 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_3_fully_sim1_4g.pngbin0 -> 1695 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_3_fully_sim1_hp.pngbin0 -> 1661 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_3_fully_sim2_4g.pngbin0 -> 1709 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_3_fully_sim2_hp.pngbin0 -> 1677 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_3_sim1_4g.pngbin0 -> 1551 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_3_sim1_hp.pngbin0 -> 1560 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_3_sim2_4g.pngbin0 -> 1572 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_3_sim2_hp.pngbin0 -> 1582 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_4_fully_sim1_4g.pngbin0 -> 1700 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_4_fully_sim1_hp.pngbin0 -> 1652 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_4_fully_sim2_4g.pngbin0 -> 1721 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_4_fully_sim2_hp.pngbin0 -> 1673 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_4_sim1_4g.pngbin0 -> 1506 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_4_sim1_hp.pngbin0 -> 1531 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_4_sim2_4g.pngbin0 -> 1528 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_4_sim2_hp.pngbin0 -> 1555 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_3g.pngbin0 -> 1260 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_3g_default.pngbin0 -> 1291 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_3g_default_fully.pngbin0 -> 1290 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_3g_default_fully_roam.pngbin0 -> 1327 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_3g_default_roam.pngbin0 -> 1331 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_3g_fully.pngbin0 -> 1260 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_4g.pngbin0 -> 1236 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_4g_default.pngbin0 -> 1276 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_4g_default_fully.pngbin0 -> 1274 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_4g_default_fully_roam.pngbin0 -> 1315 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_4g_default_roam.pngbin0 -> 1315 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_4g_fully.pngbin0 -> 1236 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_e.pngbin0 -> 1189 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_e_fully.pngbin0 -> 1186 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_e_fully_roam.pngbin0 -> 1227 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_e_roam.pngbin0 -> 1229 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_fully_sim1_4g.pngbin0 -> 1696 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_fully_sim1_hp.pngbin0 -> 1659 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_fully_sim2_4g.pngbin0 -> 1717 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_fully_sim2_hp.pngbin0 -> 1684 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_g.pngbin0 -> 1273 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_g_fully.pngbin0 -> 1271 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_g_fully_roam.pngbin0 -> 1307 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_g_roam.pngbin0 -> 1307 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_gsm.pngbin0 -> 1193 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_gsm_fully.pngbin0 -> 1193 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_sim1_4g.pngbin0 -> 1696 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_sim1_hp.pngbin0 -> 1659 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_sim2_4g.pngbin0 -> 1717 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_sim2_hp.pngbin0 -> 1684 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_3g.pngbin0 -> 1277 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_3g_default.pngbin0 -> 1337 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_3g_default_fully.pngbin0 -> 1330 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_3g_default_fully_roam.pngbin0 -> 1369 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_3g_default_roam.pngbin0 -> 1373 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_3g_fully.pngbin0 -> 1278 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_4g.pngbin0 -> 1253 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_4g_default.pngbin0 -> 1318 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_4g_default_fully.pngbin0 -> 1310 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_4g_default_fully_roam.pngbin0 -> 1350 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_4g_default_roam.pngbin0 -> 1358 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_4g_fully.pngbin0 -> 1254 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_e.pngbin0 -> 1230 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_e_fully.pngbin0 -> 1222 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_e_fully_roam.pngbin0 -> 1263 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_e_roam.pngbin0 -> 1270 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_fully_sim1_4g.pngbin0 -> 1720 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_fully_sim1_hp.pngbin0 -> 1678 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_fully_sim2_4g.pngbin0 -> 1739 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_fully_sim2_hp.pngbin0 -> 1699 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_g.pngbin0 -> 1316 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_g_fully.pngbin0 -> 1302 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_g_fully_roam.pngbin0 -> 1337 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_g_roam.pngbin0 -> 1351 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_gsm.pngbin0 -> 1210 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_gsm_fully.pngbin0 -> 1211 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_sim1_4g.pngbin0 -> 1671 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_sim1_hp.pngbin0 -> 1626 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_sim2_4g.pngbin0 -> 1694 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_sim2_hp.pngbin0 -> 1650 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_3g.pngbin0 -> 1286 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_3g_default.pngbin0 -> 1345 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_3g_default_fully.pngbin0 -> 1345 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_3g_default_fully_roam.pngbin0 -> 1384 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_3g_default_roam.pngbin0 -> 1384 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_3g_fully.pngbin0 -> 1289 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_4g.pngbin0 -> 1262 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_4g_default.pngbin0 -> 1325 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_4g_default_fully.pngbin0 -> 1321 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_4g_default_fully_roam.pngbin0 -> 1363 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_4g_default_roam.pngbin0 -> 1367 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_4g_fully.pngbin0 -> 1266 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_e.pngbin0 -> 1239 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_e_fully.pngbin0 -> 1236 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_e_fully_roam.pngbin0 -> 1279 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_e_roam.pngbin0 -> 1283 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_fully_sim1_4g.pngbin0 -> 1719 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_fully_sim1_hp.pngbin0 -> 1677 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_fully_sim2_4g.pngbin0 -> 1738 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_fully_sim2_hp.pngbin0 -> 1698 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_g.pngbin0 -> 1322 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_g_fully.pngbin0 -> 1321 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_g_fully_roam.pngbin0 -> 1360 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_g_roam.pngbin0 -> 1361 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_gsm.pngbin0 -> 1219 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_gsm_fully.pngbin0 -> 1223 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_sim1_4g.pngbin0 -> 1657 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_sim1_hp.pngbin0 -> 1613 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_sim2_4g.pngbin0 -> 1683 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_sim2_hp.pngbin0 -> 1635 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_3g.pngbin0 -> 1308 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_3g_default.pngbin0 -> 1363 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_3g_default_fully.pngbin0 -> 1369 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_3g_default_fully_roam.pngbin0 -> 1407 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_3g_default_roam.pngbin0 -> 1401 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_3g_fully.pngbin0 -> 1313 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_4g.pngbin0 -> 1287 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_4g_default.pngbin0 -> 1342 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_4g_default_fully.pngbin0 -> 1345 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_4g_default_fully_roam.pngbin0 -> 1383 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_4g_default_roam.pngbin0 -> 1381 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_4g_fully.pngbin0 -> 1293 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_e.pngbin0 -> 1257 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_e_fully.pngbin0 -> 1260 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_e_fully_roam.pngbin0 -> 1298 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_e_roam.pngbin0 -> 1296 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_fully_sim1_4g.pngbin0 -> 1719 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_fully_sim1_hp.pngbin0 -> 1680 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_fully_sim2_4g.pngbin0 -> 1740 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_fully_sim2_hp.pngbin0 -> 1702 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_g.pngbin0 -> 1336 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_g_fully.pngbin0 -> 1346 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_g_fully_roam.pngbin0 -> 1384 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_g_roam.pngbin0 -> 1374 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_gsm.pngbin0 -> 1243 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_gsm_fully.pngbin0 -> 1246 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_sim1_4g.pngbin0 -> 1628 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_sim1_hp.pngbin0 -> 1585 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_sim2_4g.pngbin0 -> 1647 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_sim2_hp.pngbin0 -> 1605 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_3g.pngbin0 -> 1270 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_3g_default.pngbin0 -> 1332 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_3g_default_fully.pngbin0 -> 1334 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_3g_default_fully_roam.pngbin0 -> 1369 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_3g_default_roam.pngbin0 -> 1366 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_3g_fully.pngbin0 -> 1283 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_4g.pngbin0 -> 1251 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_4g_default.pngbin0 -> 1310 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_4g_default_fully.pngbin0 -> 1312 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_4g_default_fully_roam.pngbin0 -> 1347 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_4g_default_roam.pngbin0 -> 1339 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_4g_fully.pngbin0 -> 1264 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_e.pngbin0 -> 1236 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_e_fully.pngbin0 -> 1234 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_e_fully_roam.pngbin0 -> 1268 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_e_roam.pngbin0 -> 1271 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_fully_sim1_4g.pngbin0 -> 1722 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_fully_sim1_hp.pngbin0 -> 1667 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_fully_sim2_4g.pngbin0 -> 1741 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_fully_sim2_hp.pngbin0 -> 1693 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_g.pngbin0 -> 1312 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_g_fully.pngbin0 -> 1312 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_g_fully_roam.pngbin0 -> 1346 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_g_roam.pngbin0 -> 1347 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_gsm.pngbin0 -> 1211 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_gsm_fully.pngbin0 -> 1219 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_sim1_4g.pngbin0 -> 1601 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_sim1_hp.pngbin0 -> 1552 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_sim2_4g.pngbin0 -> 1616 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_sim2_hp.pngbin0 -> 1573 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_signal_in.pngbin0 -> 386 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_signal_inout.pngbin0 -> 418 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_signal_null_1.pngbin0 -> 1341 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_signal_out.pngbin0 -> 378 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_in.pngbin0 -> 396 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_inout.pngbin0 -> 445 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_out.pngbin0 -> 385 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xhdpi/ic_mini_settings.pngbin0 -> 218 bytes
-rw-r--r--packages/SystemUI/res/drawable-xhdpi/ic_notification_overlay.9.pngbin1006 -> 519 bytes
-rw-r--r--packages/SystemUI/res/drawable-xhdpi/ic_sysbar_add.pngbin0 -> 552 bytes
-rw-r--r--packages/SystemUI/res/drawable-xhdpi/ic_sysbar_add_land.pngbin0 -> 543 bytes
-rw-r--r--packages/SystemUI/res/drawable-xhdpi/ic_sysbar_add_side.pngbin0 -> 517 bytes
-rw-r--r--packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_side.pngbin0 -> 3434 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xhdpi/ic_sysbar_ime_left.pngbin0 -> 1388 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xhdpi/ic_sysbar_ime_right.pngbin0 -> 1383 bytes
-rw-r--r--packages/SystemUI/res/drawable-xhdpi/ic_sysbar_menu_big.pngbin0 -> 898 bytes
-rw-r--r--packages/SystemUI/res/drawable-xhdpi/ic_sysbar_menu_big_land.pngbin0 -> 880 bytes
-rw-r--r--packages/SystemUI/res/drawable-xhdpi/ic_sysbar_recent_side.pngbin0 -> 3209 bytes
-rw-r--r--packages/SystemUI/res/drawable-xhdpi/ic_sysbar_search.pngbin0 -> 1457 bytes
-rw-r--r--packages/SystemUI/res/drawable-xhdpi/ic_sysbar_search_land.pngbin0 -> 1409 bytes
-rw-r--r--packages/SystemUI/res/drawable-xhdpi/ic_sysbar_search_side.pngbin0 -> 3766 bytes
-rw-r--r--packages/SystemUI/res/drawable-xhdpi/stat_notify_image.pngbin981 -> 0 bytes
-rw-r--r--packages/SystemUI/res/drawable-xhdpi/stat_notify_image_error.pngbin1418 -> 0 bytes
-rw-r--r--packages/SystemUI/res/drawable-xhdpi/stat_sys_r_signal_0_fully_sim1_4g.pngbin0 -> 1584 bytes
-rw-r--r--packages/SystemUI/res/drawable-xhdpi/stat_sys_r_signal_0_fully_sim2_4g.pngbin0 -> 1688 bytes
-rw-r--r--packages/SystemUI/res/drawable-xhdpi/stat_sys_r_signal_0_sim1_4g.pngbin0 -> 1590 bytes
-rw-r--r--packages/SystemUI/res/drawable-xhdpi/stat_sys_r_signal_0_sim2_4g.pngbin0 -> 1688 bytes
-rw-r--r--packages/SystemUI/res/drawable-xhdpi/stat_sys_r_signal_1_fully_sim1_4g.pngbin0 -> 1590 bytes
-rw-r--r--packages/SystemUI/res/drawable-xhdpi/stat_sys_r_signal_1_fully_sim2_4g.pngbin0 -> 1696 bytes
-rw-r--r--packages/SystemUI/res/drawable-xhdpi/stat_sys_r_signal_1_sim1_4g.pngbin0 -> 1678 bytes
-rw-r--r--packages/SystemUI/res/drawable-xhdpi/stat_sys_r_signal_1_sim2_4g.pngbin0 -> 1784 bytes
-rw-r--r--packages/SystemUI/res/drawable-xhdpi/stat_sys_r_signal_2_fully_sim1_4g.pngbin0 -> 1590 bytes
-rw-r--r--packages/SystemUI/res/drawable-xhdpi/stat_sys_r_signal_2_fully_sim2_4g.pngbin0 -> 1697 bytes
-rw-r--r--packages/SystemUI/res/drawable-xhdpi/stat_sys_r_signal_2_sim1_4g.pngbin0 -> 1574 bytes
-rw-r--r--packages/SystemUI/res/drawable-xhdpi/stat_sys_r_signal_2_sim2_4g.pngbin0 -> 1680 bytes
-rw-r--r--packages/SystemUI/res/drawable-xhdpi/stat_sys_r_signal_3_fully_sim1_4g.pngbin0 -> 1599 bytes
-rw-r--r--packages/SystemUI/res/drawable-xhdpi/stat_sys_r_signal_3_fully_sim2_4g.pngbin0 -> 1700 bytes
-rw-r--r--packages/SystemUI/res/drawable-xhdpi/stat_sys_r_signal_3_sim1_4g.pngbin0 -> 1577 bytes
-rw-r--r--packages/SystemUI/res/drawable-xhdpi/stat_sys_r_signal_3_sim2_4g.pngbin0 -> 1682 bytes
-rw-r--r--packages/SystemUI/res/drawable-xhdpi/stat_sys_r_signal_4_fully_sim1_4g.pngbin0 -> 1590 bytes
-rw-r--r--packages/SystemUI/res/drawable-xhdpi/stat_sys_r_signal_4_fully_sim2_4g.pngbin0 -> 1688 bytes
-rw-r--r--packages/SystemUI/res/drawable-xhdpi/stat_sys_r_signal_4_sim1_4g.pngbin0 -> 1543 bytes
-rw-r--r--packages/SystemUI/res/drawable-xhdpi/stat_sys_r_signal_4_sim2_4g.pngbin0 -> 1645 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_3g.pngbin0 -> 1459 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_3g_default.pngbin0 -> 1648 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_3g_default_fully.pngbin0 -> 1648 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_3g_default_fully_roam.pngbin0 -> 1760 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_3g_default_roam.pngbin0 -> 1760 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_3g_fully.pngbin0 -> 1459 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_4g.pngbin0 -> 1432 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_4g_default.pngbin0 -> 1589 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_4g_default_fully.pngbin0 -> 1589 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_4g_default_fully_roam.pngbin0 -> 1719 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_4g_default_roam.pngbin0 -> 1719 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_4g_fully.pngbin0 -> 1432 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_e.pngbin0 -> 1370 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_e_fully.pngbin0 -> 1370 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_e_fully_roam.pngbin0 -> 1509 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_e_roam.pngbin0 -> 1509 bytes
-rw-r--r--packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_fully_sim1_4g.pngbin0 -> 1685 bytes
-rw-r--r--packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_fully_sim2_4g.pngbin0 -> 1755 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_g.pngbin0 -> 1534 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_g_fully.pngbin0 -> 1534 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_g_fully_roam.pngbin0 -> 1646 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_g_roam.pngbin0 -> 1646 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_gsm.pngbin0 -> 1360 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_gsm_fully.pngbin0 -> 1360 bytes
-rw-r--r--packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_sim1_4g.pngbin0 -> 1678 bytes
-rw-r--r--packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_sim2_4g.pngbin0 -> 1755 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_3g.pngbin0 -> 1505 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_3g_default.pngbin0 -> 1723 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_3g_default_fully.pngbin0 -> 1738 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_3g_default_fully_roam.pngbin0 -> 1850 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_3g_default_roam.pngbin0 -> 1838 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_3g_fully.pngbin0 -> 1515 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_4g.pngbin0 -> 1481 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_4g_default.pngbin0 -> 1671 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_4g_default_fully.pngbin0 -> 1683 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_4g_default_fully_roam.pngbin0 -> 1803 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_4g_default_roam.pngbin0 -> 1796 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_4g_fully.pngbin0 -> 1489 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_e.pngbin0 -> 1435 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_e_fully.pngbin0 -> 1438 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_e_fully_roam.pngbin0 -> 1585 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_e_roam.pngbin0 -> 1580 bytes
-rw-r--r--packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_fully_sim1_4g.pngbin0 -> 1693 bytes
-rw-r--r--packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_fully_sim2_4g.pngbin0 -> 1769 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_g.pngbin0 -> 1609 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_g_fully.pngbin0 -> 1622 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_g_fully_roam.pngbin0 -> 1730 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_g_roam.pngbin0 -> 1719 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_gsm.pngbin0 -> 1404 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_gsm_fully.pngbin0 -> 1411 bytes
-rw-r--r--packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_sim1_4g.pngbin0 -> 1678 bytes
-rw-r--r--packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_sim2_4g.pngbin0 -> 1750 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_3g.pngbin0 -> 1535 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_3g_default.pngbin0 -> 1765 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_3g_default_fully.pngbin0 -> 1783 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_3g_default_fully_roam.pngbin0 -> 1897 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_3g_default_roam.pngbin0 -> 1881 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_3g_fully.pngbin0 -> 1552 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_4g.pngbin0 -> 1513 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_4g_default.pngbin0 -> 1714 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_4g_default_fully.pngbin0 -> 1729 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_4g_default_fully_roam.pngbin0 -> 1853 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_4g_default_roam.pngbin0 -> 1837 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_4g_fully.pngbin0 -> 1527 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_e.pngbin0 -> 1478 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_e_fully.pngbin0 -> 1483 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_e_fully_roam.pngbin0 -> 1633 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_e_roam.pngbin0 -> 1628 bytes
-rw-r--r--packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_fully_sim1_4g.pngbin0 -> 1685 bytes
-rw-r--r--packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_fully_sim2_4g.pngbin0 -> 1763 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_g.pngbin0 -> 1663 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_g_fully.pngbin0 -> 1671 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_g_fully_roam.pngbin0 -> 1788 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_g_roam.pngbin0 -> 1771 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_gsm.pngbin0 -> 1434 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_gsm_fully.pngbin0 -> 1442 bytes
-rw-r--r--packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_sim1_4g.pngbin0 -> 1668 bytes
-rw-r--r--packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_sim2_4g.pngbin0 -> 1753 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_3g.pngbin0 -> 1561 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_3g_default.pngbin0 -> 1792 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_3g_default_fully.pngbin0 -> 1812 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_3g_default_fully_roam.pngbin0 -> 1932 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_3g_default_roam.pngbin0 -> 1912 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_3g_fully.pngbin0 -> 1580 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_4g.pngbin0 -> 1536 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_4g_default.pngbin0 -> 1739 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_4g_default_fully.pngbin0 -> 1759 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_4g_default_fully_roam.pngbin0 -> 1883 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_4g_default_roam.pngbin0 -> 1862 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_4g_fully.pngbin0 -> 1551 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_e.pngbin0 -> 1499 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_e_fully.pngbin0 -> 1509 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_e_fully_roam.pngbin0 -> 1650 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_e_roam.pngbin0 -> 1643 bytes
-rw-r--r--packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_fully_sim1_4g.pngbin0 -> 1693 bytes
-rw-r--r--packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_fully_sim2_4g.pngbin0 -> 1763 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_g.pngbin0 -> 1682 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_g_fully.pngbin0 -> 1693 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_g_fully_roam.pngbin0 -> 1809 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_g_roam.pngbin0 -> 1794 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_gsm.pngbin0 -> 1454 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_gsm_fully.pngbin0 -> 1466 bytes
-rw-r--r--packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_sim1_4g.pngbin0 -> 1671 bytes
-rw-r--r--packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_sim2_4g.pngbin0 -> 1745 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_3g.pngbin0 -> 1501 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_3g_default.pngbin0 -> 1869 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_3g_default_fully.pngbin0 -> 1736 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_3g_default_fully_roam.pngbin0 -> 1835 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_3g_default_roam.pngbin0 -> 1972 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_3g_fully.pngbin0 -> 1505 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_4g.pngbin0 -> 1481 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_4g_default.pngbin0 -> 1681 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_4g_default_fully.pngbin0 -> 1685 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_4g_default_fully_roam.pngbin0 -> 1787 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_4g_default_roam.pngbin0 -> 1779 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_4g_fully.pngbin0 -> 1486 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_e.pngbin0 -> 1455 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_e_fully.pngbin0 -> 1449 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_e_fully_roam.pngbin0 -> 1569 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_e_roam.pngbin0 -> 1569 bytes
-rw-r--r--packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_fully_sim1_4g.pngbin0 -> 1686 bytes
-rw-r--r--packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_fully_sim2_4g.pngbin0 -> 1755 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_g.pngbin0 -> 1630 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_g_fully.pngbin0 -> 1619 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_g_fully_roam.pngbin0 -> 1719 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_g_roam.pngbin0 -> 1720 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_gsm.pngbin0 -> 1405 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_gsm_fully.pngbin0 -> 1403 bytes
-rw-r--r--packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_sim1_4g.pngbin0 -> 1635 bytes
-rw-r--r--packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_sim2_4g.pngbin0 -> 1658 bytes
-rw-r--r--packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_in.pngbin0 -> 463 bytes
-rw-r--r--packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_inout.pngbin0 -> 571 bytes
-rw-r--r--packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_out.pngbin0 -> 453 bytes
-rw-r--r--packages/SystemUI/res/drawable-xhdpi/stat_sys_wifi_in.pngbin0 -> 479 bytes
-rw-r--r--packages/SystemUI/res/drawable-xhdpi/stat_sys_wifi_inout.pngbin0 -> 583 bytes
-rw-r--r--packages/SystemUI/res/drawable-xhdpi/stat_sys_wifi_out.pngbin0 -> 446 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xxhdpi/ic_mini_settings.pngbin0 -> 324 bytes
-rw-r--r--packages/SystemUI/res/drawable-xxhdpi/ic_notification_overlay.9.pngbin1823 -> 775 bytes
-rw-r--r--packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_add.pngbin0 -> 889 bytes
-rw-r--r--packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_add_land.pngbin0 -> 891 bytes
-rw-r--r--packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_ime_left.pngbin0 -> 1632 bytes
-rw-r--r--packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_ime_right.pngbin0 -> 1770 bytes
-rw-r--r--packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_menu_big.pngbin0 -> 1444 bytes
-rw-r--r--packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_menu_big_land.pngbin0 -> 1479 bytes
-rw-r--r--packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_search.pngbin0 -> 2566 bytes
-rw-r--r--packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_search_land.pngbin0 -> 2769 bytes
-rw-r--r--packages/SystemUI/res/drawable-xxhdpi/stat_notify_image.pngbin1458 -> 0 bytes
-rw-r--r--packages/SystemUI/res/drawable-xxhdpi/stat_notify_image_error.pngbin1923 -> 0 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xxxhdpi/ic_mini_settings.pngbin0 -> 401 bytes
-rw-r--r--packages/SystemUI/res/drawable/cid.xml33
-rw-r--r--packages/SystemUI/res/drawable/ic_lockscreen_shortcuts_blank.xml30
-rw-r--r--packages/SystemUI/res/drawable/ic_qs_edit_tiles.xml30
-rw-r--r--packages/SystemUI/res/drawable/ic_qs_signal_4g_plus.xml50
-rw-r--r--packages/SystemUI/res/drawable/ic_settings.xml39
-rw-r--r--packages/SystemUI/res/drawable/lockscreen_shortcuts_phone_background.xml21
-rw-r--r--packages/SystemUI/res/drawable/lockscreen_target_background.xml20
-rw-r--r--packages/SystemUI/res/drawable/notification_guts_ic_ringer_mute.xml20
-rw-r--r--packages/SystemUI/res/drawable/notification_guts_ic_settings.xml20
-rw-r--r--packages/SystemUI/res/drawable/qs_tile_background_drag.xml22
-rw-r--r--packages/SystemUI/res/drawable/stat_notify_image.xml27
-rw-r--r--packages/SystemUI/res/drawable/stat_notify_image_error.xml27
-rw-r--r--packages/SystemUI/res/drawable/stat_sys_data_fully_connected_4g_plus.xml50
-rw-r--r--packages/SystemUI/res/drawable/stat_sys_signal_in_auto_mirrored.xml32
-rw-r--r--packages/SystemUI/res/drawable/stat_sys_signal_inout_auto_mirrored.xml32
-rw-r--r--packages/SystemUI/res/drawable/stat_sys_signal_out_auto_mirrored.xml32
-rw-r--r--packages/SystemUI/res/drawable/stat_sys_su.xml15
-rw-r--r--packages/SystemUI/res/drawable/volume_dialog_background.xml2
-rw-r--r--packages/SystemUI/res/drawable/zen_mode_panel_background.xml24
-rw-r--r--packages/SystemUI/res/layout-sw600dp/mid_navigation_bar_land.xml115
-rw-r--r--packages/SystemUI/res/layout-sw600dp/mid_navigation_bar_port.xml132
-rw-r--r--packages/SystemUI/res/layout-sw600dp/navigation_bar.xml324
-rw-r--r--packages/SystemUI/res/layout/cmland.xml104
-rw-r--r--packages/SystemUI/res/layout/keyguard_bottom_area.xml2
-rw-r--r--packages/SystemUI/res/layout/keyguard_status_bar.xml2
-rw-r--r--packages/SystemUI/res/layout/lockscreen_shortcuts.xml65
-rw-r--r--packages/SystemUI/res/layout/mid_navigation_bar_land.xml130
-rw-r--r--packages/SystemUI/res/layout/mid_navigation_bar_port.xml126
-rw-r--r--packages/SystemUI/res/layout/mobile_signal_group.xml82
-rw-r--r--packages/SystemUI/res/layout/navigation_bar.xml218
-rw-r--r--packages/SystemUI/res/layout/navigation_bar_edit_menu_item.xml44
-rw-r--r--packages/SystemUI/res/layout/notification_guts.xml14
-rw-r--r--packages/SystemUI/res/layout/qs_custom_detail.xml59
-rw-r--r--packages/SystemUI/res/layout/qs_custom_detail_remote.xml25
-rw-r--r--packages/SystemUI/res/layout/qs_detail.xml12
-rw-r--r--packages/SystemUI/res/layout/qs_detail_header.xml13
-rw-r--r--packages/SystemUI/res/layout/qs_detail_items.xml6
-rw-r--r--packages/SystemUI/res/layout/qs_detail_items_grid.xml27
-rw-r--r--packages/SystemUI/res/layout/qs_detail_items_list.xml53
-rw-r--r--packages/SystemUI/res/layout/qs_panel.xml5
-rw-r--r--packages/SystemUI/res/layout/qs_settings.xml75
-rw-r--r--packages/SystemUI/res/layout/qs_settings_row.xml34
-rw-r--r--packages/SystemUI/res/layout/qs_tile_top.xml88
-rw-r--r--packages/SystemUI/res/layout/qs_user_detail_item.xml2
-rw-r--r--packages/SystemUI/res/layout/quick_settings_notification_brightness_dialog.xml31
-rw-r--r--packages/SystemUI/res/layout/screen_pinning_request.xml6
-rw-r--r--packages/SystemUI/res/layout/screen_pinning_request_text_area.xml6
-rw-r--r--packages/SystemUI/res/layout/signal_cluster_view.xml9
-rw-r--r--packages/SystemUI/res/layout/status_bar.xml36
-rw-r--r--packages/SystemUI/res/layout/status_bar_expanded.xml18
-rw-r--r--packages/SystemUI/res/layout/status_bar_expanded_header.xml68
-rw-r--r--packages/SystemUI/res/layout/super_status_bar.xml8
-rw-r--r--packages/SystemUI/res/layout/system_icons.xml3
-rw-r--r--packages/SystemUI/res/layout/volume_dialog.xml4
-rw-r--r--packages/SystemUI/res/menu/recent_popup_menu.xml26
-rw-r--r--packages/SystemUI/res/values-hdpi/cm_dimens.xml19
-rw-r--r--packages/SystemUI/res/values-land/cm_dimens.xml21
-rw-r--r--packages/SystemUI/res/values-mdpi/cm_dimens.xml19
-rw-r--r--packages/SystemUI/res/values-xhdpi/cm_dimens.xml19
-rw-r--r--packages/SystemUI/res/values-xxhdpi/cm_dimens.xml19
-rw-r--r--packages/SystemUI/res/values-zh-rCN/strings.xml2
-rw-r--r--packages/SystemUI/res/values-zh-rTW/strings.xml2
-rw-r--r--packages/SystemUI/res/values/arrays.xml1093
-rw-r--r--packages/SystemUI/res/values/cm_arrays.xml27
-rw-r--r--packages/SystemUI/res/values/cm_attrs.xml33
-rw-r--r--packages/SystemUI/res/values/cm_colors.xml70
-rw-r--r--packages/SystemUI/res/values/cm_dimens.xml52
-rw-r--r--packages/SystemUI/res/values/cm_strings.xml91
-rw-r--r--packages/SystemUI/res/values/cm_styles.xml44
-rw-r--r--packages/SystemUI/res/values/colors.xml3
-rw-r--r--packages/SystemUI/res/values/config.xml40
-rw-r--r--packages/SystemUI/res/values/strings.xml3
-rw-r--r--packages/SystemUI/res/values/vpi__attrs.xml44
-rw-r--r--packages/SystemUI/res/values/vpi__defaults.xml26
-rw-r--r--packages/SystemUI/src/com/android/systemui/BatteryLevelTextView.java129
-rwxr-xr-xpackages/SystemUI/src/com/android/systemui/BatteryMeterView.java1094
-rw-r--r--packages/SystemUI/src/com/android/systemui/ImageWallpaper.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/cm/GlowBackground.java83
-rw-r--r--packages/SystemUI/src/com/android/systemui/cm/LockscreenShortcutsActivity.java239
-rw-r--r--packages/SystemUI/src/com/android/systemui/cm/LockscreenShortcutsHelper.java196
-rw-r--r--packages/SystemUI/src/com/android/systemui/cm/SpamMessageProvider.java204
-rw-r--r--packages/SystemUI/src/com/android/systemui/cm/SpamOpenHelper.java46
-rw-r--r--packages/SystemUI/src/com/android/systemui/cm/UserContentObserver.java89
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeService.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/egg/CMLand.java43
-rw-r--r--packages/SystemUI/src/com/android/systemui/egg/MLand.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/egg/MLandActivity.java10
-rwxr-xr-x[-rw-r--r--]packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java42
-rw-r--r--packages/SystemUI/src/com/android/systemui/power/PowerUI.java48
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSBooleanSettingRow.java167
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSContainer.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSDetailClipper.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSDetailItemsGrid.java154
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSDetailItemsList.java214
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSDragPanel.java1705
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSPage.java147
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSPanel.java117
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSPanelTopView.java251
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSSettings.java71
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSTile.java82
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSTileView.java75
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSViewPager.java132
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java85
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java22
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java48
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java27
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/CustomQSTile.java269
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java22
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/EditTile.java84
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java27
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java97
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/Constants.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java31
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java30
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java91
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/settings/NotificationBrightnessController.java247
-rw-r--r--packages/SystemUI/src/com/android/systemui/settings/NotificationBrightnessDialog.java71
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java30
-rwxr-xr-x[-rw-r--r--]packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java71
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/CustomTileData.java67
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java60
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java16
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java132
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/StackScrollerDecorView.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java132
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/BackButtonDrawable.java139
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java68
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/BlurLayer.java196
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/ClockController.java145
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java42
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/IconMerger.java20
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java187
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java46
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NavbarEditor.java565
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java411
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java97
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java35
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java1051
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java49
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarTransitions.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java154
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/SettingsButton.java42
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java270
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java39
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java89
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java99
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java16
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java80
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/CallbackHandler.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/CastControllerImpl.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java26
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/DeadZone.java34
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonRipple.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java140
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java347
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java20
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockControllerImpl.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/SignalCallbackAdapter.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/SuController.java27
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/SuControllerImpl.java137
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java451
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/WeatherController.java32
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/WeatherControllerImpl.java126
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/tuner/QsTuner.java276
-rw-r--r--packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/tuner/TunerService.java45
-rw-r--r--packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java19
-rw-r--r--packages/SystemUI/src/com/viewpagerindicator/CirclePageIndicator.java527
-rw-r--r--packages/SystemUI/src/com/viewpagerindicator/PageIndicator.java63
-rw-r--r--packages/SystemUI/tests/Android.mk3
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CallbackHandlerTest.java10
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java8
-rw-r--r--services/Android.mk7
-rw-r--r--services/accessibility/Android.mk2
-rw-r--r--services/accessibility/java/com/android/server/accessibility/DisplayAdjustmentUtils.java25
-rw-r--r--services/accessibility/java/com/android/server/accessibility/ScreenMagnifier.java7
-rw-r--r--services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java3
-rw-r--r--services/backup/java/com/android/server/backup/BackupManagerService.java32
-rw-r--r--services/core/Android.mk4
-rw-r--r--services/core/java/com/android/server/AlarmManagerService.java162
-rw-r--r--services/core/java/com/android/server/AppOpsPolicy.java441
-rw-r--r--services/core/java/com/android/server/AppOpsService.java480
-rw-r--r--services/core/java/com/android/server/AssetAtlasService.java5
-rw-r--r--services/core/java/com/android/server/BasePermissionDialog.java84
-rw-r--r--services/core/java/com/android/server/BatteryService.java213
-rw-r--r--services/core/java/com/android/server/BluetoothManagerService.java325
-rw-r--r--services/core/java/com/android/server/ConnectivityService.java19
-rw-r--r--services/core/java/com/android/server/DeviceIdleController.java8
-rw-r--r--services/core/java/com/android/server/InputMethodManagerService.java21
-rw-r--r--services/core/java/com/android/server/LocationManagerService.java148
-rw-r--r--services/core/java/com/android/server/LockSettingsService.java32
-rw-r--r--services/core/java/com/android/server/MasterClearReceiver.java6
-rw-r--r--services/core/java/com/android/server/MountService.java36
-rw-r--r--services/core/java/com/android/server/NetworkManagementService.java34
-rw-r--r--services/core/java/com/android/server/PermissionDialog.java141
-rw-r--r--services/core/java/com/android/server/PermissionDialogReqQueue.java82
-rw-r--r--services/core/java/com/android/server/SystemConfig.java45
-rw-r--r--services/core/java/com/android/server/ThemeService.java1254
-rw-r--r--services/core/java/com/android/server/Watchdog.java42
-rw-r--r--services/core/java/com/android/server/WiredAccessoryManager.java28
-rw-r--r--services/core/java/com/android/server/accounts/AccountManagerService.java8
-rwxr-xr-xservices/core/java/com/android/server/am/ActiveServices.java2
-rwxr-xr-x[-rw-r--r--]services/core/java/com/android/server/am/ActivityManagerService.java411
-rw-r--r--services/core/java/com/android/server/am/ActivityStack.java77
-rw-r--r--services/core/java/com/android/server/am/ActivityStackSupervisor.java53
-rw-r--r--services/core/java/com/android/server/am/BroadcastQueue.java13
-rw-r--r--services/core/java/com/android/server/am/EventLogTags.logtags2
-rw-r--r--services/core/java/com/android/server/am/LockTaskNotify.java30
-rw-r--r--services/core/java/com/android/server/am/ProcessList.java121
-rw-r--r--services/core/java/com/android/server/am/ProcessRecord.java24
-rw-r--r--services/core/java/com/android/server/audio/AudioService.java276
-rw-r--r--services/core/java/com/android/server/audio/MediaFocusControl.java79
-rw-r--r--services/core/java/com/android/server/connectivity/Nat464Xlat.java17
-rw-r--r--services/core/java/com/android/server/connectivity/Tethering.java241
-rw-r--r--services/core/java/com/android/server/display/AutomaticBrightnessController.java17
-rw-r--r--services/core/java/com/android/server/display/DisplayManagerService.java2
-rw-r--r--services/core/java/com/android/server/display/DisplayPowerController.java31
-rw-r--r--services/core/java/com/android/server/display/ExtendedRemoteDisplayHelper.java163
-rw-r--r--services/core/java/com/android/server/display/LiveDisplayController.java825
-rw-r--r--services/core/java/com/android/server/display/LocalDisplayAdapter.java1
-rw-r--r--services/core/java/com/android/server/display/WifiDisplayController.java35
-rw-r--r--services/core/java/com/android/server/dreams/DreamManagerService.java86
-rw-r--r--services/core/java/com/android/server/gesture/GestureInputFilter.java333
-rw-r--r--services/core/java/com/android/server/gesture/GestureService.java63
-rw-r--r--services/core/java/com/android/server/input/InputManagerService.java221
-rw-r--r--services/core/java/com/android/server/lights/Light.java2
-rw-r--r--services/core/java/com/android/server/lights/LightsManager.java4
-rw-r--r--services/core/java/com/android/server/lights/LightsService.java31
-rw-r--r--services/core/java/com/android/server/location/GeoFencerBase.java147
-rw-r--r--services/core/java/com/android/server/location/GeoFencerProxy.java149
-rw-r--r--services/core/java/com/android/server/location/GpsLocationProvider.java4
-rw-r--r--services/core/java/com/android/server/media/MediaSessionRecord.java182
-rw-r--r--services/core/java/com/android/server/net/NetPluginDelegate.java101
-rw-r--r--services/core/java/com/android/server/net/NetworkPolicyManagerService.java4
-rw-r--r--services/core/java/com/android/server/net/NetworkStatsService.java2
-rwxr-xr-x[-rw-r--r--]services/core/java/com/android/server/notification/NotificationManagerService.java464
-rw-r--r--services/core/java/com/android/server/pm/BasePermission.java2
-rw-r--r--services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java36
-rw-r--r--services/core/java/com/android/server/pm/Installer.java39
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerSession.java10
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java1091
-rw-r--r--services/core/java/com/android/server/pm/PackageSettingBase.java38
-rwxr-xr-x[-rw-r--r--]services/core/java/com/android/server/pm/Settings.java349
-rw-r--r--services/core/java/com/android/server/policy/BarController.java3
-rw-r--r--services/core/java/com/android/server/policy/GlobalActions.java228
-rw-r--r--services/core/java/com/android/server/policy/ImmersiveModeConfirmation.java3
-rw-r--r--services/core/java/com/android/server/policy/PhoneWindowManager.java1215
-rw-r--r--services/core/java/com/android/server/policy/PolicyControl.java4
-rw-r--r--services/core/java/com/android/server/policy/SystemGesturesPointerEventListener.java10
-rw-r--r--services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java2
-rw-r--r--services/core/java/com/android/server/power/Notifier.java35
-rw-r--r--services/core/java/com/android/server/power/PowerManagerService.java453
-rw-r--r--services/core/java/com/android/server/power/ShutdownThread.java326
-rw-r--r--services/core/java/com/android/server/tv/TvInputHal.java2
-rw-r--r--services/core/java/com/android/server/wallpaper/WallpaperManagerService.java323
-rw-r--r--services/core/java/com/android/server/wm/BlurLayer.java313
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java29
-rw-r--r--services/core/java/com/android/server/wm/ScreenRotationAnimation.java28
-rw-r--r--services/core/java/com/android/server/wm/Session.java28
-rw-r--r--services/core/java/com/android/server/wm/TaskStack.java98
-rw-r--r--services/core/java/com/android/server/wm/Watermark.java52
-rw-r--r--services/core/java/com/android/server/wm/WindowAnimator.java19
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java143
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java5
-rw-r--r--services/core/java/com/android/server/wm/WindowStateAnimator.java148
-rw-r--r--services/core/jni/Android.mk7
-rw-r--r--services/core/jni/com_android_server_AlarmManagerService.cpp73
-rw-r--r--services/core/jni/com_android_server_PersistentDataBlockService.cpp9
-rw-r--r--services/core/jni/com_android_server_SystemServer.cpp16
-rw-r--r--services/core/jni/com_android_server_UsbMidiDevice.cpp22
-rw-r--r--services/core/jni/com_android_server_input_InputManagerService.cpp62
-rw-r--r--services/core/jni/com_android_server_lights_LightsService.cpp24
-rw-r--r--services/core/jni/com_android_server_location_GpsLocationProvider.cpp9
-rw-r--r--services/core/jni/com_android_server_power_PowerManagerService.cpp18
-rw-r--r--services/core/jni/com_android_server_tv_TvInputHal.cpp85
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java42
-rw-r--r--services/java/com/android/server/AppsFailureReceiver.java118
-rw-r--r--services/java/com/android/server/SystemServer.java142
-rw-r--r--services/java/com/android/server/gesture/EdgeGestureInputFilter.java539
-rw-r--r--services/java/com/android/server/gesture/EdgeGestureService.java488
-rw-r--r--services/java/com/android/server/gesture/EdgeGestureTracker.java252
-rw-r--r--services/libtvextensions/Android.mk21
-rw-r--r--services/libtvextensions/common/ExtensionsLoader.hpp91
-rw-r--r--services/libtvextensions/common/TvInputHalExtensionsCommon.h69
-rw-r--r--services/libtvextensions/jni/BufferProducerThread.h89
-rw-r--r--services/libtvextensions/jni/TvInputHalExtensions.h54
-rw-r--r--services/libtvextensions/jni/TvInputHalFactory.cpp56
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java60
-rw-r--r--services/usage/java/com/android/server/usage/UsageStatsService.java2
-rw-r--r--services/usb/Android.mk2
-rw-r--r--services/usb/java/com/android/server/usb/UsbAlsaManager.java2
-rw-r--r--services/usb/java/com/android/server/usb/UsbDeviceManager.java53
-rw-r--r--services/usb/java/com/android/server/usb/UsbSettingsManager.java2
-rw-r--r--telecomm/java/android/telecom/Call.java95
-rw-r--r--telecomm/java/android/telecom/Conference.java19
-rw-r--r--telecomm/java/android/telecom/Connection.java56
-rw-r--r--telecomm/java/android/telecom/ConnectionRequest.java5
-rw-r--r--telecomm/java/android/telecom/ConnectionService.java76
-rw-r--r--telecomm/java/android/telecom/ConnectionServiceAdapter.java12
-rw-r--r--telecomm/java/android/telecom/ConnectionServiceAdapterServant.java4
-rw-r--r--telecomm/java/android/telecom/InCallAdapter.java13
-rw-r--r--telecomm/java/android/telecom/InCallService.java21
-rw-r--r--telecomm/java/android/telecom/ParcelableCall.java28
-rw-r--r--telecomm/java/android/telecom/Phone.java18
-rw-r--r--telecomm/java/android/telecom/PhoneAccount.java38
-rw-r--r--telecomm/java/android/telecom/RemoteConnectionService.java4
-rw-r--r--telecomm/java/android/telecom/TelecomManager.java32
-rw-r--r--telecomm/java/android/telecom/VideoCallImpl.java22
-rw-r--r--telecomm/java/com/android/internal/telecom/IConnectionService.aidl4
-rw-r--r--telecomm/java/com/android/internal/telecom/IConnectionServiceAdapter.aidl2
-rw-r--r--telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl2
-rw-r--r--telecomm/java/com/android/internal/telecom/IInCallService.aidl2
-rw-r--r--telecomm/java/com/android/internal/telecom/ITelecomService.aidl10
-rw-r--r--telephony/java/android/telephony/DisconnectCause.java162
-rw-r--r--telephony/java/android/telephony/PhoneNumberUtils.java118
-rwxr-xr-x[-rw-r--r--]telephony/java/android/telephony/RadioAccessFamily.java24
-rw-r--r--telephony/java/android/telephony/ServiceState.java19
-rw-r--r--telephony/java/android/telephony/SignalStrength.java35
-rw-r--r--telephony/java/android/telephony/SubscriptionInfo.java22
-rw-r--r--telephony/java/android/telephony/SubscriptionManager.java80
-rw-r--r--telephony/java/android/telephony/TelephonyManager.java144
-rw-r--r--telephony/java/com/android/ims/ImsCallProfile.java1
-rw-r--r--telephony/java/com/android/ims/ImsReasonInfo.java15
-rw-r--r--telephony/java/com/android/ims/ImsStreamMediaProfile.java12
-rw-r--r--telephony/java/com/android/ims/internal/IImsRegistrationListener.aidl29
-rw-r--r--telephony/java/com/android/internal/telephony/CallerInfo.java2
-rw-r--r--telephony/java/com/android/internal/telephony/IExtTelephony.aidl119
-rw-r--r--telephony/java/com/android/internal/telephony/ISms.aidl100
-rwxr-xr-xtelephony/java/com/android/internal/telephony/ISub.aidl8
-rw-r--r--telephony/java/com/android/internal/telephony/ITelephony.aidl117
-rw-r--r--telephony/java/com/android/internal/telephony/OperatorInfo.java17
-rwxr-xr-x[-rw-r--r--]telephony/java/com/android/internal/telephony/PhoneConstants.java3
-rwxr-xr-x[-rw-r--r--]telephony/java/com/android/internal/telephony/RILConstants.java5
-rw-r--r--telephony/java/com/android/internal/telephony/TelephonyProperties.java45
-rw-r--r--test-runner/src/android/test/mock/MockContext.java19
-rw-r--r--test-runner/src/android/test/mock/MockPackageManager.java44
-rwxr-xr-xtests/ThemeTests/cm11_to_cm12/downgrade_to_cm11.sh34
-rw-r--r--tools/aapt/AaptAssets.cpp151
-rw-r--r--tools/aapt/AaptAssets.h21
-rw-r--r--tools/aapt/AaptConfig.cpp11
-rw-r--r--tools/aapt/Android.mk25
-rw-r--r--tools/aapt/Bundle.h17
-rw-r--r--tools/aapt/Command.cpp33
-rw-r--r--tools/aapt/Images.cpp105
-rw-r--r--tools/aapt/Images.h16
-rw-r--r--tools/aapt/Main.cpp47
-rw-r--r--tools/aapt/Main.h9
-rw-r--r--tools/aapt/Package.cpp306
-rw-r--r--tools/aapt/Resource.cpp24
-rw-r--r--tools/aapt/ResourceTable.cpp12
-rw-r--r--tools/aapt/ResourceTable.h3
-rw-r--r--tools/aapt/XMLNode.cpp43
-rw-r--r--tools/aapt/XMLNode.h3
-rw-r--r--tools/aapt/ZipFile.cpp65
-rw-r--r--tools/aapt/ZipFile.h1
-rw-r--r--tools/aapt/tests/ZipReading_test.cpp156
-rw-r--r--tools/aapt/tests/mocks/MockZipEntry.h29
-rw-r--r--tools/aapt/tests/mocks/MockZipFile.h29
-rw-r--r--tools/aidl/aidl.cpp23
-rw-r--r--tools/aidl/aidl_language.h1
-rw-r--r--tools/aidl/generate_java_binder.cpp6
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java5
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java16
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/view/WindowManagerImpl.java2
-rw-r--r--wifi/java/android/net/wifi/IWifiManager.aidl2
-rw-r--r--wifi/java/android/net/wifi/WifiChannel.java5
-rw-r--r--wifi/java/android/net/wifi/WifiConfiguration.java62
-rwxr-xr-xwifi/java/android/net/wifi/WifiDevice.aidl32
-rwxr-xr-xwifi/java/android/net/wifi/WifiDevice.java137
-rw-r--r--wifi/java/android/net/wifi/WifiManager.java23
1664 files changed, 62627 insertions, 4139 deletions
diff --git a/Android.mk b/Android.mk
index 99e0c46..9684271 100644
--- a/Android.mk
+++ b/Android.mk
@@ -103,7 +103,6 @@ LOCAL_SRC_FILES += \
core/java/android/bluetooth/IBluetoothA2dpSink.aidl \
core/java/android/bluetooth/IBluetoothAvrcpController.aidl \
core/java/android/bluetooth/IBluetoothCallback.aidl \
- core/java/android/bluetooth/IBluetoothProfileServiceConnection.aidl \
core/java/android/bluetooth/IBluetoothHeadset.aidl \
core/java/android/bluetooth/IBluetoothHeadsetPhone.aidl \
core/java/android/bluetooth/IBluetoothHealth.aidl \
@@ -117,9 +116,12 @@ LOCAL_SRC_FILES += \
core/java/android/bluetooth/IBluetoothSap.aidl \
core/java/android/bluetooth/IBluetoothStateChangeCallback.aidl \
core/java/android/bluetooth/IBluetoothHeadsetClient.aidl \
+ core/java/android/bluetooth/IBluetoothHidDevice.aidl \
+ core/java/android/bluetooth/IBluetoothHidDeviceCallback.aidl \
core/java/android/bluetooth/IBluetoothGatt.aidl \
core/java/android/bluetooth/IBluetoothGattCallback.aidl \
core/java/android/bluetooth/IBluetoothGattServerCallback.aidl \
+ core/java/android/bluetooth/IBluetoothDun.aidl \
core/java/android/content/IClipboard.aidl \
core/java/android/content/IContentService.aidl \
core/java/android/content/IIntentReceiver.aidl \
@@ -144,6 +146,9 @@ LOCAL_SRC_FILES += \
core/java/android/content/pm/IPackageMoveObserver.aidl \
core/java/android/content/pm/IPackageStatsObserver.aidl \
core/java/android/content/pm/IOnPermissionsChangeListener.aidl \
+ core/java/android/content/res/IThemeChangeListener.aidl \
+ core/java/android/content/res/IThemeProcessingListener.aidl \
+ core/java/android/content/res/IThemeService.aidl \
core/java/android/database/IContentObserver.aidl \
core/java/android/hardware/ICameraService.aidl \
core/java/android/hardware/ICameraServiceListener.aidl \
@@ -247,6 +252,10 @@ LOCAL_SRC_FILES += \
core/java/android/service/voice/IVoiceInteractionService.aidl \
core/java/android/service/voice/IVoiceInteractionSession.aidl \
core/java/android/service/voice/IVoiceInteractionSessionService.aidl \
+ core/java/android/service/gesture/IEdgeGestureService.aidl \
+ core/java/android/service/gesture/IEdgeGestureActivationListener.aidl \
+ core/java/android/service/gesture/IEdgeGestureHostCallback.aidl \
+ core/java/android/service/gesture/IGestureService.aidl \
core/java/android/service/wallpaper/IWallpaperConnection.aidl \
core/java/android/service/wallpaper/IWallpaperEngine.aidl \
core/java/android/service/wallpaper/IWallpaperService.aidl \
@@ -322,6 +331,8 @@ LOCAL_SRC_FILES += \
location/java/android/location/IGeofenceProvider.aidl \
location/java/android/location/IGpsMeasurementsListener.aidl \
location/java/android/location/IGpsNavigationMessageListener.aidl \
+ location/java/android/location/IGeoFencer.aidl \
+ location/java/android/location/IGeoFenceListener.aidl \
location/java/android/location/IGpsStatusListener.aidl \
location/java/android/location/IGpsStatusProvider.aidl \
location/java/android/location/ILocationListener.aidl \
@@ -405,6 +416,7 @@ LOCAL_SRC_FILES += \
telephony/java/com/android/internal/telephony/ITelephony.aidl \
telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl \
telephony/java/com/android/internal/telephony/IWapPushManager.aidl \
+ telephony/java/com/android/internal/telephony/IExtTelephony.aidl \
wifi/java/android/net/wifi/IWifiManager.aidl \
wifi/java/android/net/wifi/passpoint/IWifiPasspointManager.aidl \
wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl \
@@ -565,6 +577,7 @@ aidl_files := \
frameworks/base/core/java/android/app/usage/UsageEvents.aidl \
frameworks/base/core/java/android/app/Notification.aidl \
frameworks/base/core/java/android/app/NotificationManager.aidl \
+ frameworks/base/core/java/android/app/NotificationGroup.aidl \
frameworks/base/core/java/android/app/WallpaperInfo.aidl \
frameworks/base/core/java/android/app/AppOpsManager.aidl \
frameworks/base/core/java/android/app/ActivityManager.aidl \
@@ -1033,7 +1046,7 @@ LOCAL_STATIC_JAVA_LIBRARIES:=$(framework_docs_LOCAL_STATIC_JAVA_LIBRARIES)
LOCAL_JAVA_LIBRARIES:=$(framework_docs_LOCAL_JAVA_LIBRARIES)
LOCAL_MODULE_CLASS:=$(framework_docs_LOCAL_MODULE_CLASS)
LOCAL_DROIDDOC_SOURCE_PATH:=$(framework_docs_LOCAL_DROIDDOC_SOURCE_PATH)
-LOCAL_DROIDDOC_HTML_DIR:=docs/html-ndk
+LOCAL_DROIDDOC_HTML_DIR:=$(framework_docs_LOCAL_DROIDDOC_HTML_DIR)
LOCAL_ADDITIONAL_JAVA_DIR:=$(framework_docs_LOCAL_ADDITIONAL_JAVA_DIR)
LOCAL_ADDITIONAL_DEPENDENCIES:=$(framework_docs_LOCAL_ADDITIONAL_DEPENDENCIES)
# specify a second html input dir and an output path relative to OUT_DIR)
diff --git a/CleanSpec.mk b/CleanSpec.mk
index 48be749..fe7284e 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -239,3 +239,12 @@ $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framew
# ******************************************************************
# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST ABOVE THIS BANNER
# ******************************************************************
+
+# clean steps for aapt
+$(call add-clean-step, rm -rf $(OUT_DIR)/host/$(HOST_PREBUILT_TAG)/bin/aapt)
+$(call add-clean-step, rm -rf $(OUT_DIR)/host/$(HOST_PREBUILT_TAG)/obj32/EXECUTABLES/aapt_intermediates)
+$(call add-clean-step, rm -rf $(OUT_DIR)/host/$(HOST_PREBUILT_TAG)/bin/libaapt_tests)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/EXECUTABLES/aapt_intermediates)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/bin/aapt)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/symbols/system/bin/aapt)
+$(call add-clean-step, rm -rf $(OUT_DIR)/host/$(HOST_PREBUILT_TAG)/obj32/STATIC_LIBRARIES/libaapt_intermediates)
diff --git a/cmds/bootanimation/Android.mk b/cmds/bootanimation/Android.mk
index 2ee586f..0c05ded 100644
--- a/cmds/bootanimation/Android.mk
+++ b/cmds/bootanimation/Android.mk
@@ -23,7 +23,28 @@ LOCAL_SHARED_LIBRARIES := \
libEGL \
libGLESv1_CM \
libgui \
- libtinyalsa
+ libtinyalsa \
+ libmedia
+
+ifeq ($(TARGET_CONTINUOUS_SPLASH_ENABLED),true)
+ LOCAL_CFLAGS += -DCONTINUOUS_SPLASH
+endif
+
+ifeq ($(TARGET_BOOTANIMATION_PRELOAD),true)
+ LOCAL_CFLAGS += -DPRELOAD_BOOTANIMATION
+endif
+
+ifeq ($(TARGET_BOOTANIMATION_TEXTURE_CACHE),true)
+ LOCAL_CFLAGS += -DNO_TEXTURE_CACHE=0
+endif
+
+ifeq ($(TARGET_BOOTANIMATION_TEXTURE_CACHE),false)
+ LOCAL_CFLAGS += -DNO_TEXTURE_CACHE=1
+endif
+
+ifeq ($(TARGET_BOOTANIMATION_USE_RGB565),true)
+ LOCAL_CFLAGS += -DUSE_565
+endif
LOCAL_MODULE:= bootanimation
diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp
index 8f361ce..b153454 100644
--- a/cmds/bootanimation/BootAnimation.cpp
+++ b/cmds/bootanimation/BootAnimation.cpp
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2007 The Android Open Source Project
+ * Copyright (c) 2012-2014, The Linux Foundation. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -24,6 +25,8 @@
#include <utils/misc.h>
#include <signal.h>
#include <time.h>
+#include <pthread.h>
+#include <sys/select.h>
#include <cutils/properties.h>
@@ -54,12 +57,28 @@
#include <GLES/glext.h>
#include <EGL/eglext.h>
+#include <media/AudioSystem.h>
+#include <media/mediaplayer.h>
+#include <media/IMediaHTTPService.h>
+
#include "BootAnimation.h"
#include "AudioPlayer.h"
#define OEM_BOOTANIMATION_FILE "/oem/media/bootanimation.zip"
#define SYSTEM_BOOTANIMATION_FILE "/system/media/bootanimation.zip"
#define SYSTEM_ENCRYPTED_BOOTANIMATION_FILE "/system/media/bootanimation-encrypted.zip"
+#define THEME_BOOTANIMATION_FILE "/data/system/theme/bootanimation.zip"
+
+#define OEM_SHUTDOWN_ANIMATION_FILE "/oem/media/shutdownanimation.zip"
+#define SYSTEM_SHUTDOWN_ANIMATION_FILE "/system/media/shutdownanimation.zip"
+#define SYSTEM_ENCRYPTED_SHUTDOWN_ANIMATION_FILE "/system/media/shutdownanimation-encrypted.zip"
+
+#define OEM_BOOT_MUSIC_FILE "/oem/media/boot.wav"
+#define SYSTEM_BOOT_MUSIC_FILE "/system/media/boot.wav"
+
+#define OEM_SHUTDOWN_MUSIC_FILE "/oem/media/shutdown.wav"
+#define SYSTEM_SHUTDOWN_MUSIC_FILE "/system/media/shutdown.wav"
+
#define EXIT_PROP_NAME "service.bootanim.exit"
namespace android {
@@ -68,6 +87,87 @@ static const int ANIM_ENTRY_NAME_MAX = 256;
// ---------------------------------------------------------------------------
+static pthread_mutex_t mp_lock;
+static pthread_cond_t mp_cond;
+static bool isMPlayerPrepared = false;
+static bool isMPlayerCompleted = false;
+
+class MPlayerListener : public MediaPlayerListener
+{
+ void notify(int msg, int /*ext1*/, int /*ext2*/, const Parcel * /*obj*/)
+ {
+ switch (msg) {
+ case MEDIA_NOP: // interface test message
+ break;
+ case MEDIA_PREPARED:
+ pthread_mutex_lock(&mp_lock);
+ isMPlayerPrepared = true;
+ pthread_cond_signal(&mp_cond);
+ pthread_mutex_unlock(&mp_lock);
+ break;
+ case MEDIA_PLAYBACK_COMPLETE:
+ pthread_mutex_lock(&mp_lock);
+ isMPlayerCompleted = true;
+ pthread_cond_signal(&mp_cond);
+ pthread_mutex_unlock(&mp_lock);
+ break;
+ default:
+ break;
+ }
+ }
+};
+
+static unsigned long getFreeMemory(void)
+{
+ int fd = open("/proc/meminfo", O_RDONLY);
+ const char* const sums[] = { "MemFree:", "Cached:", NULL };
+ const size_t sumsLen[] = { strlen("MemFree:"), strlen("Cached:"), 0 };
+ unsigned int num = 2;
+
+ if (fd < 0) {
+ ALOGW("Unable to open /proc/meminfo");
+ return -1;
+ }
+
+ char buffer[256];
+ const int len = read(fd, buffer, sizeof(buffer)-1);
+ close(fd);
+
+ if (len < 0) {
+ ALOGW("Unable to read /proc/meminfo");
+ return -1;
+ }
+ buffer[len] = 0;
+
+ size_t numFound = 0;
+ unsigned long mem = 0;
+
+ char* p = buffer;
+ while (*p && numFound < num) {
+ int i = 0;
+ while (sums[i]) {
+ if (strncmp(p, sums[i], sumsLen[i]) == 0) {
+ p += sumsLen[i];
+ while (*p == ' ') p++;
+ char* num = p;
+ while (*p >= '0' && *p <= '9') p++;
+ if (*p != 0) {
+ *p = 0;
+ p++;
+ if (*p == 0) p--;
+ }
+ mem += atoll(num);
+ numFound++;
+ break;
+ }
+ i++;
+ }
+ p++;
+ }
+
+ return numFound > 0 ? mem : -1;
+}
+
BootAnimation::BootAnimation() : Thread(false), mZip(NULL)
{
mSession = new SurfaceComposerClient();
@@ -171,16 +271,15 @@ status_t BootAnimation::initTexture(const Animation::Frame& frame)
if (codec != NULL) {
codec->setDitherImage(false);
codec->decode(&stream, &bitmap,
+ #ifdef USE_565
+ kRGB_565_SkColorType,
+ #else
kN32_SkColorType,
+ #endif
SkImageDecoder::kDecodePixels_Mode);
delete codec;
}
- // FileMap memory is never released until application exit.
- // Release it now as the texture is already loaded and the memory used for
- // the packed resource can be released.
- delete frame.map;
-
// ensure we can call getPixels(). No need to call unlock, since the
// bitmap will go out of scope when we return from this method.
bitmap.lockPixels();
@@ -237,6 +336,18 @@ status_t BootAnimation::readyToRun() {
status_t status = SurfaceComposerClient::getDisplayInfo(dtoken, &dinfo);
if (status)
return -1;
+ char value[PROPERTY_VALUE_MAX];
+ property_get("persist.panel.orientation", value, "0");
+ int orient = atoi(value) / 90;
+
+ if(orient == eOrientation90 || orient == eOrientation270) {
+ int temp = dinfo.h;
+ dinfo.h = dinfo.w;
+ dinfo.w = temp;
+ }
+
+ Rect destRect(dinfo.w, dinfo.h);
+ mSession->setDisplayProjection(dtoken, orient, destRect, destRect);
// create the native surface
sp<SurfaceControl> control = session()->createSurface(String8("BootAnimation"),
@@ -287,21 +398,63 @@ status_t BootAnimation::readyToRun() {
char decrypt[PROPERTY_VALUE_MAX];
property_get("vold.decrypt", decrypt, "");
+ // Use customized resources for boot and showdown animation
+ // instead of system predefined boot animation files.
bool encryptedAnimation = atoi(decrypt) != 0 || !strcmp("trigger_restart_min_framework", decrypt);
ZipFileRO* zipFile = NULL;
if ((encryptedAnimation &&
- (access(SYSTEM_ENCRYPTED_BOOTANIMATION_FILE, R_OK) == 0) &&
- ((zipFile = ZipFileRO::open(SYSTEM_ENCRYPTED_BOOTANIMATION_FILE)) != NULL)) ||
+ (access(getAnimationFileName(IMG_ENC), R_OK) == 0) &&
+ ((zipFile = ZipFileRO::open(getAnimationFileName(IMG_ENC))) != NULL)) ||
+
+ ((access(THEME_BOOTANIMATION_FILE, R_OK) == 0) &&
+ ((zipFile = ZipFileRO::open(THEME_BOOTANIMATION_FILE)) != NULL)) ||
((access(OEM_BOOTANIMATION_FILE, R_OK) == 0) &&
((zipFile = ZipFileRO::open(OEM_BOOTANIMATION_FILE)) != NULL)) ||
((access(SYSTEM_BOOTANIMATION_FILE, R_OK) == 0) &&
- ((zipFile = ZipFileRO::open(SYSTEM_BOOTANIMATION_FILE)) != NULL))) {
+ ((zipFile = ZipFileRO::open(SYSTEM_BOOTANIMATION_FILE)) != NULL)) ||
+
+ ((access(getAnimationFileName(IMG_DATA), R_OK) == 0) &&
+ ((zipFile = ZipFileRO::open(getAnimationFileName(IMG_DATA))) != NULL)) ||
+
+ ((access(getAnimationFileName(IMG_SYS), R_OK) == 0) &&
+ ((zipFile = ZipFileRO::open(getAnimationFileName(IMG_SYS))) != NULL))) {
mZip = zipFile;
}
+#ifdef PRELOAD_BOOTANIMATION
+ // Preload the bootanimation zip on memory, so we don't stutter
+ // when showing the animation
+ FILE* fd;
+ if (encryptedAnimation && access(SYSTEM_ENCRYPTED_BOOTANIMATION_FILE, R_OK) == 0)
+ fd = fopen(SYSTEM_ENCRYPTED_BOOTANIMATION_FILE, "r");
+ else if (access(OEM_BOOTANIMATION_FILE, R_OK) == 0)
+ fd = fopen(OEM_BOOTANIMATION_FILE, "r");
+ else if (access(SYSTEM_BOOTANIMATION_FILE, R_OK) == 0)
+ fd = fopen(SYSTEM_BOOTANIMATION_FILE, "r");
+ else
+ return NO_ERROR;
+
+ if (fd != NULL) {
+ // We could use readahead..
+ // ... if bionic supported it :(
+ //readahead(fd, 0, INT_MAX);
+ void *crappyBuffer = malloc(2*1024*1024);
+ if (crappyBuffer != NULL) {
+ // Read all the zip
+ while (!feof(fd))
+ fread(crappyBuffer, 1024, 2*1024, fd);
+
+ free(crappyBuffer);
+ } else {
+ ALOGW("Unable to allocate memory to preload the animation");
+ }
+ fclose(fd);
+ }
+#endif
+
return NO_ERROR;
}
@@ -452,6 +605,7 @@ bool BootAnimation::readFile(const char* name, String8& outString)
bool BootAnimation::movie()
{
+ char value[PROPERTY_VALUE_MAX];
String8 desString;
if (!readFile("desc.txt", desString)) {
@@ -556,11 +710,14 @@ bool BootAnimation::movie()
mZip->endIteration(cookie);
+#ifndef CONTINUOUS_SPLASH
glShadeModel(GL_FLAT);
glDisable(GL_DITHER);
glDisable(GL_SCISSOR_TEST);
glDisable(GL_BLEND);
+#endif
+
glBindTexture(GL_TEXTURE_2D, 0);
glEnable(GL_TEXTURE_2D);
glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
@@ -576,11 +733,46 @@ bool BootAnimation::movie()
Region clearReg(Rect(mWidth, mHeight));
clearReg.subtractSelf(Rect(xc, yc, xc+animation.width, yc+animation.height));
+ pthread_mutex_init(&mp_lock, NULL);
+ pthread_cond_init(&mp_cond, NULL);
+
+ property_get("persist.sys.silent", value, "null");
+ if (strncmp(value, "1", 1) != 0) {
+ playBackgroundMusic();
+ }
for (size_t i=0 ; i<pcount ; i++) {
const Animation::Part& part(animation.parts[i]);
const size_t fcount = part.frames.size();
+
+ // can be 1, 0, or not set
+ #ifdef NO_TEXTURE_CACHE
+ const int noTextureCache = NO_TEXTURE_CACHE;
+ #else
+ const int noTextureCache =
+ ((animation.width * animation.height * fcount) > 48 * 1024 * 1024) ? 1 : 0;
+ #endif
+
glBindTexture(GL_TEXTURE_2D, 0);
+ /*calculate if we need to runtime save memory
+ * condition: runtime free memory is less than the textures that will used.
+ * needSaveMem default to be false
+ */
+ GLint mMaxTextureSize;
+ bool needSaveMem = false;
+ GLuint mTextureid;
+ glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize);
+ //ALOGD("freemem:%ld, %d", getFreeMemory(), mMaxTextureSize);
+ if(getFreeMemory() < mMaxTextureSize * mMaxTextureSize * fcount / 1024 || noTextureCache) {
+ ALOGD("Use save memory method, maybe small fps in actual.");
+ needSaveMem = true;
+ glGenTextures(1, &mTextureid);
+ glBindTexture(GL_TEXTURE_2D, mTextureid);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+ }
+
for (int r=0 ; !part.count || r<part.count ; r++) {
// Exit any non playuntil complete parts immediately
if(exitPending() && !part.playUntilComplete)
@@ -601,10 +793,10 @@ bool BootAnimation::movie()
const Animation::Frame& frame(part.frames[j]);
nsecs_t lastFrame = systemTime();
- if (r > 0) {
+ if (r > 0 && !needSaveMem) {
glBindTexture(GL_TEXTURE_2D, frame.tid);
} else {
- if (part.count != 1) {
+ if (!needSaveMem && part.count != 1) {
glGenTextures(1, &frame.tid);
glBindTexture(GL_TEXTURE_2D, frame.tid);
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
@@ -657,18 +849,169 @@ bool BootAnimation::movie()
}
// free the textures for this part
- if (part.count != 1) {
+ if (!needSaveMem && part.count != 1) {
for (size_t j=0 ; j<fcount ; j++) {
const Animation::Frame& frame(part.frames[j]);
glDeleteTextures(1, &frame.tid);
}
}
+
+ if (needSaveMem) {
+ glDeleteTextures(1, &mTextureid);
+ }
+
}
+ if (isMPlayerPrepared) {
+ ALOGD("waiting for media player to complete.");
+ struct timespec timeout;
+ clock_gettime(CLOCK_REALTIME, &timeout);
+ timeout.tv_sec += 5; //timeout after 5s.
+
+ pthread_mutex_lock(&mp_lock);
+ while (!isMPlayerCompleted) {
+ int err = pthread_cond_timedwait(&mp_cond, &mp_lock, &timeout);
+ if (err == ETIMEDOUT) {
+ break;
+ }
+ }
+ pthread_mutex_unlock(&mp_lock);
+ ALOGD("media player is completed.");
+ }
+
+ pthread_cond_destroy(&mp_cond);
+ pthread_mutex_destroy(&mp_lock);
+
return false;
}
-// ---------------------------------------------------------------------------
+const char *BootAnimation::getAnimationFileName(ImageID image)
+{
+ const char *fileName[2][3] = { { OEM_BOOTANIMATION_FILE,
+ SYSTEM_BOOTANIMATION_FILE,
+ SYSTEM_ENCRYPTED_BOOTANIMATION_FILE }, {
+ OEM_SHUTDOWN_ANIMATION_FILE,
+ SYSTEM_SHUTDOWN_ANIMATION_FILE,
+ SYSTEM_ENCRYPTED_SHUTDOWN_ANIMATION_FILE} };
+ int state;
+ char sku[PROPERTY_VALUE_MAX];
+ char skusuffix[PATH_MAX];
+
+ state = checkBootState() ? 0 : 1;
+
+ property_get("ro.prebundled.mcc", sku, "000");
+ sprintf(skusuffix,"-%s",sku);
+ String16 skuPath(fileName[state][image]);
+ skuPath.insert(skuPath.size()-4,String16(skusuffix));
+
+ if (access(String8(skuPath).string(), R_OK) == 0)
+ return (char *)String8(skuPath).string();
+
+ return fileName[state][image];
}
-; // namespace android
+
+const char *BootAnimation::getBootRingtoneFileName(ImageID image)
+{
+ if (image == IMG_ENC) {
+ return NULL;
+ }
+
+ const char *fileName[2][2] = { { OEM_BOOT_MUSIC_FILE,
+ SYSTEM_BOOT_MUSIC_FILE }, {
+ OEM_SHUTDOWN_MUSIC_FILE,
+ SYSTEM_SHUTDOWN_MUSIC_FILE } };
+ int state;
+
+ state = checkBootState() ? 0 : 1;
+
+ return fileName[state][image];
+}
+
+static void* playMusic(void* arg)
+{
+ int index = 0;
+ char *fileName = (char *)arg;
+ sp<MediaPlayer> mp = new MediaPlayer();
+ sp<MPlayerListener> mListener = new MPlayerListener();
+ if (mp != NULL) {
+ ALOGD("starting to play %s", fileName);
+ mp->setListener(mListener);
+
+ if (mp->setDataSource(NULL, fileName, NULL) == NO_ERROR) {
+ mp->setAudioStreamType(AUDIO_STREAM_ENFORCED_AUDIBLE);
+ mp->prepare();
+ } else {
+ ALOGE("failed to setDataSource for %s", fileName);
+ return NULL;
+ }
+
+ //waiting for media player is prepared.
+ pthread_mutex_lock(&mp_lock);
+ while (!isMPlayerPrepared) {
+ pthread_cond_wait(&mp_cond, &mp_lock);
+ }
+ pthread_mutex_unlock(&mp_lock);
+
+ audio_devices_t device = AudioSystem::getDevicesForStream(AUDIO_STREAM_ENFORCED_AUDIBLE);
+ AudioSystem::initStreamVolume(AUDIO_STREAM_ENFORCED_AUDIBLE,0,7);
+ AudioSystem::setStreamVolumeIndex(AUDIO_STREAM_ENFORCED_AUDIBLE, 7, device);
+
+ AudioSystem::getStreamVolumeIndex(AUDIO_STREAM_ENFORCED_AUDIBLE, &index, device);
+ if (index != 0) {
+ ALOGD("playing %s", fileName);
+ mp->seekTo(0);
+ mp->start();
+ } else {
+ ALOGW("current volume is zero.");
+ }
+ }
+ return NULL;
+}
+
+void BootAnimation::playBackgroundMusic(void)
+{
+ //Shutdown music is playing in ShutdownThread.java
+ if (!checkBootState()) {
+ return;
+ }
+
+ /* Make sure sound cards are populated */
+ FILE* fp = NULL;
+ if ((fp = fopen("/proc/asound/cards", "r")) == NULL) {
+ ALOGW("Cannot open /proc/asound/cards file to get sound card info.");
+ }
+
+ char value[PROPERTY_VALUE_MAX];
+ property_get("qcom.audio.init", value, "null");
+ if (strncmp(value, "complete", 8) != 0) {
+ ALOGW("Audio service is not initiated.");
+ }
+
+ fclose(fp);
+
+ const char *fileName;
+ if (((fileName = getBootRingtoneFileName(IMG_DATA)) != NULL && access(fileName, R_OK) == 0) ||
+ ((fileName = getBootRingtoneFileName(IMG_SYS)) != NULL
+ && access(fileName, R_OK) == 0)) {
+ pthread_t tid;
+ pthread_create(&tid, NULL, playMusic, (void *)fileName);
+ pthread_join(tid, NULL);
+ }
+}
+bool BootAnimation::checkBootState(void)
+{
+ char value[PROPERTY_VALUE_MAX];
+ bool ret = true;
+
+ property_get("sys.shutdown.requested", value, "null");
+ if (strncmp(value, "null", 4) != 0) {
+ ret = false;
+ }
+
+ return ret;
+}
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/cmds/bootanimation/BootAnimation.h b/cmds/bootanimation/BootAnimation.h
index f968b25..5bc1e8a 100644
--- a/cmds/bootanimation/BootAnimation.h
+++ b/cmds/bootanimation/BootAnimation.h
@@ -40,6 +40,12 @@ class SurfaceControl;
class BootAnimation : public Thread, public IBinder::DeathRecipient
{
public:
+ enum {
+ eOrientationDefault = 0,
+ eOrientation90 = 1,
+ eOrientation180 = 2,
+ eOrientation270 = 3,
+ };
BootAnimation();
virtual ~BootAnimation();
@@ -87,12 +93,18 @@ private:
bool readFile(const char* name, String8& outString);
bool movie();
+ enum ImageID { IMG_DATA = 0, IMG_SYS = 1, IMG_ENC = 2 };
+ const char *getAnimationFileName(ImageID image);
+ const char *getBootRingtoneFileName(ImageID image);
+ void playBackgroundMusic();
+ bool checkBootState();
void checkExit();
+ void checkShowAndroid();
sp<SurfaceComposerClient> mSession;
sp<AudioPlayer> mAudioPlayer;
AssetManager mAssets;
- Texture mAndroid[2];
+ Texture mAndroid[3];
int mWidth;
int mHeight;
EGLDisplay mDisplay;
diff --git a/cmds/bootanimation/bootanimation_main.cpp b/cmds/bootanimation/bootanimation_main.cpp
index 48a34e7..50e4b1f 100644
--- a/cmds/bootanimation/bootanimation_main.cpp
+++ b/cmds/bootanimation/bootanimation_main.cpp
@@ -38,8 +38,9 @@ int main()
property_get("debug.sf.nobootanimation", value, "0");
int noBootAnimation = atoi(value);
ALOGI_IF(noBootAnimation, "boot animation disabled");
- if (!noBootAnimation) {
+ property_get("ro.alarm_boot", value, "false");
+ if (!noBootAnimation && strcmp(value, "true")) {
sp<ProcessState> proc(ProcessState::self());
ProcessState::self()->startThreadPool();
diff --git a/cmds/content/src/com/android/commands/content/Content.java b/cmds/content/src/com/android/commands/content/Content.java
index c0ed893..1d8b8b1 100644
--- a/cmds/content/src/com/android/commands/content/Content.java
+++ b/cmds/content/src/com/android/commands/content/Content.java
@@ -103,10 +103,12 @@ public class Content {
+ "--where \"name=\'new_setting\'\"\n"
+ "\n"
+ "usage: adb shell content query --uri <URI> [--user <USER_ID>]"
- + " [--projection <PROJECTION>] [--where <WHERE>] [--sort <SORT_ORDER>]\n"
+ + " [--projection <PROJECTION>] [--where <WHERE>] [--sort <SORT_ORDER>] "
+ + " [--show-type <SHOW-TYPE>] \n"
+ " <PROJECTION> is a list of colon separated column names and is formatted:\n"
+ " <COLUMN_NAME>[:<COLUMN_NAME>...]\n"
+ " <SORT_ORDER> is the order in which rows in the result should be sorted.\n"
+ + " <SHOW-TYPE> if true shows the type of value of each projection column"
+ " Example:\n"
+ " # Select \"name\" and \"value\" columns from secure settings where \"name\" is "
+ "equal to \"new_setting\" and sort the result by name in ascending order.\n"
@@ -142,6 +144,7 @@ public class Content {
private static final String ARGUMENT_METHOD = "--method";
private static final String ARGUMENT_ARG = "--arg";
private static final String ARGUMENT_EXTRA = "--extra";
+ private static final String ARGUMENT_SHOW_TYPE = "--show-type";
private static final String TYPE_BOOLEAN = "b";
private static final String TYPE_STRING = "s";
private static final String TYPE_INTEGER = "i";
@@ -316,6 +319,7 @@ public class Content {
String[] projection = null;
String sort = null;
String where = null;
+ boolean showType = false;
for (String argument; (argument = mTokenizer.nextArg())!= null;) {
if (ARGUMENT_URI.equals(argument)) {
uri = Uri.parse(argumentValueRequired(argument));
@@ -327,6 +331,8 @@ public class Content {
sort = argumentValueRequired(argument);
} else if (ARGUMENT_PROJECTION.equals(argument)) {
projection = argumentValueRequired(argument).split("[\\s]*:[\\s]*");
+ } else if (ARGUMENT_SHOW_TYPE.equals(argument)) {
+ showType = argumentValueRequiredForBoolean(argument);
} else {
throw new IllegalArgumentException("Unsupported argument: " + argument);
}
@@ -335,7 +341,7 @@ public class Content {
throw new IllegalArgumentException("Content provider URI not specified."
+ " Did you specify --uri argument?");
}
- return new QueryCommand(uri, userId, projection, where, sort);
+ return new QueryCommand(uri, userId, projection, where, sort, showType);
}
private void parseBindValue(ContentValues values) {
@@ -367,6 +373,14 @@ public class Content {
}
}
+ private boolean argumentValueRequiredForBoolean(String argument) {
+ String value = mTokenizer.nextArg();
+ if (TextUtils.isEmpty(value) || value.startsWith(ARGUMENT_PREFIX)) {
+ throw new IllegalArgumentException("No value for argument: " + argument);
+ }
+ return value.equals("true");
+ }
+
private String argumentValueRequired(String argument) {
String value = mTokenizer.nextArg();
if (TextUtils.isEmpty(value) || value.startsWith(ARGUMENT_PREFIX)) {
@@ -539,12 +553,15 @@ public class Content {
private static class QueryCommand extends DeleteCommand {
final String[] mProjection;
final String mSortOrder;
+ final boolean mShowType;
public QueryCommand(
- Uri uri, int userId, String[] projection, String where, String sortOrder) {
+ Uri uri, int userId, String[] projection, String where, String sortOrder,
+ boolean showType) {
super(uri, userId, where);
mProjection = projection;
mSortOrder = sortOrder;
+ mShowType = showType;
}
@Override
@@ -590,6 +607,7 @@ public class Content {
break;
}
builder.append(columnName).append("=").append(columnValue);
+ if (mShowType) builder.append(", type=").append(type);
}
System.out.println(builder);
} while (cursor.moveToNext());
diff --git a/cmds/idmap/create.cpp b/cmds/idmap/create.cpp
index 41395f1..dd0554e 100644
--- a/cmds/idmap/create.cpp
+++ b/cmds/idmap/create.cpp
@@ -33,6 +33,7 @@ namespace {
int open_idmap(const char *path)
{
int fd = TEMP_FAILURE_RETRY(open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644));
+ bool needUnlink = true;
if (fd == -1) {
ALOGD("error: open %s: %s\n", path, strerror(errno));
goto fail;
@@ -41,8 +42,10 @@ namespace {
ALOGD("error: fchmod %s: %s\n", path, strerror(errno));
goto fail;
}
- if (TEMP_FAILURE_RETRY(flock(fd, LOCK_EX | LOCK_NB)) != 0) {
+ if (TEMP_FAILURE_RETRY(flock(fd, LOCK_EX)) != 0) {
ALOGD("error: flock %s: %s\n", path, strerror(errno));
+ // If the file is locked by another process, then we needn't unlink the file.
+ needUnlink = false;
goto fail;
}
@@ -50,7 +53,7 @@ namespace {
fail:
if (fd != -1) {
close(fd);
- unlink(path);
+ if (needUnlink) unlink(path);
}
return -1;
}
@@ -150,26 +153,26 @@ fail:
}
int create_idmap(const char *target_apk_path, const char *overlay_apk_path,
- uint32_t **data, size_t *size)
+ const char *cache_path, uint32_t target_hash, uint32_t overlay_hash, uint32_t **data,
+ size_t *size)
{
uint32_t target_crc, overlay_crc;
- if (get_zip_entry_crc(target_apk_path, AssetManager::RESOURCES_FILENAME,
- &target_crc) == -1) {
- return -1;
- }
- if (get_zip_entry_crc(overlay_apk_path, AssetManager::RESOURCES_FILENAME,
- &overlay_crc) == -1) {
- return -1;
- }
+
+ // In the original implementation, crc of the res tables are generated
+ // theme apks however do not need a restable, everything is in assets/
+ // instead timestamps are used
+ target_crc = 0;
+ overlay_crc = 0;
AssetManager am;
- bool b = am.createIdmap(target_apk_path, overlay_apk_path, target_crc, overlay_crc,
- data, size);
+ bool b = am.createIdmap(target_apk_path, overlay_apk_path, cache_path, target_crc,
+ overlay_crc, target_hash, overlay_hash, data, size);
return b ? 0 : -1;
}
int create_and_write_idmap(const char *target_apk_path, const char *overlay_apk_path,
- int fd, bool check_if_stale)
+ const char *cache_path, uint32_t target_hash, uint32_t overlay_hash, int fd,
+ bool check_if_stale)
{
if (check_if_stale) {
if (!is_idmap_stale_fd(target_apk_path, overlay_apk_path, fd)) {
@@ -181,7 +184,8 @@ fail:
uint32_t *data = NULL;
size_t size;
- if (create_idmap(target_apk_path, overlay_apk_path, &data, &size) == -1) {
+ if (create_idmap(target_apk_path, overlay_apk_path, cache_path, target_hash, overlay_hash,
+ &data, &size) == -1) {
return -1;
}
@@ -196,6 +200,7 @@ fail:
}
int idmap_create_path(const char *target_apk_path, const char *overlay_apk_path,
+ const char *cache_path, uint32_t target_hash, uint32_t overlay_hash,
const char *idmap_path)
{
if (!is_idmap_stale_path(target_apk_path, overlay_apk_path, idmap_path)) {
@@ -208,7 +213,8 @@ int idmap_create_path(const char *target_apk_path, const char *overlay_apk_path,
return EXIT_FAILURE;
}
- int r = create_and_write_idmap(target_apk_path, overlay_apk_path, fd, false);
+ int r = create_and_write_idmap(target_apk_path, overlay_apk_path, cache_path,
+ target_hash, overlay_hash, fd, false);
close(fd);
if (r != 0) {
unlink(idmap_path);
@@ -216,8 +222,10 @@ int idmap_create_path(const char *target_apk_path, const char *overlay_apk_path,
return r == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
}
-int idmap_create_fd(const char *target_apk_path, const char *overlay_apk_path, int fd)
+int idmap_create_fd(const char *target_apk_path, const char *overlay_apk_path,
+ const char *cache_path, uint32_t target_hash, uint32_t overlay_hash, int fd)
{
- return create_and_write_idmap(target_apk_path, overlay_apk_path, fd, true) == 0 ?
+ return create_and_write_idmap(target_apk_path, overlay_apk_path, cache_path, target_hash,
+ overlay_hash, fd, true) == 0 ?
EXIT_SUCCESS : EXIT_FAILURE;
}
diff --git a/cmds/idmap/idmap.cpp b/cmds/idmap/idmap.cpp
index 90cfa2c..cc3f231 100644
--- a/cmds/idmap/idmap.cpp
+++ b/cmds/idmap/idmap.cpp
@@ -66,29 +66,31 @@ EXAMPLES \n\
Display an idmap file: \n\
\n\
$ adb shell idmap --inspect /data/resource-cache/vendor@overlay@overlay.apk@idmap \n\
- SECTION ENTRY VALUE COMMENT \n\
- IDMAP HEADER magic 0x706d6469 \n\
- base crc 0xb65a383f \n\
- overlay crc 0x7b9675e8 \n\
- base path .......... /path/to/target.apk \n\
- overlay path .......... /path/to/overlay.apk \n\
- DATA HEADER target pkg 0x0000007f \n\
- types count 0x00000003 \n\
- DATA BLOCK target type 0x00000002 \n\
- overlay type 0x00000002 \n\
- entry count 0x00000001 \n\
- entry offset 0x00000000 \n\
- entry 0x00000000 drawable/drawable \n\
- DATA BLOCK target type 0x00000003 \n\
- overlay type 0x00000003 \n\
- entry count 0x00000001 \n\
- entry offset 0x00000000 \n\
- entry 0x00000000 xml/integer \n\
- DATA BLOCK target type 0x00000004 \n\
- overlay type 0x00000004 \n\
- entry count 0x00000001 \n\
- entry offset 0x00000000 \n\
- entry 0x00000000 raw/lorem_ipsum \n\
+ SECTION ENTRY VALUE COMMENT \n\
+ IDMAP HEADER magic 0x706d6469 \n\
+ base crc 0xb65a383f \n\
+ overlay crc 0x7b9675e8 \n\
+ base mtime 0x1eb47d51 \n\
+ overlay mtime 0x185f87a2 \n\
+ base path .......... /path/to/target.apk \n\
+ overlay path .......... /path/to/overlay.apk \n\
+ DATA HEADER target pkg 0x0000007f \n\
+ types count 0x00000003 \n\
+ DATA BLOCK target type 0x00000002 \n\
+ overlay type 0x00000002 \n\
+ entry count 0x00000001 \n\
+ entry offset 0x00000000 \n\
+ entry 0x00000000 drawable/drawable \n\
+ DATA BLOCK target type 0x00000003 \n\
+ overlay type 0x00000003 \n\
+ entry count 0x00000001 \n\
+ entry offset 0x00000000 \n\
+ entry 0x00000000 xml/integer \n\
+ DATA BLOCK target type 0x00000004 \n\
+ overlay type 0x00000004 \n\
+ entry count 0x00000001 \n\
+ entry offset 0x00000000 \n\
+ entry 0x00000000 raw/lorem_ipsum \n\
\n\
In this example, the overlay package provides three alternative resource values:\n\
drawable/drawable, xml/integer, and raw/lorem_ipsum \n\
@@ -120,7 +122,8 @@ NOTES \n\
}
int maybe_create_fd(const char *target_apk_path, const char *overlay_apk_path,
- const char *idmap_str)
+ const char *cache_path, const char *idmap_str, const char *target_hash_str,
+ const char *overlay_hash_str)
{
// anyone (not just root or system) may do --fd -- the file has
// already been opened by someone else on our behalf
@@ -141,12 +144,16 @@ NOTES \n\
ALOGD("error: failed to read apk %s: %s\n", overlay_apk_path, strerror(errno));
return -1;
}
+ int target_hash = strtol(target_hash_str, 0, 10);
+ int overlay_hash = strtol(overlay_hash_str, 0, 10);
- return idmap_create_fd(target_apk_path, overlay_apk_path, idmap_fd);
+ return idmap_create_fd(target_apk_path, overlay_apk_path, cache_path, target_hash,
+ overlay_hash, idmap_fd);
}
int maybe_create_path(const char *target_apk_path, const char *overlay_apk_path,
- const char *idmap_path)
+ const char *cache_path, const char *idmap_path, const char *target_hash_str,
+ const char *overlay_hash_str)
{
if (!verify_root_or_system()) {
fprintf(stderr, "error: permission denied: not user root or user system\n");
@@ -163,7 +170,10 @@ NOTES \n\
return -1;
}
- return idmap_create_path(target_apk_path, overlay_apk_path, idmap_path);
+ int target_hash = strtol(target_hash_str, 0, 10);
+ int overlay_hash = strtol(overlay_hash_str, 0, 10);
+ return idmap_create_path(target_apk_path, overlay_apk_path, cache_path, target_hash,
+ overlay_hash, idmap_path);
}
int maybe_scan(const char *overlay_dir, const char *target_package_name,
@@ -222,12 +232,12 @@ int main(int argc, char **argv)
return 0;
}
- if (argc == 5 && !strcmp(argv[1], "--fd")) {
- return maybe_create_fd(argv[2], argv[3], argv[4]);
+ if (argc == 8 && !strcmp(argv[1], "--fd")) {
+ return maybe_create_fd(argv[2], argv[3], argv[4], argv[5], argv[6], argv[7]);
}
- if (argc == 5 && !strcmp(argv[1], "--path")) {
- return maybe_create_path(argv[2], argv[3], argv[4]);
+ if (argc == 8 && !strcmp(argv[1], "--path")) {
+ return maybe_create_path(argv[2], argv[3], argv[4], argv[5], argv[6], argv[7]);
}
if (argc == 6 && !strcmp(argv[1], "--scan")) {
diff --git a/cmds/idmap/idmap.h b/cmds/idmap/idmap.h
index f507dd8..6a9c5ef 100644
--- a/cmds/idmap/idmap.h
+++ b/cmds/idmap/idmap.h
@@ -19,9 +19,12 @@
#endif
int idmap_create_path(const char *target_apk_path, const char *overlay_apk_path,
+ const char *cache_path, uint32_t target_hash, uint32_t overlay_hash,
const char *idmap_path);
-int idmap_create_fd(const char *target_apk_path, const char *overlay_apk_path, int fd);
+int idmap_create_fd(const char *target_apk_path, const char *overlay_apk_path,
+ const char *cache_path, uint32_t target_hash, uint32_t overlay_hash,
+ int fd);
// Regarding target_package_name: the idmap_scan implementation should
// be able to extract this from the manifest in target_apk_path,
diff --git a/cmds/idmap/inspect.cpp b/cmds/idmap/inspect.cpp
index f6afc85..3087e6e 100644
--- a/cmds/idmap/inspect.cpp
+++ b/cmds/idmap/inspect.cpp
@@ -200,6 +200,18 @@ namespace {
}
print("", "overlay crc", i, "");
+ err = buf.nextUint32(&i);
+ if (err != NO_ERROR) {
+ return err;
+ }
+ print("", "base mtime", i, "");
+
+ err = buf.nextUint32(&i);
+ if (err != NO_ERROR) {
+ return err;
+ }
+ print("", "overlay mtime", i, "");
+
err = buf.nextPath(path);
if (err != NO_ERROR) {
// printe done from IdmapBuffer::nextPath
@@ -223,7 +235,8 @@ namespace {
}
status_t parse_data(IdmapBuffer& buf, const AssetManager& am) {
- const uint32_t packageId = am.getResources().getBasePackageId(0);
+ const ResTable& rt = am.getResources();
+ const uint32_t packageId = rt.getBasePackageId(rt.getBasePackageCount() - 1);
uint16_t data16;
status_t err = buf.nextUint16(&data16);
diff --git a/cmds/idmap/scan.cpp b/cmds/idmap/scan.cpp
index 612a7eb..b319e68 100644
--- a/cmds/idmap/scan.cpp
+++ b/cmds/idmap/scan.cpp
@@ -25,8 +25,7 @@ namespace {
bool operator<(Overlay const& rhs) const
{
- // Note: order is reversed by design
- return rhs.priority < priority;
+ return rhs.priority > priority;
}
String8 apk_path;
@@ -165,6 +164,62 @@ namespace {
delete dataMap;
return priority;
}
+
+ int idmap_scan(const char *overlay_dir, const char *target_package_name,
+ const char *target_apk_path, const char *idmap_dir,
+ SortedVector<Overlay>& overlayVector)
+ {
+ DIR *dir = opendir(overlay_dir);
+ if (dir == NULL) {
+ return EXIT_FAILURE;
+ }
+
+ struct dirent *dirent;
+ while ((dirent = readdir(dir)) != NULL) {
+ struct stat st;
+ char overlay_apk_path[PATH_MAX + 1];
+ snprintf(overlay_apk_path, PATH_MAX, "%s/%s", overlay_dir, dirent->d_name);
+ if (stat(overlay_apk_path, &st) < 0) {
+ continue;
+ }
+ if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode)) {
+ continue;
+ }
+
+ if (S_ISDIR(st.st_mode)) {
+ String8 dir_name = String8(overlay_apk_path).getPathLeaf();
+ if (dir_name == "." || dir_name == "..") {
+ // Skip the "." and ".." dir.
+ continue;
+ }
+ idmap_scan(overlay_apk_path, target_package_name, target_apk_path, idmap_dir,
+ overlayVector);
+ } else {
+ int priority = parse_apk(overlay_apk_path, target_package_name);
+ if (priority < 0) {
+ continue;
+ }
+
+ String8 idmap_path(idmap_dir);
+ idmap_path.appendPath(flatten_path(overlay_apk_path + 1));
+ idmap_path.append("@idmap");
+
+ if (idmap_create_path(target_apk_path, overlay_apk_path, NULL, 0, 0,
+ idmap_path.string()) != 0) {
+ ALOGE("error: failed to create idmap for target=%s overlay=%s idmap=%s\n",
+ target_apk_path, overlay_apk_path, idmap_path.string());
+ continue;
+ }
+
+ Overlay overlay(String8(overlay_apk_path), idmap_path, priority);
+ overlayVector.add(overlay);
+ }
+ }
+
+ closedir(dir);
+
+ return EXIT_SUCCESS;
+ }
}
int idmap_scan(const char *overlay_dir, const char *target_package_name,
@@ -176,48 +231,13 @@ int idmap_scan(const char *overlay_dir, const char *target_package_name,
return EXIT_FAILURE;
}
- DIR *dir = opendir(overlay_dir);
- if (dir == NULL) {
- return EXIT_FAILURE;
- }
-
SortedVector<Overlay> overlayVector;
- struct dirent *dirent;
- while ((dirent = readdir(dir)) != NULL) {
- struct stat st;
- char overlay_apk_path[PATH_MAX + 1];
- snprintf(overlay_apk_path, PATH_MAX, "%s/%s", overlay_dir, dirent->d_name);
- if (stat(overlay_apk_path, &st) < 0) {
- continue;
- }
- if (!S_ISREG(st.st_mode)) {
- continue;
- }
-
- int priority = parse_apk(overlay_apk_path, target_package_name);
- if (priority < 0) {
- continue;
- }
-
- String8 idmap_path(idmap_dir);
- idmap_path.appendPath(flatten_path(overlay_apk_path + 1));
- idmap_path.append("@idmap");
-
- if (idmap_create_path(target_apk_path, overlay_apk_path, idmap_path.string()) != 0) {
- ALOGE("error: failed to create idmap for target=%s overlay=%s idmap=%s\n",
- target_apk_path, overlay_apk_path, idmap_path.string());
- continue;
- }
-
- Overlay overlay(String8(overlay_apk_path), idmap_path, priority);
- overlayVector.add(overlay);
- }
-
- closedir(dir);
+ int res = idmap_scan(overlay_dir, target_package_name, target_apk_path, idmap_dir,
+ overlayVector);
- if (!writePackagesList(filename.string(), overlayVector)) {
+ if (res == EXIT_FAILURE || !writePackagesList(filename.string(), overlayVector)) {
return EXIT_FAILURE;
}
- return EXIT_SUCCESS;
+ return res;
}
diff --git a/cmds/input/src/com/android/commands/input/Input.java b/cmds/input/src/com/android/commands/input/Input.java
index 2a7c79b..40148c6 100644
--- a/cmds/input/src/com/android/commands/input/Input.java
+++ b/cmds/input/src/com/android/commands/input/Input.java
@@ -47,6 +47,7 @@ public class Input {
put("touchpad", InputDevice.SOURCE_TOUCHPAD);
put("touchnavigation", InputDevice.SOURCE_TOUCH_NAVIGATION);
put("joystick", InputDevice.SOURCE_JOYSTICK);
+ put("gesture", InputDevice.SOURCE_GESTURE_SENSOR);
}};
diff --git a/cmds/media/src/com/android/commands/media/Media.java b/cmds/media/src/com/android/commands/media/Media.java
index d7f23cb..d185b56 100644
--- a/cmds/media/src/com/android/commands/media/Media.java
+++ b/cmds/media/src/com/android/commands/media/Media.java
@@ -222,6 +222,26 @@ public class Media extends BaseCommand {
System.out.println("onVolumeInfoChanged " + info);
}
+ @Override
+ public void onPlayItemResponse(boolean success) throws RemoteException {
+ System.out.println("onPlayItemResponse ");
+ }
+
+ @Override
+ public void onUpdateNowPlayingEntries(long[] playList) throws RemoteException {
+ System.out.println("onUpdateNowPlayingEntries ");
+ }
+
+ @Override
+ public void onUpdateFolderInfoBrowsedPlayer(String stringUri) throws RemoteException {
+ System.out.println("onUpdateFolderInfoBrowsedPlayer ");
+ }
+
+ @Override
+ public void onUpdateNowPlayingContentChange() throws RemoteException {
+ System.out.println("onUpdateNowPlayingContentChange ");
+ }
+
void printUsageMessage() {
try {
System.out.println("V2Monitoring session " + mController.getTag()
diff --git a/cmds/pm/pm b/cmds/pm/pm
index 8183838..53f85b2 100755
--- a/cmds/pm/pm
+++ b/cmds/pm/pm
@@ -1,3 +1,4 @@
+#!/system/bin/sh
# Script to start "pm" on the device, which has a very rudimentary
# shell.
#
diff --git a/cmds/screencap/screencap.cpp b/cmds/screencap/screencap.cpp
index c469ae4..865a216 100644
--- a/cmds/screencap/screencap.cpp
+++ b/cmds/screencap/screencap.cpp
@@ -50,6 +50,7 @@ static void usage(const char* pname)
"usage: %s [-hp] [-d display-id] [FILENAME]\n"
" -h: this message\n"
" -p: save the file as a png.\n"
+ " -j: save the file as a jpeg.\n"
" -d: specify the display id to capture, default %d.\n"
"If FILENAME ends with .png it will be saved as a png.\n"
"If FILENAME is not given, the results will be printed to stdout.\n",
@@ -112,13 +113,17 @@ int main(int argc, char** argv)
const char* pname = argv[0];
bool png = false;
+ bool jpeg = false;
int32_t displayId = DEFAULT_DISPLAY_ID;
int c;
- while ((c = getopt(argc, argv, "phd:")) != -1) {
+ while ((c = getopt(argc, argv, "pjhd:")) != -1) {
switch (c) {
case 'p':
png = true;
break;
+ case 'j':
+ jpeg = true;
+ break;
case 'd':
displayId = atoi(optarg);
break;
@@ -143,8 +148,14 @@ int main(int argc, char** argv)
return 1;
}
const int len = strlen(fn);
- if (len >= 4 && 0 == strcmp(fn+len-4, ".png")) {
- png = true;
+ if (len >= 4) {
+ if (0 == strcmp(fn+len-4, ".png")) {
+ png = true;
+ } else if (0 == strcmp(fn+len-4, ".jpg")) {
+ jpeg = true;
+ } else if (len > 4 && 0 == strcmp(fn+len-5, ".jpeg")) {
+ jpeg = true;
+ }
}
}
@@ -220,11 +231,12 @@ int main(int argc, char** argv)
}
if (base != NULL) {
- if (png) {
+ if (png || jpeg) {
const SkImageInfo info = SkImageInfo::Make(w, h, flinger2skia(f),
kPremul_SkAlphaType);
SkAutoTUnref<SkData> data(SkImageEncoder::EncodeData(info, base, s*bytesPerPixel(f),
- SkImageEncoder::kPNG_Type, SkImageEncoder::kDefaultQuality));
+ (png ? SkImageEncoder::kPNG_Type : SkImageEncoder::kJPEG_Type),
+ SkImageEncoder::kDefaultQuality));
if (data.get()) {
write(fd, data->data(), data->size());
}
diff --git a/cmds/settings/Android.mk b/cmds/settings/Android.mk
index 05deb99..c397535 100644
--- a/cmds/settings/Android.mk
+++ b/cmds/settings/Android.mk
@@ -4,6 +4,7 @@ LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := $(call all-subdir-java-files)
+LOCAL_STATIC_JAVA_LIBRARIES := org.cyanogenmod.platform.internal
LOCAL_MODULE := settings
LOCAL_MODULE_TAGS := optional
include $(BUILD_JAVA_LIBRARY)
diff --git a/cmds/settings/src/com/android/commands/settings/SettingsCmd.java b/cmds/settings/src/com/android/commands/settings/SettingsCmd.java
index c27d0c0..64610fe 100644
--- a/cmds/settings/src/com/android/commands/settings/SettingsCmd.java
+++ b/cmds/settings/src/com/android/commands/settings/SettingsCmd.java
@@ -29,6 +29,8 @@ import android.os.Process;
import android.os.RemoteException;
import android.os.UserHandle;
import android.provider.Settings;
+import android.text.TextUtils;
+import cyanogenmod.providers.CMSettings;
import java.util.ArrayList;
import java.util.Collections;
@@ -36,6 +38,9 @@ import java.util.List;
public final class SettingsCmd {
+ private static final String SETTINGS_AUTHORITY = Settings.AUTHORITY;
+ private static final String CMSETTINGS_AUTHORITY = CMSettings.AUTHORITY;
+
enum CommandVerb {
UNSPECIFIED,
GET,
@@ -51,6 +56,7 @@ public final class SettingsCmd {
String mTable = null;
String mKey = null;
String mValue = null;
+ boolean mUseCMSettingsProvider = false;
public static void main(String[] args) {
if (args == null || args.length < 2) {
@@ -77,6 +83,8 @@ public final class SettingsCmd {
break;
}
mUser = Integer.parseInt(nextArg());
+ } else if ("--cm".equals(arg)) {
+ mUseCMSettingsProvider = true;
} else if (mVerb == CommandVerb.UNSPECIFIED) {
if ("get".equalsIgnoreCase(arg)) {
mVerb = CommandVerb.GET;
@@ -133,13 +141,21 @@ public final class SettingsCmd {
mUser = UserHandle.USER_OWNER;
}
+ // Implicitly use CMSettings provider if the setting is a legacy setting
+ if (!mUseCMSettingsProvider && isLegacySetting(mTable, mKey)) {
+ System.err.println("'" + mKey + "' has moved to CMSettings. Use --cm to avoid " +
+ "this warning in the future.");
+ mUseCMSettingsProvider = true;
+ }
+
try {
IActivityManager activityManager = ActivityManagerNative.getDefault();
IContentProvider provider = null;
IBinder token = new Binder();
try {
ContentProviderHolder holder = activityManager.getContentProviderExternal(
- "settings", UserHandle.USER_OWNER, token);
+ mUseCMSettingsProvider ? CMSETTINGS_AUTHORITY : SETTINGS_AUTHORITY,
+ UserHandle.USER_OWNER, token);
if (holder == null) {
throw new IllegalStateException("Could not find settings provider");
}
@@ -182,9 +198,15 @@ public final class SettingsCmd {
}
private List<String> listForUser(IContentProvider provider, int userHandle, String table) {
- final Uri uri = "system".equals(table) ? Settings.System.CONTENT_URI
- : "secure".equals(table) ? Settings.Secure.CONTENT_URI
- : "global".equals(table) ? Settings.Global.CONTENT_URI
+ final Uri systemUri = mUseCMSettingsProvider ? CMSettings.System.CONTENT_URI
+ : Settings.System.CONTENT_URI;
+ final Uri secureUri = mUseCMSettingsProvider ? CMSettings.Secure.CONTENT_URI
+ : Settings.Secure.CONTENT_URI;
+ final Uri globalUri = mUseCMSettingsProvider ? CMSettings.Global.CONTENT_URI
+ : Settings.Global.CONTENT_URI;
+ final Uri uri = "system".equals(table) ? systemUri
+ : "secure".equals(table) ? secureUri
+ : "global".equals(table) ? globalUri
: null;
final ArrayList<String> lines = new ArrayList<String>();
if (uri == null) {
@@ -220,10 +242,16 @@ public final class SettingsCmd {
String getForUser(IContentProvider provider, int userHandle,
final String table, final String key) {
+ final String systemGetCommand = mUseCMSettingsProvider ? CMSettings.CALL_METHOD_GET_SYSTEM
+ : Settings.CALL_METHOD_GET_SYSTEM;
+ final String secureGetCommand = mUseCMSettingsProvider ? CMSettings.CALL_METHOD_GET_SECURE
+ : Settings.CALL_METHOD_GET_SECURE;
+ final String globalGetCommand = mUseCMSettingsProvider ? CMSettings.CALL_METHOD_GET_GLOBAL
+ : Settings.CALL_METHOD_GET_GLOBAL;
final String callGetCommand;
- if ("system".equals(table)) callGetCommand = Settings.CALL_METHOD_GET_SYSTEM;
- else if ("secure".equals(table)) callGetCommand = Settings.CALL_METHOD_GET_SECURE;
- else if ("global".equals(table)) callGetCommand = Settings.CALL_METHOD_GET_GLOBAL;
+ if ("system".equals(table)) callGetCommand = systemGetCommand;
+ else if ("secure".equals(table)) callGetCommand = secureGetCommand;
+ else if ("global".equals(table)) callGetCommand = globalGetCommand;
else {
System.err.println("Invalid table; no put performed");
throw new IllegalArgumentException("Invalid table " + table);
@@ -232,7 +260,8 @@ public final class SettingsCmd {
String result = null;
try {
Bundle arg = new Bundle();
- arg.putInt(Settings.CALL_METHOD_USER_KEY, userHandle);
+ arg.putInt(mUseCMSettingsProvider ? CMSettings.CALL_METHOD_USER_KEY
+ : Settings.CALL_METHOD_USER_KEY, userHandle);
Bundle b = provider.call(resolveCallingPackage(), callGetCommand, key, arg);
if (b != null) {
result = b.getPairValue();
@@ -245,10 +274,16 @@ public final class SettingsCmd {
void putForUser(IContentProvider provider, int userHandle,
final String table, final String key, final String value) {
+ final String systemPutCommand = mUseCMSettingsProvider ? CMSettings.CALL_METHOD_PUT_SYSTEM
+ : Settings.CALL_METHOD_PUT_SYSTEM;
+ final String securePutCommand = mUseCMSettingsProvider ? CMSettings.CALL_METHOD_PUT_SECURE
+ : Settings.CALL_METHOD_PUT_SECURE;
+ final String globalPutCommand = mUseCMSettingsProvider ? CMSettings.CALL_METHOD_PUT_GLOBAL
+ : Settings.CALL_METHOD_PUT_GLOBAL;
final String callPutCommand;
- if ("system".equals(table)) callPutCommand = Settings.CALL_METHOD_PUT_SYSTEM;
- else if ("secure".equals(table)) callPutCommand = Settings.CALL_METHOD_PUT_SECURE;
- else if ("global".equals(table)) callPutCommand = Settings.CALL_METHOD_PUT_GLOBAL;
+ if ("system".equals(table)) callPutCommand = systemPutCommand;
+ else if ("secure".equals(table)) callPutCommand = securePutCommand;
+ else if ("global".equals(table)) callPutCommand = globalPutCommand;
else {
System.err.println("Invalid table; no put performed");
return;
@@ -257,7 +292,8 @@ public final class SettingsCmd {
try {
Bundle arg = new Bundle();
arg.putString(Settings.NameValueTable.VALUE, value);
- arg.putInt(Settings.CALL_METHOD_USER_KEY, userHandle);
+ arg.putInt(mUseCMSettingsProvider ? CMSettings.CALL_METHOD_USER_KEY
+ : Settings.CALL_METHOD_USER_KEY, userHandle);
provider.call(resolveCallingPackage(), callPutCommand, key, arg);
} catch (RemoteException e) {
System.err.println("Can't set key " + key + " in " + table + " for user " + userHandle);
@@ -266,10 +302,16 @@ public final class SettingsCmd {
int deleteForUser(IContentProvider provider, int userHandle,
final String table, final String key) {
+ final Uri systemUri = mUseCMSettingsProvider ? CMSettings.System.getUriFor(key)
+ : Settings.System.getUriFor(key);
+ final Uri secureUri = mUseCMSettingsProvider ? CMSettings.Secure.getUriFor(key)
+ : Settings.Secure.getUriFor(key);
+ final Uri globalUri = mUseCMSettingsProvider ? CMSettings.Global.getUriFor(key)
+ : Settings.Global.getUriFor(key);
Uri targetUri;
- if ("system".equals(table)) targetUri = Settings.System.getUriFor(key);
- else if ("secure".equals(table)) targetUri = Settings.Secure.getUriFor(key);
- else if ("global".equals(table)) targetUri = Settings.Global.getUriFor(key);
+ if ("system".equals(table)) targetUri = systemUri;
+ else if ("secure".equals(table)) targetUri = secureUri;
+ else if ("global".equals(table)) targetUri = globalUri;
else {
System.err.println("Invalid table; no delete performed");
throw new IllegalArgumentException("Invalid table " + table);
@@ -286,12 +328,26 @@ public final class SettingsCmd {
}
private static void printUsage() {
- System.err.println("usage: settings [--user NUM] get namespace key");
- System.err.println(" settings [--user NUM] put namespace key value");
- System.err.println(" settings [--user NUM] delete namespace key");
- System.err.println(" settings [--user NUM] list namespace");
+ System.err.println("usage: settings [--user NUM] [--cm] get namespace key");
+ System.err.println(" settings [--user NUM] [--cm] put namespace key value");
+ System.err.println(" settings [--user NUM] [--cm] delete namespace key");
+ System.err.println(" settings [--user NUM] [--cm] list namespace");
System.err.println("\n'namespace' is one of {system, secure, global}, case-insensitive");
System.err.println("If '--user NUM' is not given, the operations are performed on the owner user.");
+ System.err.println("If '--cm' is given, the operations are performed on the CMSettings provider.");
+ }
+
+ private static boolean isLegacySetting(String table, String key) {
+ if (!TextUtils.isEmpty(key)) {
+ if ("system".equals(table)) {
+ return CMSettings.System.isLegacySetting(key);
+ } else if ("secure".equals(table)) {
+ return CMSettings.Secure.isLegacySetting(key);
+ } else if ("global".equals(table)) {
+ return CMSettings.Global.isLegacySetting(key);
+ }
+ }
+ return false;
}
public static String resolveCallingPackage() {
diff --git a/cmds/tm/Android.mk b/cmds/tm/Android.mk
new file mode 100644
index 0000000..34a41dd
--- /dev/null
+++ b/cmds/tm/Android.mk
@@ -0,0 +1,15 @@
+# Copyright 2015 The CyanogenMod Project
+#
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+LOCAL_MODULE := tm
+include $(BUILD_JAVA_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := tm
+LOCAL_SRC_FILES := tm
+LOCAL_MODULE_CLASS := EXECUTABLES
+LOCAL_MODULE_TAGS := optional
+include $(BUILD_PREBUILT)
diff --git a/cmds/tm/MODULE_LICENSE_APACHE2 b/cmds/tm/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/cmds/tm/MODULE_LICENSE_APACHE2
diff --git a/cmds/tm/NOTICE b/cmds/tm/NOTICE
new file mode 100644
index 0000000..0820f6d
--- /dev/null
+++ b/cmds/tm/NOTICE
@@ -0,0 +1,190 @@
+
+ Copyright (c) 2015, 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.
+
+ 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.
+
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
diff --git a/cmds/tm/src/com/android/commands/tm/Tm.java b/cmds/tm/src/com/android/commands/tm/Tm.java
new file mode 100644
index 0000000..af1ac75
--- /dev/null
+++ b/cmds/tm/src/com/android/commands/tm/Tm.java
@@ -0,0 +1,201 @@
+/*
+**
+** Copyright 2015, 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 com.android.commands.tm;
+
+import android.content.pm.IPackageManager;
+import android.content.pm.PackageInfo;
+import android.content.pm.ParceledListSlice;
+import android.content.pm.ThemeUtils;
+import android.content.res.IThemeService;
+import android.content.res.ThemeChangeRequest;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.UserHandle;
+import android.util.AndroidException;
+import com.android.internal.os.BaseCommand;
+
+import java.io.PrintStream;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class Tm extends BaseCommand {
+ private static final String SYSTEM_THEME = "system";
+
+ IThemeService mTs;
+ IPackageManager mPm;
+
+ /**
+ * Command-line entry point.
+ *
+ * @param args The command-line arguments
+ */
+ public static void main(String[] args) {
+ (new Tm()).run(args);
+ }
+
+ public void onShowUsage(PrintStream out) {
+ List<String> components = ThemeUtils.getAllComponents();
+ StringBuilder sb = new StringBuilder();
+ sb.append("usage: tm [subcommand] [options]\n");
+ sb.append(" tm list\n");
+ sb.append(" tm apply <PACKAGE_NAME> [-r] [-c <COMPONENT> [-c <COMPONENT>] ...]\n");
+ sb.append(" tm rebuild\n");
+ sb.append(" tm process <PACKAGE_NAME>\n");
+ sb.append("\n");
+ sb.append("tm list: return a list of theme packages.\n");
+ sb.append("\n");
+ sb.append("tm apply: applies the components for the theme specified by PACKAGE_NAME.\n");
+ sb.append(" -r: remove per app themes\n");
+ sb.append(" [-c <COMPONENT> [-c <COMPONENT>] ...]\n");
+ sb.append(" if no components are specified all components will be applied.\n");
+ sb.append(" Valid components are:\n");
+ for (String component : components) {
+ sb.append(" ");
+ sb.append(component);
+ sb.append("\n");
+ }
+ sb.append("\n");
+ sb.append("tm rebuild: rebuilds the resource cache.\n");
+ sb.append("\n");
+ sb.append("tm process: processes the theme resources for the theme specified by " +
+ "PACKAGE_NAME.\n");
+
+ out.println(sb.toString());
+ }
+
+ public void onRun() throws Exception {
+ mTs = IThemeService.Stub.asInterface(ServiceManager.getService("themes"));
+ if (mTs == null) {
+ System.err.println(NO_SYSTEM_ERROR_CODE);
+ throw new AndroidException("Can't connect to theme service; is the system running?");
+ }
+
+ mPm = IPackageManager.Stub.asInterface(ServiceManager.getService("package"));
+ if (mPm == null) {
+ System.err.println(NO_SYSTEM_ERROR_CODE);
+ throw new AndroidException("Can't connect to package manager; is the system running?");
+ }
+
+ String op = nextArgRequired();
+
+ if (op.equals("list")) {
+ runListThemePackages();
+ } else if (op.equals("apply")) {
+ runApplyTheme();
+ } else if (op.equals("rebuild")) {
+ runRebuildResourceCache();
+ } else if (op.equals("process")) {
+ runProcessTheme();
+ } else {
+ showError("Error: unknown command '" + op + "'");
+ return;
+ }
+ }
+
+ private void runListThemePackages() throws Exception {
+ List<PackageInfo> packages = getInstalledPackages(mPm, 0, UserHandle.USER_OWNER);
+
+ // there is always a "system" theme available
+ System.out.println("package:system [theme]");
+ for (PackageInfo info : packages) {
+ if (info.isThemeApk || info.isLegacyIconPackApk) {
+ System.out.print("package:");
+ System.out.print(info.packageName);
+ if (info.isThemeApk) {
+ System.out.println(" [theme]");
+ } else {
+ System.out.println(" [icon pack]");
+ }
+ }
+ }
+ }
+
+ private void runApplyTheme() throws Exception {
+ String pkgName = nextArg();
+ if (pkgName == null) {
+ System.err.println("Error: didn't specify theme package to apply");
+ return;
+ }
+ if (!SYSTEM_THEME.equals(pkgName)) {
+ PackageInfo info = mPm.getPackageInfo(pkgName, 0, UserHandle.USER_OWNER);
+ if (info == null) {
+ System.err.println("Error: invalid package name");
+ return;
+ }
+ if (!(info.isThemeApk || info.isLegacyIconPackApk)) {
+ System.err.println("Error: package is not a theme or icon pack");
+ return;
+ }
+ }
+
+ boolean removePerAppThemes = false;
+
+ ThemeChangeRequest.Builder builder = new ThemeChangeRequest.Builder();
+ String opt;
+ while ((opt=nextOption()) != null) {
+ if (opt.equals("-c")) {
+ builder.setComponent(nextArgRequired(), pkgName);
+ } else if (opt.equals("-r")) {
+ removePerAppThemes = true;
+ }
+ }
+
+ // No components specified so let's just try and apply EVERYTHING!
+ Map<String, String> componentMap = builder.build().getThemeComponentsMap();
+ if (componentMap.size() == 0) {
+ List<String> components = ThemeUtils.getAllComponents();
+ for (String component : components) {
+ builder.setComponent(component, pkgName);
+ }
+ }
+ mTs.requestThemeChange(builder.build(), removePerAppThemes);
+ }
+
+ private void runRebuildResourceCache() throws Exception {
+ mTs.rebuildResourceCache();
+ }
+
+ private void runProcessTheme() throws Exception {
+ String pkgName = nextArg();
+ if (pkgName == null) {
+ System.err.println("Error: didn't specify theme package to apply");
+ return;
+ }
+ PackageInfo info = mPm.getPackageInfo(pkgName, 0, UserHandle.USER_OWNER);
+ if (info == null) {
+ System.err.println("Error: invalid package name");
+ return;
+ }
+ if (!info.isThemeApk) {
+ System.err.println("Error: package is not a theme");
+ return;
+ }
+
+ mTs.processThemeResources(pkgName);
+ }
+
+ @SuppressWarnings("unchecked")
+ private List<PackageInfo> getInstalledPackages(IPackageManager pm, int flags, int userId)
+ throws RemoteException {
+ ParceledListSlice<PackageInfo> slice = pm.getInstalledPackages(flags, userId);
+ return slice.getList();
+ }
+
+}
diff --git a/cmds/tm/tm b/cmds/tm/tm
new file mode 100755
index 0000000..dc95b6f
--- /dev/null
+++ b/cmds/tm/tm
@@ -0,0 +1,6 @@
+# Script to start "tm" on the device, which has a very rudimentary
+# shell.
+#
+base=/system
+export CLASSPATH=$base/framework/tm.jar
+exec app_process $base/bin com.android.commands.tm.Tm "$@"
diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java
index 9ef13de..eb59f6b 100644
--- a/core/java/android/accounts/AccountManager.java
+++ b/core/java/android/accounts/AccountManager.java
@@ -329,6 +329,7 @@ public class AccountManager {
* @return The account's password, null if none or if the account doesn't exist
*/
public String getPassword(final Account account) {
+ android.util.SeempLog.record(22);
if (account == null) throw new IllegalArgumentException("account is null");
try {
return mService.getPassword(account);
@@ -357,6 +358,7 @@ public class AccountManager {
* @return The user data, null if the account or key doesn't exist
*/
public String getUserData(final Account account, final String key) {
+ android.util.SeempLog.record(23);
if (account == null) throw new IllegalArgumentException("account is null");
if (key == null) throw new IllegalArgumentException("key is null");
try {
@@ -567,6 +569,7 @@ public class AccountManager {
if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
return new Future2Task<String>(handler, callback) {
public void doWork() throws RemoteException {
+ android.util.SeempLog.record(31);
mService.getAuthTokenLabel(mResponse, accountType, authTokenType);
}
@@ -612,6 +615,7 @@ public class AccountManager {
if (features == null) throw new IllegalArgumentException("features is null");
return new Future2Task<Boolean>(handler, callback) {
public void doWork() throws RemoteException {
+ android.util.SeempLog.record(31);
mService.hasFeatures(mResponse, account, features, mContext.getOpPackageName());
}
public Boolean bundleToResult(Bundle bundle) throws AuthenticatorException {
@@ -664,6 +668,7 @@ public class AccountManager {
if (type == null) throw new IllegalArgumentException("type is null");
return new Future2Task<Account[]>(handler, callback) {
public void doWork() throws RemoteException {
+ android.util.SeempLog.record(31);
mService.getAccountsByFeatures(mResponse, type, features,
mContext.getOpPackageName());
}
@@ -707,6 +712,7 @@ public class AccountManager {
* already exists, the account is null, or another error occurs.
*/
public boolean addAccountExplicitly(Account account, String password, Bundle userdata) {
+ android.util.SeempLog.record(24);
if (account == null) throw new IllegalArgumentException("account is null");
try {
return mService.addAccountExplicitly(account, password, userdata);
@@ -777,6 +783,7 @@ public class AccountManager {
return new Future2Task<Account>(handler, callback) {
@Override
public void doWork() throws RemoteException {
+ android.util.SeempLog.record(31);
mService.renameAccount(mResponse, account, newName);
}
@Override
@@ -837,10 +844,12 @@ public class AccountManager {
@Deprecated
public AccountManagerFuture<Boolean> removeAccount(final Account account,
AccountManagerCallback<Boolean> callback, Handler handler) {
+ android.util.SeempLog.record(25);
if (account == null) throw new IllegalArgumentException("account is null");
return new Future2Task<Boolean>(handler, callback) {
@Override
public void doWork() throws RemoteException {
+ android.util.SeempLog.record(31);
mService.removeAccount(mResponse, account, false);
}
@Override
@@ -896,10 +905,12 @@ public class AccountManager {
*/
public AccountManagerFuture<Bundle> removeAccount(final Account account,
final Activity activity, AccountManagerCallback<Bundle> callback, Handler handler) {
+ android.util.SeempLog.record(28);
if (account == null) throw new IllegalArgumentException("account is null");
return new AmsTask(activity, handler, callback) {
@Override
public void doWork() throws RemoteException {
+ android.util.SeempLog.record(34);
mService.removeAccount(mResponse, account, activity != null);
}
}.start();
@@ -921,6 +932,7 @@ public class AccountManager {
return new Future2Task<Boolean>(handler, callback) {
@Override
public void doWork() throws RemoteException {
+ android.util.SeempLog.record(31);
mService.removeAccountAsUser(mResponse, account, false, userHandle.getIdentifier());
}
@Override
@@ -946,6 +958,7 @@ public class AccountManager {
throw new IllegalArgumentException("userHandle is null");
return new AmsTask(activity, handler, callback) {
public void doWork() throws RemoteException {
+ android.util.SeempLog.record(34);
mService.removeAccountAsUser(mResponse, account, activity != null,
userHandle.getIdentifier());
}
@@ -1062,6 +1075,7 @@ public class AccountManager {
* @param password The password to set, null to clear the password
*/
public void setPassword(final Account account, final String password) {
+ android.util.SeempLog.record(26);
if (account == null) throw new IllegalArgumentException("account is null");
try {
mService.setPassword(account, password);
@@ -1091,6 +1105,7 @@ public class AccountManager {
* @param account The account whose password to clear
*/
public void clearPassword(final Account account) {
+ android.util.SeempLog.record(27);
if (account == null) throw new IllegalArgumentException("account is null");
try {
mService.clearPassword(account);
@@ -1119,6 +1134,7 @@ public class AccountManager {
* @param value String value to set, {@code null} to clear this user data key
*/
public void setUserData(final Account account, final String key, final String value) {
+ android.util.SeempLog.record(28);
if (account == null) throw new IllegalArgumentException("account is null");
if (key == null) throw new IllegalArgumentException("key is null");
try {
@@ -1270,6 +1286,7 @@ public class AccountManager {
optionsIn.putString(KEY_ANDROID_PACKAGE_NAME, mContext.getPackageName());
return new AmsTask(activity, handler, callback) {
public void doWork() throws RemoteException {
+ android.util.SeempLog.record(31);
mService.getAuthToken(mResponse, account, authTokenType,
false /* notifyOnAuthFailure */, true /* expectActivityLaunch */,
optionsIn);
@@ -1438,6 +1455,7 @@ public class AccountManager {
optionsIn.putString(KEY_ANDROID_PACKAGE_NAME, mContext.getPackageName());
return new AmsTask(null, handler, callback) {
public void doWork() throws RemoteException {
+ android.util.SeempLog.record(31);
mService.getAuthToken(mResponse, account, authTokenType,
notifyAuthFailure, false /* expectActivityLaunch */, optionsIn);
}
@@ -1498,6 +1516,7 @@ public class AccountManager {
final String authTokenType, final String[] requiredFeatures,
final Bundle addAccountOptions,
final Activity activity, AccountManagerCallback<Bundle> callback, Handler handler) {
+ android.util.SeempLog.record(29);
if (accountType == null) throw new IllegalArgumentException("accountType is null");
final Bundle optionsIn = new Bundle();
if (addAccountOptions != null) {
@@ -1507,6 +1526,7 @@ public class AccountManager {
return new AmsTask(activity, handler, callback) {
public void doWork() throws RemoteException {
+ android.util.SeempLog.record(31);
mService.addAccount(mResponse, accountType, authTokenType,
requiredFeatures, activity != null, optionsIn);
}
@@ -1531,6 +1551,7 @@ public class AccountManager {
return new AmsTask(activity, handler, callback) {
public void doWork() throws RemoteException {
+ android.util.SeempLog.record(31);
mService.addAccountAsUser(mResponse, accountType, authTokenType,
requiredFeatures, activity != null, optionsIn, userHandle.getIdentifier());
}
@@ -1578,6 +1599,7 @@ public class AccountManager {
return new Future2Task<Boolean>(handler, callback) {
@Override
public void doWork() throws RemoteException {
+ android.util.SeempLog.record(34);
mService.copyAccountToUser(
mResponse, account, UserHandle.USER_OWNER, user.getIdentifier());
}
@@ -1705,6 +1727,7 @@ public class AccountManager {
final int userId = userHandle.getIdentifier();
return new AmsTask(activity, handler, callback) {
public void doWork() throws RemoteException {
+ android.util.SeempLog.record(31);
mService.confirmCredentialsAsUser(mResponse, account, options, activity != null,
userId);
}
@@ -1817,9 +1840,11 @@ public class AccountManager {
public AccountManagerFuture<Bundle> editProperties(final String accountType,
final Activity activity, final AccountManagerCallback<Bundle> callback,
final Handler handler) {
+ android.util.SeempLog.record(30);
if (accountType == null) throw new IllegalArgumentException("accountType is null");
return new AmsTask(activity, handler, callback) {
public void doWork() throws RemoteException {
+ android.util.SeempLog.record(31);
mService.editProperties(mResponse, accountType, activity != null);
}
}.start();
@@ -2175,6 +2200,7 @@ public class AccountManager {
private volatile int mNumAccounts = 0;
public void doWork() throws RemoteException {
+ android.util.SeempLog.record(31);
getAccountsByTypeAndFeatures(mAccountType, mFeatures,
new AccountManagerCallback<Account[]>() {
public void run(AccountManagerFuture<Account[]> future) {
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 87c9efc2..ad08c23 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -41,6 +41,7 @@ import android.content.pm.ConfigurationInfo;
import android.content.pm.IPackageDataObserver;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
+import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Color;
@@ -59,6 +60,7 @@ import android.text.TextUtils;
import android.util.DisplayMetrics;
import android.util.Size;
import android.util.Slog;
+
import org.xmlpull.v1.XmlSerializer;
import java.io.FileDescriptor;
@@ -525,8 +527,16 @@ public class ActivityManager {
* @hide
*/
static public boolean isHighEndGfx() {
- return !isLowRamDeviceStatic() &&
- !Resources.getSystem().getBoolean(com.android.internal.R.bool.config_avoidGfxAccel);
+ return (!isLowRamDeviceStatic() &&
+ !Resources.getSystem().getBoolean(com.android.internal.R.bool.config_avoidGfxAccel))
+ || isForcedHighEndGfx();
+ }
+
+ /**
+ * @hide
+ */
+ public static boolean isForcedHighEndGfx() {
+ return SystemProperties.getBoolean("persist.sys.force_highendgfx", false);
}
/**
@@ -2298,6 +2308,16 @@ public class ActivityManager {
return null;
}
}
+ /**
+ * @hide
+ */
+ public Configuration getConfiguration() {
+ try {
+ return ActivityManagerNative.getDefault().getConfiguration();
+ } catch (RemoteException e) {
+ return null;
+ }
+ }
/**
* Sets the memory trim mode for a process and schedules a memory trim operation.
@@ -2988,4 +3008,17 @@ public class ActivityManager {
}
}
}
+
+ /**
+ * @throws SecurityException Throws SecurityException if the caller does
+ * not hold the {@link android.Manifest.permission#CHANGE_CONFIGURATION} permission.
+ *
+ * @hide
+ */
+ public void updateConfiguration(Configuration values) throws SecurityException {
+ try {
+ ActivityManagerNative.getDefault().updateConfiguration(values);
+ } catch (RemoteException e) {
+ }
+ }
}
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index f6e0735..d638de6 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -577,6 +577,15 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
return true;
}
+ case GET_CALLING_PACKAGE_FOR_BROADCAST_TRANSACTION: {
+ data.enforceInterface(IActivityManager.descriptor);
+ boolean foreground = data.readInt() == 1 ? true : false;
+ String res = getCallingPackageForBroadcast(foreground);
+ reply.writeNoException();
+ reply.writeString(res);
+ return true;
+ }
+
case GET_CALLING_ACTIVITY_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
IBinder token = data.readStrongBinder();
@@ -2096,7 +2105,7 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
case KEYGUARD_GOING_AWAY_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
- keyguardGoingAway(data.readInt() != 0, data.readInt() != 0);
+ keyguardGoingAway(data.readInt() != 0, data.readInt() != 0, data.readInt() != 0);
reply.writeNoException();
return true;
}
@@ -3192,6 +3201,19 @@ class ActivityManagerProxy implements IActivityManager
reply.recycle();
return res;
}
+ public String getCallingPackageForBroadcast(boolean foreground) throws RemoteException
+ {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ data.writeInt(foreground ? 1 : 0);
+ mRemote.transact(GET_CALLING_PACKAGE_FOR_BROADCAST_TRANSACTION, data, reply, 0);
+ reply.readException();
+ String res = reply.readString();
+ data.recycle();
+ reply.recycle();
+ return res;
+ }
public ComponentName getCallingActivity(IBinder token)
throws RemoteException {
Parcel data = Parcel.obtain();
@@ -5263,12 +5285,14 @@ class ActivityManagerProxy implements IActivityManager
}
public void keyguardGoingAway(boolean disableWindowAnimations,
- boolean keyguardGoingToNotificationShade) throws RemoteException {
+ boolean keyguardGoingToNotificationShade,
+ boolean keyguardShowingMedia) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeInt(disableWindowAnimations ? 1 : 0);
data.writeInt(keyguardGoingToNotificationShade ? 1 : 0);
+ data.writeInt(keyguardShowingMedia ? 1 : 0);
mRemote.transact(KEYGUARD_GOING_AWAY_TRANSACTION, data, reply, 0);
reply.readException();
data.recycle();
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index da21eaf..7d3b572 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -46,6 +46,7 @@ import android.database.sqlite.SQLiteDebug;
import android.database.sqlite.SQLiteDebug.DbStats;
import android.graphics.Bitmap;
import android.graphics.Canvas;
+import android.graphics.Typeface;
import android.hardware.display.DisplayManagerGlobal;
import android.net.ConnectivityManager;
import android.net.IConnectivityManager;
@@ -78,6 +79,7 @@ import android.os.Trace;
import android.os.UserHandle;
import android.provider.Settings;
import android.security.NetworkSecurityPolicy;
+import android.text.TextUtils;
import android.util.AndroidRuntimeException;
import android.util.ArrayMap;
import android.util.DisplayMetrics;
@@ -90,6 +92,7 @@ import android.util.Slog;
import android.util.SuperNotCalledException;
import android.view.Display;
import android.view.HardwareRenderer;
+import android.view.InflateException;
import android.view.View;
import android.view.ViewDebug;
import android.view.ViewManager;
@@ -893,9 +896,25 @@ public final class ActivityThread {
public void scheduleRegisteredReceiver(IIntentReceiver receiver, Intent intent,
int resultCode, String dataStr, Bundle extras, boolean ordered,
boolean sticky, int sendingUser, int processState) throws RemoteException {
- updateProcessState(processState, false);
- receiver.performReceive(intent, resultCode, dataStr, extras, ordered,
- sticky, sendingUser);
+ RemoteException remoteException = null;
+ if (!Binder.isProxy(receiver)) {
+ updateProcessState(processState, false);
+ try {
+ receiver.performReceive(intent, resultCode, dataStr, extras, ordered,
+ sticky, sendingUser);
+ return;
+ } catch (RemoteException e) {
+ remoteException = e;
+ }
+ }
+ if (ordered) {
+ Slog.w(TAG, receiver + " is no longer alive");
+ ActivityManagerNative.getDefault().finishReceiver(receiver.asBinder(),
+ resultCode, dataStr, extras, true, intent.getFlags());
+ if (remoteException != null) {
+ throw remoteException;
+ }
+ }
}
@Override
@@ -1697,9 +1716,21 @@ public final class ActivityThread {
*/
Resources getTopLevelResources(String resDir, String[] splitResDirs, String[] overlayDirs,
String[] libDirs, int displayId, Configuration overrideConfiguration,
- LoadedApk pkgInfo) {
+ LoadedApk pkgInfo, Context context, String pkgName) {
return mResourcesManager.getTopLevelResources(resDir, splitResDirs, overlayDirs, libDirs,
- displayId, overrideConfiguration, pkgInfo.getCompatibilityInfo());
+ displayId, pkgName, overrideConfiguration, pkgInfo.getCompatibilityInfo(), context,
+ pkgInfo.getApplicationInfo().isThemeable);
+ }
+
+ /**
+ * Creates the top level resources for the given package.
+ */
+ Resources getTopLevelThemedResources(String resDir, int displayId,
+ Configuration overrideConfiguration, LoadedApk pkgInfo,
+ String pkgName, String themePkgName) {
+ return mResourcesManager.getTopLevelThemedResources(resDir, displayId, pkgName,
+ themePkgName, pkgInfo.getCompatibilityInfo(),
+ pkgInfo.getApplicationInfo().isThemeable);
}
final Handler getHandler() {
@@ -1817,8 +1848,7 @@ public final class ActivityThread {
}
LoadedApk packageInfo = ref != null ? ref.get() : null;
- if (packageInfo == null || (packageInfo.mResources != null
- && !packageInfo.mResources.getAssets().isUpToDate())) {
+ if (packageInfo == null) {
if (localLOGV) Slog.v(TAG, (includeCode ? "Loading code package "
: "Loading resource-only package ") + aInfo.packageName
+ " (in " + (mBoundApplication != null
@@ -1844,6 +1874,10 @@ public final class ActivityThread {
new WeakReference<LoadedApk>(packageInfo));
}
}
+ if (packageInfo.mResources != null
+ && !packageInfo.mResources.getAssets().isUpToDate()) {
+ packageInfo.mResources = null;
+ }
return packageInfo;
}
}
@@ -2422,6 +2456,16 @@ public final class ActivityThread {
return activity;
}
+ private void sendAppLaunchFailureBroadcast(ActivityClientRecord r) {
+ String pkg = null;
+ if (r.packageInfo != null && !TextUtils.isEmpty(r.packageInfo.getPackageName())) {
+ pkg = r.packageInfo.getPackageName();
+ }
+ Intent intent = new Intent(Intent.ACTION_APP_FAILURE,
+ (pkg != null)? Uri.fromParts("package", pkg, null) : null);
+ getSystemContext().sendBroadcast(intent);
+ }
+
private Context createBaseContextForActivity(ActivityClientRecord r, final Activity activity) {
int displayId = Display.DEFAULT_DISPLAY;
try {
@@ -4253,8 +4297,12 @@ public final class ActivityThread {
if (configDiff != 0) {
// Ask text layout engine to free its caches if there is a locale change
boolean hasLocaleConfigChange = ((configDiff & ActivityInfo.CONFIG_LOCALE) != 0);
- if (hasLocaleConfigChange) {
+ boolean hasFontConfigChange = ((configDiff & ActivityInfo.CONFIG_THEME_FONT) != 0);
+ if (hasLocaleConfigChange || hasFontConfigChange) {
Canvas.freeTextLayoutCaches();
+ if (hasFontConfigChange) {
+ Typeface.recreateDefaults();
+ }
if (DEBUG_CONFIGURATION) Slog.v(TAG, "Cleared TextLayout Caches");
}
}
@@ -4423,7 +4471,7 @@ public final class ActivityThread {
+ DisplayMetrics.DENSITY_DEVICE + " to "
+ mCurDefaultDisplayDpi);
DisplayMetrics.DENSITY_DEVICE = mCurDefaultDisplayDpi;
- Bitmap.setDefaultDensity(DisplayMetrics.DENSITY_DEFAULT);
+ Bitmap.setDefaultDensity(DisplayMetrics.DENSITY_DEVICE);
}
}
@@ -4523,7 +4571,8 @@ public final class ActivityThread {
}
- final boolean is24Hr = "24".equals(mCoreSettings.getString(Settings.System.TIME_12_24));
+ final boolean is24Hr = android.text.format.DateFormat.is24HourFormat(
+ mCoreSettings.getString(Settings.System.TIME_12_24), data.config.locale);
DateFormat.set24HourTimePref(is24Hr);
View.mDebugViewAttributes =
diff --git a/core/java/android/app/AlarmManager.java b/core/java/android/app/AlarmManager.java
index 330d730..b0afe7c 100644
--- a/core/java/android/app/AlarmManager.java
+++ b/core/java/android/app/AlarmManager.java
@@ -100,6 +100,14 @@ public class AlarmManager {
*/
public static final int ELAPSED_REALTIME = 3;
+ /** @hide
+ * Alarm time in {@link System#currentTimeMillis System.currentTimeMillis()}
+ * (wall clock time in UTC), which will wake up the device when
+ * it goes off. And it will power on the devices when it shuts down.
+ * Set as 5 to make it be compatible with android_alarm_type.
+ */
+ public static final int RTC_POWEROFF_WAKEUP = 5;
+
/**
* Broadcast Action: Sent after the value returned by
* {@link #getNextAlarmClock()} has changed.
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 09c0a6e..c590fac 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -1,4 +1,7 @@
/*
+ * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ *
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -28,6 +31,7 @@ import android.os.Parcelable;
import android.os.Process;
import android.os.RemoteException;
import android.os.UserHandle;
+import android.os.SystemProperties;
import android.os.UserManager;
import android.util.ArrayMap;
@@ -69,6 +73,10 @@ public class AppOpsManager {
* will do this for you).
*/
+ /** {@hide */
+ public static final String ACTION_SU_SESSION_CHANGED =
+ "android.intent.action.SU_SESSION_CHANGED";
+
final Context mContext;
final IAppOpsService mService;
final ArrayMap<OnOpChangedListener, IAppOpsCallback> mModeWatchers
@@ -103,9 +111,18 @@ public class AppOpsManager {
*/
public static final int MODE_DEFAULT = 3;
+ /**
+ * @hide Result from {@link #checkOp}, {@link #noteOp}, {@link #startOp}:
+ * AppOps Service should show a dialog box on screen to get user
+ * permission.
+ */
+ public static final int MODE_ASK = 4;
+
// when adding one of these:
// - increment _NUM_OP
- // - add rows to sOpToSwitch, sOpToString, sOpNames, sOpPerms, sOpDefaultMode
+ // - add rows to sOpToSwitch, sOpToString, sOpNames, sOpPerms, sOpDefaultMode, sOpDefaultStrictMode,
+ // sOpToOpString, sOpStrictMode.
+ // - add descriptive strings to frameworks/base/core/res/res/values/config.xml
// - add descriptive strings to Settings/res/values/arrays.xml
// - add the op to the appropriate template in AppOpsState.OpsTemplate (settings app)
@@ -237,8 +254,20 @@ public class AppOpsManager {
public static final int OP_TURN_SCREEN_ON = 61;
/** @hide Get device accounts. */
public static final int OP_GET_ACCOUNTS = 62;
+ /** @hide Wifi state change **/
+ public static final int OP_WIFI_CHANGE = 63;
+ /** @hide */
+ public static final int OP_BLUETOOTH_CHANGE = 64;
/** @hide */
- public static final int _NUM_OP = 63;
+ public static final int OP_BOOT_COMPLETED = 65;
+ /** @hide */
+ public static final int OP_NFC_CHANGE = 66;
+ /** @hide */
+ public static final int OP_DATA_CONNECT_CHANGE = 67;
+ /** @hide */
+ public static final int OP_SU = 68;
+ /** @hide */
+ public static final int _NUM_OP = 69;
/** Access to coarse location information. */
public static final String OPSTR_COARSE_LOCATION = "android:coarse_location";
@@ -336,6 +365,19 @@ public class AppOpsManager {
/** @hide Get device accounts. */
public static final String OPSTR_GET_ACCOUNTS
= "android:get_accounts";
+ /** @hide **/
+ private static final String OPSTR_WIFI_CHANGE =
+ "android:wifi_change";
+ private static final String OPSTR_BLUETOOTH_CHANGE =
+ "android:bluetooth_change";
+ private static final String OPSTR_BOOT_COMPLETED =
+ "android:boot_completed";
+ private static final String OPSTR_NFC_CHANGE =
+ "android:nfc_change";
+ private static final String OPSTR_DATA_CONNECT_CHANGE =
+ "android:data_connect_change";
+ private static final String OPSTR_SU =
+ "android:su";
/**
* This maps each operation to the operation that serves as the
@@ -356,7 +398,7 @@ public class AppOpsManager {
OP_WRITE_CALL_LOG,
OP_READ_CALENDAR,
OP_WRITE_CALENDAR,
- OP_COARSE_LOCATION,
+ OP_WIFI_SCAN,
OP_POST_NOTIFICATION,
OP_COARSE_LOCATION,
OP_CALL_PHONE,
@@ -409,6 +451,12 @@ public class AppOpsManager {
OP_WRITE_EXTERNAL_STORAGE,
OP_TURN_SCREEN_ON,
OP_GET_ACCOUNTS,
+ OP_WIFI_CHANGE,
+ OP_BLUETOOTH_CHANGE,
+ OP_BOOT_COMPLETED,
+ OP_NFC_CHANGE,
+ OP_DATA_CONNECT_CHANGE,
+ OP_SU
};
/**
@@ -478,7 +526,13 @@ public class AppOpsManager {
OPSTR_READ_EXTERNAL_STORAGE,
OPSTR_WRITE_EXTERNAL_STORAGE,
null,
- OPSTR_GET_ACCOUNTS
+ OPSTR_GET_ACCOUNTS,
+ OPSTR_WIFI_CHANGE,
+ OPSTR_BLUETOOTH_CHANGE,
+ OPSTR_BOOT_COMPLETED,
+ OPSTR_NFC_CHANGE,
+ OPSTR_DATA_CONNECT_CHANGE,
+ OPSTR_SU,
};
/**
@@ -549,6 +603,12 @@ public class AppOpsManager {
"WRITE_EXTERNAL_STORAGE",
"TURN_ON_SCREEN",
"GET_ACCOUNTS",
+ "WIFI_CHANGE",
+ "BLUETOOTH_CHANGE",
+ "BOOT_COMPLETED",
+ "NFC_CHANGE",
+ "DATA_CONNECT_CHANGE",
+ "SU",
};
/**
@@ -566,7 +626,7 @@ public class AppOpsManager {
android.Manifest.permission.WRITE_CALL_LOG,
android.Manifest.permission.READ_CALENDAR,
android.Manifest.permission.WRITE_CALENDAR,
- android.Manifest.permission.ACCESS_WIFI_STATE,
+ null, // no permission for wifi scan available
null, // no permission required for notifications
null, // neighboring cells shares the coarse location perm
android.Manifest.permission.CALL_PHONE,
@@ -618,7 +678,13 @@ public class AppOpsManager {
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE,
null, // no permission for turning the screen on
- Manifest.permission.GET_ACCOUNTS
+ Manifest.permission.GET_ACCOUNTS,
+ Manifest.permission.CHANGE_WIFI_STATE,
+ null,
+ Manifest.permission.RECEIVE_BOOT_COMPLETED,
+ Manifest.permission.NFC,
+ Manifest.permission.MODIFY_PHONE_STATE,
+ null,
};
/**
@@ -690,6 +756,12 @@ public class AppOpsManager {
null, // WRITE_EXTERNAL_STORAGE
null, // TURN_ON_SCREEN
null, // GET_ACCOUNTS
+ null, //WIFI_CHANGE
+ null, //BLUETOOTH_CHANGE
+ null, //BOOT_COMPLETED
+ null, //NFC_CHANGE
+ null, //DATA_CONNECT_CHANGE
+ UserManager.DISALLOW_SU, //SU TODO: this should really be investigated.
};
/**
@@ -760,6 +832,12 @@ public class AppOpsManager {
false, // WRITE_EXTERNAL_STORAGE
false, // TURN_ON_SCREEN
false, // GET_ACCOUNTS
+ true, // WIFI_CHANGE
+ true, // BLUETOOTH_CHANGE
+ true, // BOOT_COMPLETED
+ true, // NFC_CHANGE
+ true, //DATA_CONNECT_CHANGE
+ false, //SU
};
/**
@@ -829,6 +907,163 @@ public class AppOpsManager {
AppOpsManager.MODE_ALLOWED,
AppOpsManager.MODE_ALLOWED, // OP_TURN_ON_SCREEN
AppOpsManager.MODE_ALLOWED,
+ AppOpsManager.MODE_ALLOWED, // OP_WIFI_CHANGE
+ AppOpsManager.MODE_ALLOWED, // OP_BLUETOOTH_CHANGE
+ AppOpsManager.MODE_ALLOWED, // OP_BOOT_COMPLETED
+ AppOpsManager.MODE_ALLOWED, // OP_NFC_CHANGE
+ AppOpsManager.MODE_ALLOWED,
+ AppOpsManager.MODE_ASK, // OP_SU
+ };
+
+ /**
+ * This specifies the default mode for each strict operation.
+ */
+
+ private static int[] sOpDefaultStrictMode = new int[] {
+ AppOpsManager.MODE_ASK, // OP_COARSE_LOCATION
+ AppOpsManager.MODE_ASK, // OP_FINE_LOCATION
+ AppOpsManager.MODE_ASK, // OP_GPS
+ AppOpsManager.MODE_ALLOWED, // OP_VIBRATE
+ AppOpsManager.MODE_ASK, // OP_READ_CONTACTS
+ AppOpsManager.MODE_ASK, // OP_WRITE_CONTACTS
+ AppOpsManager.MODE_ASK, // OP_READ_CALL_LOG
+ AppOpsManager.MODE_ASK, // OP_WRITE_CALL_LOG
+ AppOpsManager.MODE_ALLOWED, // OP_READ_CALENDAR
+ AppOpsManager.MODE_ALLOWED, // OP_WRITE_CALENDAR
+ AppOpsManager.MODE_ASK, // OP_WIFI_SCAN
+ AppOpsManager.MODE_ALLOWED, // OP_POST_NOTIFICATION
+ AppOpsManager.MODE_ALLOWED, // OP_NEIGHBORING_CELLS
+ AppOpsManager.MODE_ASK, // OP_CALL_PHONE
+ AppOpsManager.MODE_ASK, // OP_READ_SMS
+ AppOpsManager.MODE_ASK, // OP_WRITE_SMS
+ AppOpsManager.MODE_ASK, // OP_RECEIVE_SMS
+ AppOpsManager.MODE_ALLOWED, // OP_RECEIVE_EMERGECY_SMS
+ AppOpsManager.MODE_ASK, // OP_RECEIVE_MMS
+ AppOpsManager.MODE_ALLOWED, // OP_RECEIVE_WAP_PUSH
+ AppOpsManager.MODE_ASK, // OP_SEND_SMS
+ AppOpsManager.MODE_ALLOWED, // OP_READ_ICC_SMS
+ AppOpsManager.MODE_ALLOWED, // OP_WRITE_ICC_SMS
+ AppOpsManager.MODE_ALLOWED, // OP_WRITE_SETTINGS
+ AppOpsManager.MODE_ALLOWED, // OP_SYSTEM_ALERT_WINDOW
+ AppOpsManager.MODE_ALLOWED, // OP_ACCESS_NOTIFICATIONS
+ AppOpsManager.MODE_ASK, // OP_CAMERA
+ AppOpsManager.MODE_ASK, // OP_RECORD_AUDIO
+ AppOpsManager.MODE_ALLOWED, // OP_PLAY_AUDIO
+ AppOpsManager.MODE_ALLOWED, // OP_READ_CLIPBOARD
+ AppOpsManager.MODE_ALLOWED, // OP_WRITE_CLIPBOARD
+ AppOpsManager.MODE_ALLOWED, // OP_TAKE_MEDIA_BUTTONS
+ AppOpsManager.MODE_ALLOWED, // OP_TAKE_AUDIO_FOCUS
+ AppOpsManager.MODE_ALLOWED, // OP_AUDIO_MASTER_VOLUME
+ AppOpsManager.MODE_ALLOWED, // OP_AUDIO_VOICE_VOLUME
+ AppOpsManager.MODE_ALLOWED, // OP_AUDIO_RING_VOLUME
+ AppOpsManager.MODE_ALLOWED, // OP_AUDIO_MEDIA_VOLUME
+ AppOpsManager.MODE_ALLOWED, // OP_AUDIO_ALARM_VOLUME
+ AppOpsManager.MODE_ALLOWED, // OP_AUDIO_NOTIFICATION_VOLUME
+ AppOpsManager.MODE_ALLOWED, // OP_AUDIO_BLUETOOTH_VOLUME
+ AppOpsManager.MODE_ALLOWED, // OP_WAKE_LOCK
+ AppOpsManager.MODE_ALLOWED, // OP_MONITOR_LOCATION
+ AppOpsManager.MODE_ASK, // OP_MONITOR_HIGH_POWER_LOCATION
+ AppOpsManager.MODE_DEFAULT, // OP_GET_USAGE_STATS
+ AppOpsManager.MODE_ALLOWED, // OP_MUTE_MICROPHONE
+ AppOpsManager.MODE_ALLOWED, // OP_TOAST_WINDOW
+ AppOpsManager.MODE_IGNORED, // OP_PROJECT_MEDIA
+ AppOpsManager.MODE_IGNORED, // OP_ACTIVATE_VPN
+ AppOpsManager.MODE_ALLOWED, // OP WALLPAPER
+ AppOpsManager.MODE_ALLOWED, // OP_ASSIST_STRUCTURE
+ AppOpsManager.MODE_ALLOWED, // OP_ASSIST_SCREENSHOT
+ AppOpsManager.MODE_ALLOWED, // OP_READ_PHONE_STATE
+ AppOpsManager.MODE_ALLOWED, // OP_ADD_VOICEMAIL
+ AppOpsManager.MODE_ALLOWED, // OP_USE_SIP
+ AppOpsManager.MODE_ALLOWED, // OP_PROCESS_OUTGOING_CALLS
+ AppOpsManager.MODE_ALLOWED, // OP_USE_FINGERPRINT
+ AppOpsManager.MODE_ALLOWED, // OP_BODY_SENSORS
+ AppOpsManager.MODE_ALLOWED, // OP_READ_CELL_BROADCASTS
+ AppOpsManager.MODE_ERRORED, // OP_MOCK_LOCATION
+ AppOpsManager.MODE_ALLOWED, // OP_READ_EXTERNAL_STORAGE
+ AppOpsManager.MODE_ALLOWED, // OP_WRITE_EXTERNAL_STORAGE
+ AppOpsManager.MODE_ALLOWED, // OP_TURN_ON_SCREEN
+ AppOpsManager.MODE_ALLOWED, // OP_GET_ACCOUNTS
+ AppOpsManager.MODE_ASK, // OP_WIFI_CHANGE
+ AppOpsManager.MODE_ASK, // OP_BLUETOOTH_CHANGE
+ AppOpsManager.MODE_ALLOWED, // OP_BOOT_COMPLETED
+ AppOpsManager.MODE_ASK, // OP_NFC_CHANGE
+ AppOpsManager.MODE_ASK, // OP_DATA_CONNECT_CHANGE
+ AppOpsManager.MODE_ASK, // OP_SU
+ };
+
+ /**
+ * This specifies if operation is in strict mode.
+ */
+ private final static boolean[] sOpStrictMode = new boolean[] {
+ true, // OP_COARSE_LOCATION
+ true, // OP_FINE_LOCATION
+ true, // OP_GPS
+ false, // OP_VIBRATE
+ true, // OP_READ_CONTACTS
+ true, // OP_WRITE_CONTACTS
+ true, // OP_READ_CALL_LOG
+ true, // OP_WRITE_CALL_LOG
+ false, // OP_READ_CALENDAR
+ false, // OP_WRITE_CALENDAR
+ true, // OP_WIFI_SCAN
+ false, // OP_POST_NOTIFICATION
+ false, // OP_NEIGHBORING_CELLS
+ true, // OP_CALL_PHONE
+ true, // OP_READ_SMS
+ true, // OP_WRITE_SMS
+ false, // OP_RECEIVE_SMS
+ false, // OP_RECEIVE_EMERGECY_SMS
+ true, // OP_RECEIVE_MMS
+ false, // OP_RECEIVE_WAP_PUSH
+ true, // OP_SEND_SMS
+ false, // OP_READ_ICC_SMS
+ false, // OP_WRITE_ICC_SMS
+ false, // OP_WRITE_SETTINGS
+ false, // OP_SYSTEM_ALERT_WINDOW
+ false, // OP_ACCESS_NOTIFICATIONS
+ true, // OP_CAMERA
+ true, // OP_RECORD_AUDIO
+ false, // OP_PLAY_AUDIO
+ false, // OP_READ_CLIPBOARD
+ false, // OP_WRITE_CLIPBOARD
+ false, // OP_TAKE_MEDIA_BUTTONS
+ false, // OP_TAKE_AUDIO_FOCUS
+ false, // OP_AUDIO_MASTER_VOLUME
+ false, // OP_AUDIO_VOICE_VOLUME
+ false, // OP_AUDIO_RING_VOLUME
+ false, // OP_AUDIO_MEDIA_VOLUME
+ false, // OP_AUDIO_ALARM_VOLUME
+ false, // OP_AUDIO_NOTIFICATION_VOLUME
+ false, // OP_AUDIO_BLUETOOTH_VOLUME
+ false, // OP_WAKE_LOCK
+ false, // OP_MONITOR_LOCATION
+ true, // OP_MONITOR_HIGH_POWER_LOCATION
+ false, // OP_GET_USAGE_STATS
+ false, // OP_MUTE_MICROPHONE
+ false, // OP_TOAST_WINDOW
+ false, // OP_PROJECT_MEDIA
+ false, // OP_ACTIVATE_VPN
+ true, // OP WALLPAPER
+ false, //ASSIST_STRUCTURE
+ false, //ASSIST_SCREENSHOT
+ false, //READ_PHONE_STATE
+ false, //ADD_VOICEMAIL
+ false, // USE_SIP
+ false, // PROCESS_OUTGOING_CALLS
+ false, // USE_FINGERPRINT
+ false, // BODY_SENSORS
+ false, // READ_CELL_BROADCASTS
+ false, // MOCK_LOCATION
+ true, // READ_EXTERNAL_STORAGE
+ true, // WRITE_EXTERNAL_STORAGE
+ false, // TURN_ON_SCREEN
+ false, // GET_ACCOUNTS
+ true, // OP_WIFI_CHANGE
+ true, // OP_BLUETOOTH_CHANGE
+ false, // OP_BOOT_COMPLETED
+ true, // OP_NFC_CHANGE
+ true, // OP_DATA_CONNECT_CHANGE
+ true, // OP_SU
};
/**
@@ -901,7 +1136,13 @@ public class AppOpsManager {
false,
false,
false,
- false
+ false,
+ false, // OP_WIFI_CHANGE
+ false, // OP_BLUETOOTH_CHANGE
+ false, // OP_BOOT_COMPLETED
+ false, // OP_NFC_CHANGE
+ false, // OP_DATA_CONNECT_CHANGE
+ false, // OP_SU
};
/**
@@ -914,6 +1155,8 @@ public class AppOpsManager {
*/
private static HashMap<String, Integer> sPermToOp = new HashMap<>();
+ private static HashMap<String, Integer> sNameToOp = new HashMap<String, Integer>();
+
static {
if (sOpToSwitch.length != _NUM_OP) {
throw new IllegalStateException("sOpToSwitch length " + sOpToSwitch.length
@@ -935,6 +1178,10 @@ public class AppOpsManager {
throw new IllegalStateException("sOpDefaultMode length " + sOpDefaultMode.length
+ " should be " + _NUM_OP);
}
+ if (sOpDefaultStrictMode.length != _NUM_OP) {
+ throw new IllegalStateException("sOpDefaultStrictMode length " + sOpDefaultStrictMode.length
+ + " should be " + _NUM_OP);
+ }
if (sOpDisableReset.length != _NUM_OP) {
throw new IllegalStateException("sOpDisableReset length " + sOpDisableReset.length
+ " should be " + _NUM_OP);
@@ -947,6 +1194,10 @@ public class AppOpsManager {
throw new IllegalStateException("sOpAllowSYstemRestrictionsBypass length "
+ sOpRestrictions.length + " should be " + _NUM_OP);
}
+ if (sOpStrictMode.length != _NUM_OP) {
+ throw new IllegalStateException("sOpStrictMode length "
+ + sOpStrictMode.length + " should be " + _NUM_OP);
+ }
for (int i=0; i<_NUM_OP; i++) {
if (sOpToString[i] != null) {
sOpStrToOp.put(sOpToString[i], i);
@@ -957,6 +1208,9 @@ public class AppOpsManager {
sPermToOp.put(sOpPerms[i], i);
}
}
+ for (int i=0; i<_NUM_OP; i++) {
+ sNameToOp.put(sOpNames[i], i);
+ }
}
/**
@@ -989,6 +1243,15 @@ public class AppOpsManager {
}
/**
+ * Map a non-localized name for the operation back to the Op number
+ * @hide
+ */
+ public static int nameToOp(String name) {
+ Integer val = sNameToOp.get(name);
+ return val != null ? val : OP_NONE;
+ }
+
+ /**
* Retrieve the permission associated with an operation, or null if there is not one.
* @hide
*/
@@ -1026,7 +1289,9 @@ public class AppOpsManager {
* Retrieve the default mode for the operation.
* @hide
*/
- public static int opToDefaultMode(int op) {
+ public static int opToDefaultMode(int op, boolean isStrict) {
+ if (isStrict)
+ return sOpDefaultStrictMode[op];
return sOpDefaultMode[op];
}
@@ -1113,9 +1378,16 @@ public class AppOpsManager {
private final int mDuration;
private final int mProxyUid;
private final String mProxyPackageName;
+ private final int mAllowedCount;
+ private final int mIgnoredCount;
public OpEntry(int op, int mode, long time, long rejectTime, int duration,
- int proxyUid, String proxyPackage) {
+ int proxyUid, String proxyPackage) {
+ this(op, mode, time, rejectTime, duration, proxyUid, proxyPackage, 0, 0);
+ }
+
+ public OpEntry(int op, int mode, long time, long rejectTime, int duration,
+ int proxyUid, String proxyPackage, int allowedCount, int ignoredCount) {
mOp = op;
mMode = mode;
mTime = time;
@@ -1123,6 +1395,8 @@ public class AppOpsManager {
mDuration = duration;
mProxyUid = proxyUid;
mProxyPackageName = proxyPackage;
+ mAllowedCount = allowedCount;
+ mIgnoredCount = ignoredCount;
}
public int getOp() {
@@ -1157,6 +1431,14 @@ public class AppOpsManager {
return mProxyPackageName;
}
+ public int getAllowedCount() {
+ return mAllowedCount;
+ }
+
+ public int getIgnoredCount() {
+ return mIgnoredCount;
+ }
+
@Override
public int describeContents() {
return 0;
@@ -1171,6 +1453,8 @@ public class AppOpsManager {
dest.writeInt(mDuration);
dest.writeInt(mProxyUid);
dest.writeString(mProxyPackageName);
+ dest.writeInt(mAllowedCount);
+ dest.writeInt(mIgnoredCount);
}
OpEntry(Parcel source) {
@@ -1181,6 +1465,8 @@ public class AppOpsManager {
mDuration = source.readInt();
mProxyUid = source.readInt();
mProxyPackageName = source.readString();
+ mAllowedCount = source.readInt();
+ mIgnoredCount = source.readInt();
}
public static final Creator<OpEntry> CREATOR = new Creator<OpEntry>() {
@@ -1753,4 +2039,75 @@ public class AppOpsManager {
public void finishOp(int op) {
finishOp(op, Process.myUid(), mContext.getOpPackageName());
}
+
+ /** @hide */
+ public static boolean isStrictEnable() {
+ return SystemProperties.getBoolean("persist.sys.strict_op_enable", false);
+ }
+
+ /**
+ * Check if op in strict mode
+ * @hide
+ */
+ public static boolean isStrictOp(int code) {
+ return sOpStrictMode[code];
+ }
+
+
+ /** @hide */
+ public static int stringToMode(String permission) {
+ if ("allowed".equalsIgnoreCase(permission)) {
+ return AppOpsManager.MODE_ALLOWED;
+ } else if ("ignored".equalsIgnoreCase(permission)) {
+ return AppOpsManager.MODE_IGNORED;
+ } else if ("ask".equalsIgnoreCase(permission)) {
+ return AppOpsManager.MODE_ASK;
+ }
+ return AppOpsManager.MODE_ERRORED;
+ }
+
+ /** @hide */
+ public static int stringOpToOp (String op) {
+ Integer val = sOpStrToOp.get(op);
+ if (val == null) {
+ val = OP_NONE;
+ }
+ return val;
+ }
+
+ /** @hide */
+ public boolean isControlAllowed(int op, String packageName) {
+ boolean isShow = true;
+ try {
+ isShow = mService.isControlAllowed(op, packageName);
+ } catch (RemoteException e) {
+ }
+ return isShow;
+ }
+
+ /** @hide */
+ public boolean getPrivacyGuardSettingForPackage(int uid, String packageName) {
+ try {
+ return mService.getPrivacyGuardSettingForPackage(uid, packageName);
+ } catch (RemoteException e) {
+ }
+ return false;
+ }
+
+ /** @hide */
+ public void setPrivacyGuardSettingForPackage(int uid, String packageName,
+ boolean state) {
+ try {
+ mService.setPrivacyGuardSettingForPackage(uid, packageName, state);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /** @hide */
+ public void resetCounters() {
+ try {
+ mService.resetCounters();
+ } catch (RemoteException e) {
+ }
+ }
}
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 7cae745..c0cd9ec 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -23,6 +23,7 @@ import android.annotation.StringRes;
import android.annotation.XmlRes;
import android.content.ComponentName;
import android.content.ContentResolver;
+import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.IntentSender;
@@ -1028,12 +1029,13 @@ final class ApplicationPackageManager extends PackageManager {
if (app.packageName.equals("system")) {
return mContext.mMainThread.getSystemContext().getResources();
}
+
final boolean sameUid = (app.uid == Process.myUid());
final Resources r = mContext.mMainThread.getTopLevelResources(
sameUid ? app.sourceDir : app.publicSourceDir,
sameUid ? app.splitSourceDirs : app.splitPublicSourceDirs,
app.resourceDirs, app.sharedLibraryFiles, Display.DEFAULT_DISPLAY,
- null, mContext.mPackageInfo);
+ null, mContext.mPackageInfo, mContext, app.packageName);
if (r != null) {
return r;
}
@@ -1069,6 +1071,49 @@ final class ApplicationPackageManager extends PackageManager {
throw new NameNotFoundException("Package " + appPackageName + " doesn't exist");
}
+ /** @hide */
+ @Override public Resources getThemedResourcesForApplication(
+ ApplicationInfo app, String themePkgName) throws NameNotFoundException {
+ if (app.packageName.equals("system")) {
+ return mContext.mMainThread.getSystemContext().getResources();
+ }
+
+ Resources r = mContext.mMainThread.getTopLevelThemedResources(
+ app.uid == Process.myUid() ? app.sourceDir : app.publicSourceDir,
+ Display.DEFAULT_DISPLAY, null, mContext.mPackageInfo, app.packageName,
+ themePkgName);
+ if (r != null) {
+ return r;
+ }
+ throw new NameNotFoundException("Unable to open " + app.publicSourceDir);
+ }
+
+ /** @hide */
+ @Override public Resources getThemedResourcesForApplication(
+ String appPackageName, String themePkgName) throws NameNotFoundException {
+ return getThemedResourcesForApplication(
+ getApplicationInfo(appPackageName, 0), themePkgName);
+ }
+
+ /** @hide */
+ @Override
+ public Resources getThemedResourcesForApplicationAsUser(String appPackageName,
+ String themePackageName, int userId) throws NameNotFoundException {
+ if (userId < 0) {
+ throw new IllegalArgumentException(
+ "Call does not support special user #" + userId);
+ }
+ try {
+ ApplicationInfo ai = mPM.getApplicationInfo(appPackageName, 0, userId);
+ if (ai != null) {
+ return getThemedResourcesForApplication(ai, themePackageName);
+ }
+ } catch (RemoteException e) {
+ throw new RuntimeException("Package manager has died", e);
+ }
+ throw new NameNotFoundException("Package " + appPackageName + " doesn't exist");
+ }
+
int mCachedSafeMode = -1;
@Override public boolean isSafeMode() {
try {
@@ -1993,6 +2038,15 @@ final class ApplicationPackageManager extends PackageManager {
}
@Override
+ public void setComponentProtectedSetting(ComponentName componentName, boolean newState) {
+ try {
+ mPM.setComponentProtectedSetting(componentName, newState, mContext.getUserId());
+ } catch (RemoteException re) {
+ Log.e(TAG, "Failed to set component protected setting", re);
+ }
+ }
+
+ @Override
public PackageInstaller getPackageInstaller() {
synchronized (mLock) {
if (mInstaller == null) {
@@ -2240,4 +2294,30 @@ final class ApplicationPackageManager extends PackageManager {
return false;
}
}
+
+ /**
+ * @hide
+ */
+ @Override
+ public void updateIconMaps(String pkgName) {
+ try {
+ mPM.updateIconMapping(pkgName);
+ } catch (RemoteException re) {
+ Log.e(TAG, "Failed to update icon maps", re);
+ }
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public int processThemeResources(String themePkgName) {
+ try {
+ return mPM.processThemeResources(themePkgName);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Unable to process theme resources for " + themePkgName, e);
+ }
+
+ return 0;
+ }
}
diff --git a/core/java/android/app/ComposedIconInfo.aidl b/core/java/android/app/ComposedIconInfo.aidl
new file mode 100644
index 0000000..8a1bab5
--- /dev/null
+++ b/core/java/android/app/ComposedIconInfo.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2014 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;
+
+/** @hide */
+parcelable ComposedIconInfo;
diff --git a/core/java/android/app/ComposedIconInfo.java b/core/java/android/app/ComposedIconInfo.java
new file mode 100644
index 0000000..f49c230
--- /dev/null
+++ b/core/java/android/app/ComposedIconInfo.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2014 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;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/** @hide */
+public class ComposedIconInfo implements Parcelable {
+ public int iconUpon, iconMask;
+ public int[] iconBacks;
+ public float iconScale;
+ public float iconRotation;
+ // value used to provide some randomization to the angle of rotation
+ public float iconRotationVariance;
+ public float iconTranslationX;
+ public float iconTranslationY;
+ public int iconDensity;
+ public int iconSize;
+ public float[] colorFilter;
+
+ // Palettized background items
+ public int iconPaletteBack;
+ public SwatchType swatchType;
+ public int[] defaultSwatchColors;
+
+ public ComposedIconInfo() {
+ super();
+ iconPaletteBack = 0;
+ swatchType = SwatchType.None;
+ iconRotation = 0;
+ iconTranslationX = 0;
+ iconTranslationY = 0;
+ iconScale = 1f;
+ }
+
+ private ComposedIconInfo(Parcel source) {
+ iconScale = source.readFloat();
+ iconRotation = source.readFloat();
+ iconRotationVariance = source.readFloat();
+ iconTranslationX = source.readFloat();
+ iconTranslationY = source.readFloat();
+ iconDensity = source.readInt();
+ iconSize = source.readInt();
+ int backCount = source.readInt();
+ if (backCount > 0) {
+ iconBacks = new int[backCount];
+ for (int i = 0; i < backCount; i++) {
+ iconBacks[i] = source.readInt();
+ }
+ }
+ iconMask = source.readInt();
+ iconUpon = source.readInt();
+ int colorFilterSize = source.readInt();
+ if (colorFilterSize > 0) {
+ colorFilter = new float[colorFilterSize];
+ for (int i = 0; i < colorFilterSize; i++) {
+ colorFilter[i] = source.readFloat();
+ }
+ }
+ iconPaletteBack = source.readInt();
+ swatchType = SwatchType.values()[source.readInt()];
+ int numDefaultColors = source.readInt();
+ if (numDefaultColors > 0) {
+ defaultSwatchColors = new int[numDefaultColors];
+ for (int i = 0; i < numDefaultColors; i++) {
+ defaultSwatchColors[i] = source.readInt();
+ }
+ }
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeFloat(iconScale);
+ dest.writeFloat(iconRotation);
+ dest.writeFloat(iconRotationVariance);
+ dest.writeFloat(iconTranslationX);
+ dest.writeFloat(iconTranslationY);
+ dest.writeInt(iconDensity);
+ dest.writeInt(iconSize);
+ dest.writeInt(iconBacks != null ? iconBacks.length : 0);
+ if (iconBacks != null) {
+ for (int resId : iconBacks) {
+ dest.writeInt(resId);
+ }
+ }
+ dest.writeInt(iconMask);
+ dest.writeInt(iconUpon);
+ if (colorFilter != null) {
+ dest.writeInt(colorFilter.length);
+ for (float val : colorFilter) {
+ dest.writeFloat(val);
+ }
+ } else {
+ dest.writeInt(0);
+ }
+ dest.writeInt(iconPaletteBack);
+ dest.writeInt(swatchType.ordinal());
+ if (defaultSwatchColors != null) {
+ dest.writeInt(defaultSwatchColors.length);
+ for (int color : defaultSwatchColors) {
+ dest.writeInt(color);
+ }
+ } else {
+ dest.writeInt(0);
+ }
+ }
+
+ public static final Creator<ComposedIconInfo> CREATOR
+ = new Creator<ComposedIconInfo>() {
+ @Override
+ public ComposedIconInfo createFromParcel(Parcel source) {
+ return new ComposedIconInfo(source);
+ }
+
+ @Override
+ public ComposedIconInfo[] newArray(int size) {
+ return new ComposedIconInfo[0];
+ }
+ };
+
+ public enum SwatchType {
+ None,
+ Vibrant,
+ VibrantLight,
+ VibrantDark,
+ Muted,
+ MutedLight,
+ MutedDark
+ }
+}
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 235f294..479010d 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -40,6 +40,8 @@ import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.AssetManager;
import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
+import android.content.res.IThemeService;
+import android.content.res.ThemeManager;
import android.content.res.Resources;
import android.database.DatabaseErrorHandler;
import android.database.sqlite.SQLiteDatabase;
@@ -74,6 +76,7 @@ import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.util.ArrayList;
class ReceiverRestrictedContext extends ContextWrapper {
ReceiverRestrictedContext(Context base) {
@@ -269,6 +272,15 @@ class ContextImpl extends Context {
}
@Override
+ public void recreateTheme() {
+ if (mTheme != null) {
+ Resources.Theme newTheme = mResources.newTheme();
+ newTheme.applyStyle(mThemeResource, true);
+ mTheme.setTo(newTheme);
+ }
+ }
+
+ @Override
public ClassLoader getClassLoader() {
return mPackageInfo != null ?
mPackageInfo.getClassLoader() : ClassLoader.getSystemClassLoader();
@@ -1657,13 +1669,19 @@ class ContextImpl extends Context {
@Override
public Context createApplicationContext(ApplicationInfo application, int flags)
throws NameNotFoundException {
+ return createApplicationContext(application, null, flags);
+ }
+
+ @Override
+ public Context createApplicationContext(ApplicationInfo application, String themePackageName,
+ int flags) throws NameNotFoundException {
LoadedApk pi = mMainThread.getPackageInfo(application, mResources.getCompatibilityInfo(),
flags | CONTEXT_REGISTER_PACKAGE);
if (pi != null) {
final boolean restricted = (flags & CONTEXT_RESTRICTED) == CONTEXT_RESTRICTED;
ContextImpl c = new ContextImpl(this, mMainThread, pi, mActivityToken,
new UserHandle(UserHandle.getUserId(application.uid)), restricted,
- mDisplay, null, Display.INVALID_DISPLAY);
+ mDisplay, null, Display.INVALID_DISPLAY, themePackageName);
if (c.mResources != null) {
return c;
}
@@ -1676,24 +1694,30 @@ class ContextImpl extends Context {
@Override
public Context createPackageContext(String packageName, int flags)
throws NameNotFoundException {
- return createPackageContextAsUser(packageName, flags,
+ return createPackageContextAsUser(packageName, null, flags,
mUser != null ? mUser : Process.myUserHandle());
}
@Override
public Context createPackageContextAsUser(String packageName, int flags, UserHandle user)
throws NameNotFoundException {
+ return createPackageContextAsUser(packageName, null, flags, user);
+ }
+
+ @Override
+ public Context createPackageContextAsUser(String packageName, String themePackageName,
+ int flags, UserHandle user) throws NameNotFoundException {
final boolean restricted = (flags & CONTEXT_RESTRICTED) == CONTEXT_RESTRICTED;
if (packageName.equals("system") || packageName.equals("android")) {
return new ContextImpl(this, mMainThread, mPackageInfo, mActivityToken,
- user, restricted, mDisplay, null, Display.INVALID_DISPLAY);
+ user, restricted, mDisplay, null, Display.INVALID_DISPLAY, themePackageName);
}
LoadedApk pi = mMainThread.getPackageInfo(packageName, mResources.getCompatibilityInfo(),
flags | CONTEXT_REGISTER_PACKAGE, user.getIdentifier());
if (pi != null) {
ContextImpl c = new ContextImpl(this, mMainThread, pi, mActivityToken,
- user, restricted, mDisplay, null, Display.INVALID_DISPLAY);
+ user, restricted, mDisplay, null, Display.INVALID_DISPLAY, themePackageName);
if (c.mResources != null) {
return c;
}
@@ -1774,7 +1798,7 @@ class ContextImpl extends Context {
static ContextImpl createSystemContext(ActivityThread mainThread) {
LoadedApk packageInfo = new LoadedApk(mainThread);
ContextImpl context = new ContextImpl(null, mainThread,
- packageInfo, null, null, false, null, null, Display.INVALID_DISPLAY);
+ packageInfo, null, null, false, null, null, Display.INVALID_DISPLAY, null);
context.mResources.updateConfiguration(context.mResourcesManager.getConfiguration(),
context.mResourcesManager.getDisplayMetricsLocked());
return context;
@@ -1783,19 +1807,27 @@ class ContextImpl extends Context {
static ContextImpl createAppContext(ActivityThread mainThread, LoadedApk packageInfo) {
if (packageInfo == null) throw new IllegalArgumentException("packageInfo");
return new ContextImpl(null, mainThread,
- packageInfo, null, null, false, null, null, Display.INVALID_DISPLAY);
+ packageInfo, null, null, false, null, null, Display.INVALID_DISPLAY, null);
}
static ContextImpl createActivityContext(ActivityThread mainThread,
LoadedApk packageInfo, int displayId, Configuration overrideConfiguration) {
if (packageInfo == null) throw new IllegalArgumentException("packageInfo");
return new ContextImpl(null, mainThread, packageInfo, null, null, false,
- null, overrideConfiguration, displayId);
+ null, overrideConfiguration, displayId, null);
}
private ContextImpl(ContextImpl container, ActivityThread mainThread,
LoadedApk packageInfo, IBinder activityToken, UserHandle user, boolean restricted,
Display display, Configuration overrideConfiguration, int createDisplayWithId) {
+ this(container, mainThread, packageInfo, activityToken, user, restricted, display,
+ overrideConfiguration, createDisplayWithId, null);
+ }
+
+ private ContextImpl(ContextImpl container, ActivityThread mainThread,
+ LoadedApk packageInfo, IBinder activityToken, UserHandle user, boolean restricted,
+ Display display, Configuration overrideConfiguration, int createDisplayWithId,
+ String themePackageName) {
mOuterContext = this;
mMainThread = mainThread;
@@ -1829,16 +1861,27 @@ class ContextImpl extends Context {
mDisplay = (createDisplayWithId == Display.INVALID_DISPLAY) ? display
: ResourcesManager.getInstance().getAdjustedDisplay(displayId, mDisplayAdjustments);
+ // We need to create the content resolver before all the context resources creation because
+ // the content resolver is reference by the outer context while the theme information
+ // is created.
+ mContentResolver = new ApplicationContentResolver(this, mainThread, user);
+
Resources resources = packageInfo.getResources(mainThread);
if (resources != null) {
if (displayId != Display.DEFAULT_DISPLAY
+ || themePackageName != null
|| overrideConfiguration != null
|| (compatInfo != null && compatInfo.applicationScale
!= resources.getCompatibilityInfo().applicationScale)) {
- resources = mResourcesManager.getTopLevelResources(packageInfo.getResDir(),
- packageInfo.getSplitResDirs(), packageInfo.getOverlayDirs(),
+ resources = themePackageName == null ? mResourcesManager.getTopLevelResources(
+ packageInfo.getResDir(), packageInfo.getSplitResDirs(),
+ packageInfo.getOverlayDirs(),
packageInfo.getApplicationInfo().sharedLibraryFiles, displayId,
- overrideConfiguration, compatInfo);
+ packageInfo.getAppDir(), overrideConfiguration, compatInfo, mOuterContext,
+ packageInfo.getApplicationInfo().isThemeable) :
+ mResourcesManager.getTopLevelThemedResources(packageInfo.getResDir(), displayId,
+ packageInfo.getPackageName(), themePackageName, compatInfo,
+ packageInfo.getApplicationInfo().isThemeable);
}
}
mResources = resources;
@@ -1859,8 +1902,6 @@ class ContextImpl extends Context {
mOpPackageName = mBasePackageName;
}
}
-
- mContentResolver = new ApplicationContentResolver(this, mainThread, user);
}
void installSystemApplicationInfo(ApplicationInfo info, ClassLoader classLoader) {
@@ -1950,9 +1991,12 @@ class ContextImpl extends Context {
* unable to create, they are filtered by replacing with {@code null}.
*/
private File[] ensureDirsExistOrFilter(File[] dirs) {
- File[] result = new File[dirs.length];
+ ArrayList<File> result = new ArrayList<File>(dirs.length);
for (int i = 0; i < dirs.length; i++) {
File dir = dirs[i];
+ if (Environment.MEDIA_REMOVED.equals(Environment.getStorageState(dir))) {
+ continue;
+ }
if (!dir.exists()) {
if (!dir.mkdirs()) {
// recheck existence in case of cross-process race
@@ -1974,9 +2018,9 @@ class ContextImpl extends Context {
}
}
}
- result[i] = dir;
+ result.add(dir);
}
- return result;
+ return result.toArray(new File[result.size()]);
}
// ----------------------------------------------------------------------
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index ef121ce..a27f9c8 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -122,6 +122,7 @@ public interface IActivityManager extends IInterface {
public void activitySlept(IBinder token) throws RemoteException;
public void activityDestroyed(IBinder token) throws RemoteException;
public String getCallingPackage(IBinder token) throws RemoteException;
+ public String getCallingPackageForBroadcast(boolean foreground) throws RemoteException;
public ComponentName getCallingActivity(IBinder token) throws RemoteException;
public List<IAppTask> getAppTasks(String callingPackage) throws RemoteException;
public int addAppTask(IBinder activityToken, Intent intent,
@@ -411,7 +412,8 @@ public interface IActivityManager extends IInterface {
public void keyguardWaitingForActivityDrawn() throws RemoteException;
public void keyguardGoingAway(boolean disableWindowAnimations,
- boolean keyguardGoingToNotificationShade) throws RemoteException;
+ boolean keyguardGoingToNotificationShade,
+ boolean keyguardShowingMedia) throws RemoteException;
public boolean shouldUpRecreateTask(IBinder token, String destAffinity)
throws RemoteException;
@@ -839,6 +841,10 @@ public interface IActivityManager extends IInterface {
int START_IN_PLACE_ANIMATION_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+240;
int CHECK_PERMISSION_WITH_TOKEN_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+241;
int REGISTER_TASK_STACK_LISTENER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+242;
+ // 243: Available
+
+ // start of CM transactions
+ int GET_CALLING_PACKAGE_FOR_BROADCAST_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+244;
// Start of M transactions
int NOTIFY_CLEARTEXT_NETWORK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+280;
diff --git a/core/java/android/app/IAlarmManager.aidl b/core/java/android/app/IAlarmManager.aidl
index 327c00b..4fdbfaa 100644
--- a/core/java/android/app/IAlarmManager.aidl
+++ b/core/java/android/app/IAlarmManager.aidl
@@ -35,6 +35,8 @@ interface IAlarmManager {
void remove(in PendingIntent operation);
long getNextWakeFromIdleTime();
AlarmManager.AlarmClockInfo getNextAlarmClock(int userId);
+ // update the uids being synchronized by network socket request manager
+ void updateBlockedUids(int uid, boolean isBlocked);
}
diff --git a/core/java/android/app/IWallpaperManager.aidl b/core/java/android/app/IWallpaperManager.aidl
index ccba250..c717459 100644
--- a/core/java/android/app/IWallpaperManager.aidl
+++ b/core/java/android/app/IWallpaperManager.aidl
@@ -30,6 +30,12 @@ interface IWallpaperManager {
* Set the wallpaper.
*/
ParcelFileDescriptor setWallpaper(String name, in String callingPackage);
+
+ /**
+ * Set the keyguard wallpaper.
+ * @hide
+ */
+ ParcelFileDescriptor setKeyguardWallpaper(String name, in String callingPackage);
/**
* Set the live wallpaper.
@@ -46,6 +52,13 @@ interface IWallpaperManager {
*/
ParcelFileDescriptor getWallpaper(IWallpaperManagerCallback cb,
out Bundle outParams);
+
+ /**
+ * Get the keyguard wallpaper.
+ * @hide
+ */
+ ParcelFileDescriptor getKeyguardWallpaper(IWallpaperManagerCallback cb,
+ out Bundle outParams);
/**
* Get information about a live wallpaper.
@@ -57,6 +70,12 @@ interface IWallpaperManager {
*/
void clearWallpaper(in String callingPackage);
+ /*
+ * Clear the keyguard wallpaper.
+ * @hide
+ */
+ void clearKeyguardWallpaper();
+
/**
* Return whether there is a wallpaper set with the given name.
*/
diff --git a/core/java/android/app/IWallpaperManagerCallback.aidl b/core/java/android/app/IWallpaperManagerCallback.aidl
index 991b2bc..b217318 100644
--- a/core/java/android/app/IWallpaperManagerCallback.aidl
+++ b/core/java/android/app/IWallpaperManagerCallback.aidl
@@ -28,4 +28,9 @@ oneway interface IWallpaperManagerCallback {
* Called when the wallpaper has changed
*/
void onWallpaperChanged();
+
+ /**
+ * Called when the keygaurd wallpaper has changed
+ */
+ void onKeyguardWallpaperChanged();
}
diff --git a/core/java/android/app/IconPackHelper.java b/core/java/android/app/IconPackHelper.java
new file mode 100644
index 0000000..627330f
--- /dev/null
+++ b/core/java/android/app/IconPackHelper.java
@@ -0,0 +1,1057 @@
+/*
+ * Copyright (C) 2014 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;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Random;
+
+import android.content.pm.PackageInfo;
+import android.content.res.IThemeService;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.ColorMatrix;
+import android.graphics.ColorMatrixColorFilter;
+import android.graphics.Paint;
+import android.graphics.PaintFlagsDrawFilter;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffColorFilter;
+import android.graphics.PorterDuffXfermode;
+import android.graphics.Rect;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.PaintDrawable;
+import android.graphics.drawable.VectorDrawable;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.Log;
+import android.util.TypedValue;
+import com.android.internal.util.cm.palette.Palette;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlPullParserFactory;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.pm.ActivityInfo;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.ThemeUtils;
+import android.content.res.AssetManager;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.content.res.XmlResourceParser;
+import android.graphics.drawable.Drawable;
+import android.text.TextUtils;
+import android.util.DisplayMetrics;
+
+/** @hide */
+public class IconPackHelper {
+ private static final String TAG = IconPackHelper.class.getSimpleName();
+
+ private static final boolean DEBUG = false;
+
+ private static final String ICON_MASK_TAG = "iconmask";
+ private static final String ICON_BACK_TAG = "iconback";
+ private static final String ICON_UPON_TAG = "iconupon";
+ private static final String ICON_SCALE_TAG = "scale";
+ private static final String ICON_ROTATE_TAG = "rotate";
+ private static final String ICON_TRANSLATE_TAG = "translate";
+ private static final String ICON_BACK_FORMAT = "iconback%d";
+
+ // Palettized icon background constants
+ private static final String ICON_PALETTIZED_BACK_TAG = "paletteback";
+ private static final String IMG_ATTR = "img";
+ private static final String SWATCH_TYPE_ATTR = "swatchType";
+ private static final String DEFAULT_SWATCH_COLOR_ATTR = "defaultSwatchColor";
+ private static final String VIBRANT_VALUE = "vibrant";
+ private static final String VIBRANT_LIGHT_VALUE = "vibrantLight";
+ private static final String VIBRANT_DARK_VALUE = "vibrantDark";
+ private static final String MUTED_VALUE = "muted";
+ private static final String MUTED_LIGHT_VALUE = "mutedLight";
+ private static final String MUTED_DARK_VALUE = "mutedDark";
+ private static final int NUM_PALETTE_COLORS = 32;
+
+ // Rotation and translation constants
+ private static final String ANGLE_ATTR = "angle";
+ private static final String ANGLE_VARIANCE = "plusMinus";
+ private static final String TRANSLATE_X_ATTR = "xOffset";
+ private static final String TRANSLATE_Y_ATTR = "yOffset";
+
+ private static final ComponentName ICON_BACK_COMPONENT;
+ private static final ComponentName ICON_MASK_COMPONENT;
+ private static final ComponentName ICON_UPON_COMPONENT;
+ private static final ComponentName ICON_SCALE_COMPONENT;
+
+ private static final float DEFAULT_SCALE = 1.0f;
+ private static final int COMPOSED_ICON_COOKIE = 128;
+
+ private final Context mContext;
+ private Map<ComponentName, String> mIconPackResourceMap;
+ private String mLoadedIconPackName;
+ private Resources mLoadedIconPackResource;
+ private ComposedIconInfo mComposedIconInfo;
+ private int mIconBackCount = 0;
+ private ColorFilterUtils.Builder mFilterBuilder;
+
+ static {
+ ICON_BACK_COMPONENT = new ComponentName(ICON_BACK_TAG, "");
+ ICON_MASK_COMPONENT = new ComponentName(ICON_MASK_TAG, "");
+ ICON_UPON_COMPONENT = new ComponentName(ICON_UPON_TAG, "");
+ ICON_SCALE_COMPONENT = new ComponentName(ICON_SCALE_TAG, "");
+ }
+
+ public IconPackHelper(Context context) {
+ mContext = context;
+ mIconPackResourceMap = new HashMap<ComponentName, String>();
+ ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
+ mComposedIconInfo = new ComposedIconInfo();
+ mComposedIconInfo.iconSize = am.getLauncherLargeIconSize();
+ mComposedIconInfo.iconDensity = am.getLauncherLargeIconDensity();
+ mFilterBuilder = new ColorFilterUtils.Builder();
+ }
+
+ private void loadResourcesFromXmlParser(XmlPullParser parser,
+ Map<ComponentName, String> iconPackResources)
+ throws XmlPullParserException, IOException {
+ mIconBackCount = 0;
+ int eventType = parser.getEventType();
+ do {
+
+ if (eventType != XmlPullParser.START_TAG) {
+ continue;
+ }
+
+ if (parseComposedIconComponent(parser, iconPackResources)) {
+ continue;
+ }
+
+ if (ColorFilterUtils.parseIconFilter(parser, mFilterBuilder)) {
+ continue;
+ }
+
+ if (parser.getName().equalsIgnoreCase(ICON_SCALE_TAG)) {
+ String factor = parser.getAttributeValue(null, "factor");
+ if (factor == null) {
+ if (parser.getAttributeCount() == 1) {
+ factor = parser.getAttributeValue(0);
+ }
+ }
+ iconPackResources.put(ICON_SCALE_COMPONENT, factor);
+ continue;
+ }
+
+ if (parseRotationComponent(parser, mComposedIconInfo)) {
+ continue;
+ }
+
+ if (parseTranslationComponent(parser, mComposedIconInfo)) {
+ continue;
+ }
+
+ if (!parser.getName().equalsIgnoreCase("item")) {
+ continue;
+ }
+
+ String component = parser.getAttributeValue(null, "component");
+ String drawable = parser.getAttributeValue(null, "drawable");
+
+ // Validate component/drawable exist
+ if (TextUtils.isEmpty(component) || TextUtils.isEmpty(drawable)) {
+ continue;
+ }
+
+ // Validate format/length of component
+ if (!component.startsWith("ComponentInfo{") || !component.endsWith("}")
+ || component.length() < 16 || drawable.length() == 0) {
+ continue;
+ }
+
+ // Sanitize stored value
+ component = component.substring(14, component.length() - 1).toLowerCase();
+
+ ComponentName name = null;
+ if (!component.contains("/")) {
+ // Package icon reference
+ name = new ComponentName(component.toLowerCase(), "");
+ } else {
+ name = ComponentName.unflattenFromString(component);
+ }
+
+ if (name != null) {
+ iconPackResources.put(name, drawable);
+ }
+ } while ((eventType = parser.next()) != XmlPullParser.END_DOCUMENT);
+ }
+
+ private boolean isComposedIconComponent(String tag) {
+ return ICON_MASK_TAG.equalsIgnoreCase(tag) ||
+ ICON_BACK_TAG.equalsIgnoreCase(tag) ||
+ ICON_UPON_TAG.equalsIgnoreCase(tag) ||
+ ICON_PALETTIZED_BACK_TAG.equalsIgnoreCase(tag);
+ }
+
+ private boolean parseComposedIconComponent(XmlPullParser parser,
+ Map<ComponentName, String> iconPackResources) {
+ String icon;
+ String tag = parser.getName();
+ if (!isComposedIconComponent(tag)) {
+ return false;
+ }
+
+ if (parser.getAttributeCount() >= 1) {
+ if (ICON_BACK_TAG.equalsIgnoreCase(tag)) {
+ mIconBackCount = parser.getAttributeCount();
+ for (int i = 0; i < mIconBackCount; i++) {
+ tag = String.format(ICON_BACK_FORMAT, i);
+ icon = parser.getAttributeValue(i);
+ iconPackResources.put(new ComponentName(tag, ""), icon);
+ }
+ } else if (ICON_PALETTIZED_BACK_TAG.equalsIgnoreCase(tag)) {
+ parsePalettizedBackground(parser, mComposedIconInfo);
+ } else {
+ icon = parser.getAttributeValue(0);
+ iconPackResources.put(new ComponentName(tag, ""),
+ icon);
+ }
+ return true;
+ }
+
+ return false;
+ }
+
+ private void parsePalettizedBackground(XmlPullParser parser, ComposedIconInfo iconInfo) {
+ int attrCount = parser.getAttributeCount();
+ ArrayList<Integer> convertedColors = new ArrayList<Integer>();
+ for (int i = 0; i < attrCount; i++) {
+ String name = parser.getAttributeName(i);
+ String value = parser.getAttributeValue(i);
+ if (TextUtils.isEmpty(name)) {
+ Log.w(TAG, "Attribute name cannot be empty or null");
+ continue;
+ }
+ if (TextUtils.isEmpty(value)) {
+ Log.w(TAG, "Attribute value cannot be empty or null");
+ continue;
+ }
+ if (IMG_ATTR.equalsIgnoreCase(name)) {
+ iconInfo.iconPaletteBack = getResourceIdForDrawable(value);
+ if (DEBUG) {
+ Log.d(TAG, String.format("img=%s, resId=%d", value,
+ iconInfo.iconPaletteBack));
+ }
+ } else if (SWATCH_TYPE_ATTR.equalsIgnoreCase(name)) {
+ ComposedIconInfo.SwatchType type = ComposedIconInfo.SwatchType.None;
+ if (VIBRANT_VALUE.equalsIgnoreCase(value)) {
+ type = ComposedIconInfo.SwatchType.Vibrant;
+ } else if (VIBRANT_LIGHT_VALUE.equalsIgnoreCase(value)) {
+ type = ComposedIconInfo.SwatchType.VibrantLight;
+ } else if (VIBRANT_DARK_VALUE.equalsIgnoreCase(value)) {
+ type = ComposedIconInfo.SwatchType.VibrantDark;
+ } else if (MUTED_VALUE.equalsIgnoreCase(value)) {
+ type = ComposedIconInfo.SwatchType.Muted;
+ } else if (MUTED_LIGHT_VALUE.equalsIgnoreCase(value)) {
+ type = ComposedIconInfo.SwatchType.MutedLight;
+ } else if (MUTED_DARK_VALUE.equalsIgnoreCase(value)) {
+ type = ComposedIconInfo.SwatchType.MutedDark;
+ }
+ if (type != ComposedIconInfo.SwatchType.None) {
+ iconInfo.swatchType = type;
+ if (DEBUG) Log.d(TAG, "PaletteType=" + type);
+ }
+ } else if (name.startsWith(DEFAULT_SWATCH_COLOR_ATTR)) {
+ try {
+ // ensure alpha is always 0xff
+ convertedColors.add(Color.parseColor(value) | 0xff000000);
+ } catch (IllegalArgumentException e) {
+ Log.w(TAG, "Invalid color format", e);
+ }
+ }
+ if (convertedColors.size() > 0) {
+ iconInfo.defaultSwatchColors = new int[convertedColors.size()];
+ for (int j = 0; j < convertedColors.size(); j++) {
+ iconInfo.defaultSwatchColors[j] = convertedColors.get(j);
+ }
+ }
+ }
+ }
+
+ private boolean parseRotationComponent(XmlPullParser parser, ComposedIconInfo iconInfo) {
+ if (!parser.getName().equalsIgnoreCase(ICON_ROTATE_TAG)) return false;
+ String angle = parser.getAttributeValue(null, ANGLE_ATTR);
+ String variance = parser.getAttributeValue(null, ANGLE_VARIANCE);
+ if (angle != null) {
+ try {
+ iconInfo.iconRotation = Float.valueOf(angle);
+ } catch (NumberFormatException e) {
+ Log.w(TAG, "Error parsing " + ANGLE_ATTR, e);
+ }
+ }
+ if (variance != null) {
+ try {
+ iconInfo.iconRotationVariance = Float.valueOf(variance);
+ } catch (NumberFormatException e) {
+ Log.w(TAG, "Error parsing " + ANGLE_VARIANCE, e);
+ }
+ }
+ return true;
+ }
+
+ private boolean parseTranslationComponent(XmlPullParser parser, ComposedIconInfo iconInfo) {
+ if (!parser.getName().equalsIgnoreCase(ICON_TRANSLATE_TAG)) return false;
+
+ final float density = mContext.getResources().getDisplayMetrics().density;
+ String translateX = parser.getAttributeValue(null, TRANSLATE_X_ATTR);
+ String translateY = parser.getAttributeValue(null, TRANSLATE_Y_ATTR);
+ if (translateX != null) {
+ try {
+ iconInfo.iconTranslationX = Float.valueOf(translateX) * density;
+ } catch (NumberFormatException e) {
+ Log.w(TAG, "Error parsing " + TRANSLATE_X_ATTR, e);
+ }
+ }
+ if (translateY != null) {
+ try {
+ iconInfo.iconTranslationY = Float.valueOf(translateY) * density;
+ } catch (NumberFormatException e) {
+ Log.w(TAG, "Error parsing " + TRANSLATE_Y_ATTR, e);
+ }
+ }
+ return true;
+ }
+
+ public void loadIconPack(String packageName) throws NameNotFoundException {
+ if (packageName == null) {
+ mLoadedIconPackResource = null;
+ mLoadedIconPackName = null;
+ mComposedIconInfo.iconBacks = null;
+ mComposedIconInfo.iconMask = mComposedIconInfo.iconUpon = 0;
+ mComposedIconInfo.iconScale = 0;
+ mComposedIconInfo.iconRotation = 0;
+ mComposedIconInfo.iconTranslationX = 0;
+ mComposedIconInfo.iconTranslationY = 0;
+ mComposedIconInfo.colorFilter = null;
+ mComposedIconInfo.iconPaletteBack = 0;
+ mComposedIconInfo.swatchType = ComposedIconInfo.SwatchType.None;
+ } else {
+ mIconBackCount = 0;
+ Resources res = createIconResource(mContext, packageName);
+ mLoadedIconPackResource = res;
+ mLoadedIconPackName = packageName;
+ mIconPackResourceMap = getIconResMapFromXml(res, packageName);
+ loadComposedIconComponents();
+ ColorMatrix cm = mFilterBuilder.build();
+ if (cm != null) {
+ mComposedIconInfo.colorFilter = cm.getArray().clone();
+ }
+ }
+ }
+
+ public ComposedIconInfo getComposedIconInfo() {
+ return mComposedIconInfo;
+ }
+
+ private void loadComposedIconComponents() {
+ mComposedIconInfo.iconMask = getResourceIdForName(ICON_MASK_COMPONENT);
+ mComposedIconInfo.iconUpon = getResourceIdForName(ICON_UPON_COMPONENT);
+
+ // Take care of loading iconback which can have multiple images
+ if (mIconBackCount > 0) {
+ mComposedIconInfo.iconBacks = new int[mIconBackCount];
+ for (int i = 0; i < mIconBackCount; i++) {
+ mComposedIconInfo.iconBacks[i] =
+ getResourceIdForName(
+ new ComponentName(String.format(ICON_BACK_FORMAT, i), ""));
+ }
+ }
+
+ // Get the icon scale from this pack
+ String scale = mIconPackResourceMap.get(ICON_SCALE_COMPONENT);
+ if (scale != null) {
+ try {
+ mComposedIconInfo.iconScale = Float.valueOf(scale);
+ } catch (NumberFormatException e) {
+ mComposedIconInfo.iconScale = DEFAULT_SCALE;
+ }
+ } else {
+ mComposedIconInfo.iconScale = DEFAULT_SCALE;
+ }
+ }
+
+ private int getResourceIdForName(ComponentName component) {
+ String item = mIconPackResourceMap.get(component);
+ if (!TextUtils.isEmpty(item)) {
+ return getResourceIdForDrawable(item);
+ }
+ return 0;
+ }
+
+ public static Resources createIconResource(Context context, String packageName)
+ throws NameNotFoundException {
+ PackageInfo info = context.getPackageManager().getPackageInfo(packageName, 0);
+ String themeApk = info.applicationInfo.publicSourceDir;
+
+ String prefixPath;
+ String iconApkPath;
+ String iconResPath;
+ if (info.isLegacyIconPackApk) {
+ iconResPath = "";
+ iconApkPath = "";
+ prefixPath = "";
+ } else {
+ prefixPath = ThemeUtils.ICONS_PATH; //path inside APK
+ iconApkPath = ThemeUtils.getIconPackApkPath(packageName);
+ iconResPath = ThemeUtils.getIconPackResPath(packageName);
+ }
+
+ AssetManager assets = new AssetManager();
+ assets.addIconPath(themeApk, iconApkPath,
+ prefixPath, Resources.THEME_ICON_PKG_ID);
+
+ DisplayMetrics dm = context.getResources().getDisplayMetrics();
+ Configuration config = context.getResources().getConfiguration();
+ Resources res = new Resources(assets, dm, config);
+ return res;
+ }
+
+ public Map<ComponentName, String> getIconResMapFromXml(Resources res, String packageName) {
+ XmlPullParser parser = null;
+ InputStream inputStream = null;
+ Map<ComponentName, String> iconPackResources = new HashMap<ComponentName, String>();
+
+ try {
+ inputStream = res.getAssets().open("appfilter.xml");
+ XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
+ parser = factory.newPullParser();
+ parser.setInput(inputStream, "UTF-8");
+ } catch (Exception e) {
+ // Catch any exception since we want to fall back to parsing the xml/
+ // resource in all cases
+ int resId = res.getIdentifier("appfilter", "xml", packageName);
+ if (resId != 0) {
+ parser = res.getXml(resId);
+ }
+ }
+
+ if (parser != null) {
+ try {
+ loadResourcesFromXmlParser(parser, iconPackResources);
+ return iconPackResources;
+ } catch (XmlPullParserException e) {
+ e.printStackTrace();
+ } catch (IOException e) {
+ e.printStackTrace();
+ } finally {
+ // Cleanup resources
+ if (parser instanceof XmlResourceParser) {
+ ((XmlResourceParser) parser).close();
+ } else if (inputStream != null) {
+ try {
+ inputStream.close();
+ } catch (IOException e) {
+ }
+ }
+ }
+ }
+
+ // Application uses a different theme format (most likely launcher pro)
+ int arrayId = res.getIdentifier("theme_iconpack", "array", packageName);
+ if (arrayId == 0) {
+ arrayId = res.getIdentifier("icon_pack", "array", packageName);
+ }
+
+ if (arrayId != 0) {
+ String[] iconPack = res.getStringArray(arrayId);
+ ComponentName compName = null;
+ for (String entry : iconPack) {
+
+ if (TextUtils.isEmpty(entry)) {
+ continue;
+ }
+
+ String icon = entry;
+ entry = entry.replaceAll("_", ".");
+
+ compName = new ComponentName(entry.toLowerCase(), "");
+ iconPackResources.put(compName, icon);
+
+ int activityIndex = entry.lastIndexOf(".");
+ if (activityIndex <= 0 || activityIndex == entry.length() - 1) {
+ continue;
+ }
+
+ String iconPackage = entry.substring(0, activityIndex);
+ if (TextUtils.isEmpty(iconPackage)) {
+ continue;
+ }
+
+ String iconActivity = entry.substring(activityIndex + 1);
+ if (TextUtils.isEmpty(iconActivity)) {
+ continue;
+ }
+
+ // Store entries as lower case to ensure match
+ iconPackage = iconPackage.toLowerCase();
+ iconActivity = iconActivity.toLowerCase();
+
+ iconActivity = iconPackage + "." + iconActivity;
+ compName = new ComponentName(iconPackage, iconActivity);
+ iconPackResources.put(compName, icon);
+ }
+ }
+ return iconPackResources;
+ }
+
+ boolean isIconPackLoaded() {
+ return mLoadedIconPackResource != null &&
+ mLoadedIconPackName != null &&
+ mIconPackResourceMap != null;
+ }
+
+ private int getResourceIdForDrawable(String resource) {
+ int resId =
+ mLoadedIconPackResource.getIdentifier(resource, "drawable",mLoadedIconPackName);
+ return resId;
+ }
+
+ public int getResourceIdForActivityIcon(ActivityInfo info) {
+ if (!isIconPackLoaded()) {
+ return 0;
+ }
+ ComponentName compName = new ComponentName(info.packageName.toLowerCase(),
+ info.name.toLowerCase());
+ String drawable = mIconPackResourceMap.get(compName);
+ if (drawable != null) {
+ int resId = getResourceIdForDrawable(drawable);
+ if (resId != 0) return resId;
+ }
+
+ // Icon pack doesn't have an icon for the activity, fallback to package icon
+ compName = new ComponentName(info.packageName.toLowerCase(), "");
+ drawable = mIconPackResourceMap.get(compName);
+ if (drawable == null) {
+ return 0;
+ }
+ return getResourceIdForDrawable(drawable);
+ }
+
+ public int getResourceIdForApp(String pkgName) {
+ ActivityInfo info = new ActivityInfo();
+ info.packageName = pkgName;
+ info.name = "";
+ return getResourceIdForActivityIcon(info);
+ }
+
+ public Drawable getDrawableForActivity(ActivityInfo info) {
+ int id = getResourceIdForActivityIcon(info);
+ if (id == 0) return null;
+ return mLoadedIconPackResource.getDrawable(id, null, false);
+ }
+
+ public Drawable getDrawableForActivityWithDensity(ActivityInfo info, int density) {
+ int id = getResourceIdForActivityIcon(info);
+ if (id == 0) return null;
+ return mLoadedIconPackResource.getDrawableForDensity(id, density, null, false);
+ }
+
+ public static boolean shouldComposeIcon(ComposedIconInfo iconInfo) {
+ return iconInfo != null &&
+ (iconInfo.iconBacks != null ||
+ iconInfo.iconMask != 0 ||
+ iconInfo.iconUpon != 0 ||
+ iconInfo.colorFilter != null ||
+ iconInfo.iconPaletteBack != 0 ||
+ iconInfo.iconRotation != 0 ||
+ iconInfo.iconRotationVariance != 0 ||
+ iconInfo.iconTranslationX != 0 ||
+ iconInfo.iconTranslationY != 0 ||
+ iconInfo.iconScale != 1f);
+ }
+
+ public static class IconCustomizer {
+ private static final Random sRandom = new Random();
+ private static final IThemeService sThemeService;
+
+ static {
+ sThemeService = IThemeService.Stub.asInterface(
+ ServiceManager.getService(Context.THEME_SERVICE));
+ }
+
+ public static Drawable getComposedIconDrawable(Drawable icon, Context context,
+ ComposedIconInfo iconInfo) {
+ final Resources res = context.getResources();
+ return getComposedIconDrawable(icon, res, iconInfo);
+ }
+
+ public static Drawable getComposedIconDrawable(Drawable icon, Resources res,
+ ComposedIconInfo iconInfo) {
+ if (iconInfo == null) return icon;
+ int back = 0;
+ int defaultSwatchColor = 0;
+ if (iconInfo.swatchType != ComposedIconInfo.SwatchType.None) {
+ back = iconInfo.iconPaletteBack;
+ if (iconInfo.defaultSwatchColors.length > 0) {
+ defaultSwatchColor = iconInfo.defaultSwatchColors[
+ sRandom.nextInt(iconInfo.defaultSwatchColors.length)];
+ }
+ } else if (iconInfo.iconBacks != null && iconInfo.iconBacks.length > 0) {
+ back = iconInfo.iconBacks[sRandom.nextInt(iconInfo.iconBacks.length)];
+ }
+ Bitmap bmp = createIconBitmap(icon, res, back, defaultSwatchColor, iconInfo);
+ return bmp != null ? new BitmapDrawable(res, bmp): null;
+ }
+
+ public static void getValue(Resources res, int resId, TypedValue outValue,
+ Drawable baseIcon) {
+ final String pkgName = res.getAssets().getAppName();
+ final ComposedIconInfo iconInfo = res.getComposedIconInfo();
+ if (iconInfo == null) {
+ // No composed icon info available so return, keeping original value
+ return;
+ }
+ TypedValue tempValue = new TypedValue();
+ tempValue.setTo(outValue);
+ outValue.assetCookie = COMPOSED_ICON_COOKIE;
+ outValue.data = resId & (COMPOSED_ICON_COOKIE << 24 | 0x00ffffff);
+ outValue.string = getCachedIconPath(pkgName, resId, outValue.density);
+ int hashCode = outValue.string.hashCode() & 0x7fffffff;
+ int defaultSwatchColor = 0;
+
+ if (!(new File(outValue.string.toString()).exists())) {
+ // compose the icon and cache it
+ int back = 0;
+ if (iconInfo.swatchType != ComposedIconInfo.SwatchType.None) {
+ back = iconInfo.iconPaletteBack;
+ if (iconInfo.defaultSwatchColors.length > 0) {
+ defaultSwatchColor =iconInfo.defaultSwatchColors[
+ hashCode % iconInfo.defaultSwatchColors.length];
+ }
+ } else if (iconInfo.iconBacks != null && iconInfo.iconBacks.length > 0) {
+ back = iconInfo.iconBacks[hashCode % iconInfo.iconBacks.length];
+ }
+ if (DEBUG) {
+ Log.d(TAG, "Composing icon for " + pkgName);
+ }
+ Bitmap bmp = createIconBitmap(baseIcon, res, back, defaultSwatchColor, iconInfo);
+ if (!cacheComposedIcon(bmp, getCachedIconName(pkgName, resId, outValue.density))) {
+ Log.w(TAG, "Unable to cache icon " + outValue.string);
+ // restore the original TypedValue
+ outValue.setTo(tempValue);
+ }
+ }
+ }
+
+ private static Bitmap createIconBitmap(Drawable icon, Resources res, int iconBack,
+ int defaultSwatchColor, ComposedIconInfo iconInfo) {
+ if (iconInfo.iconSize <= 0) return null;
+
+ final Canvas canvas = new Canvas();
+ canvas.setDrawFilter(new PaintFlagsDrawFilter(Paint.ANTI_ALIAS_FLAG,
+ Paint.FILTER_BITMAP_FLAG));
+
+ int width = 0, height = 0;
+ int backTintColor = 0;
+ if (icon instanceof PaintDrawable) {
+ PaintDrawable painter = (PaintDrawable) icon;
+ painter.setIntrinsicWidth(iconInfo.iconSize);
+ painter.setIntrinsicHeight(iconInfo.iconSize);
+
+ // A PaintDrawable does not have an exact size
+ width = iconInfo.iconSize;
+ height = iconInfo.iconSize;
+ } else if (icon instanceof BitmapDrawable) {
+ // Ensure the bitmap has a density.
+ BitmapDrawable bitmapDrawable = (BitmapDrawable) icon;
+ Bitmap bitmap = bitmapDrawable.getBitmap();
+ if (bitmap.getDensity() == Bitmap.DENSITY_NONE) {
+ bitmapDrawable.setTargetDensity(res.getDisplayMetrics());
+ }
+ canvas.setDensity(bitmap.getDensity());
+
+ // If the original size of the icon isn't greater
+ // than twice the size of recommended large icons
+ // respect the original size of the icon
+ // otherwise enormous icons can easily create
+ // OOM situations.
+ if ((bitmap.getWidth() < (iconInfo.iconSize * 2))
+ && (bitmap.getHeight() < (iconInfo.iconSize * 2))) {
+ width = bitmap.getWidth();
+ height = bitmap.getHeight();
+ } else {
+ width = iconInfo.iconSize;
+ height = iconInfo.iconSize;
+ }
+ if (iconInfo.swatchType != ComposedIconInfo.SwatchType.None) {
+ Palette palette = Palette.generate(bitmap, NUM_PALETTE_COLORS);
+ switch (iconInfo.swatchType) {
+ case Vibrant:
+ backTintColor = palette.getVibrantColor(defaultSwatchColor);
+ break;
+ case VibrantLight:
+ backTintColor = palette.getLightVibrantColor(defaultSwatchColor);
+ break;
+ case VibrantDark:
+ backTintColor = palette.getDarkVibrantColor(defaultSwatchColor);
+ break;
+ case Muted:
+ backTintColor = palette.getMutedColor(defaultSwatchColor);
+ break;
+ case MutedLight:
+ backTintColor = palette.getLightMutedColor(defaultSwatchColor);
+ break;
+ case MutedDark:
+ backTintColor = palette.getDarkMutedColor(defaultSwatchColor);
+ break;
+ }
+ if (DEBUG) {
+ Log.d(TAG, String.format("palette tint color=0x%08x", backTintColor));
+ }
+ }
+ } else if (icon instanceof VectorDrawable) {
+ width = height = iconInfo.iconSize;
+ }
+
+ if (width <= 0 || height <= 0) return null;
+
+ Bitmap bitmap = Bitmap.createBitmap(width, height,
+ Bitmap.Config.ARGB_8888);
+ canvas.setBitmap(bitmap);
+
+ // Scale the original
+ Rect oldBounds = new Rect();
+ oldBounds.set(icon.getBounds());
+ icon.setBounds(0, 0, width, height);
+ canvas.save();
+ final float halfWidth = width / 2f;
+ final float halfHeight = height / 2f;
+ float angle = iconInfo.iconRotation;
+ if (iconInfo.iconRotationVariance != 0) {
+ angle += (sRandom.nextFloat() * (iconInfo.iconRotationVariance * 2))
+ - iconInfo.iconRotationVariance;
+ }
+ canvas.scale(iconInfo.iconScale, iconInfo.iconScale, halfWidth, halfHeight);
+ canvas.translate(iconInfo.iconTranslationX, iconInfo.iconTranslationY);
+ canvas.rotate(angle, halfWidth, halfHeight);
+ if (iconInfo.colorFilter != null) {
+ Paint p = null;
+ if (icon instanceof BitmapDrawable) {
+ p = ((BitmapDrawable) icon).getPaint();
+ } else if (icon instanceof PaintDrawable) {
+ p = ((PaintDrawable) icon).getPaint();
+ }
+ if (p != null) p.setColorFilter(new ColorMatrixColorFilter(iconInfo.colorFilter));
+ }
+ icon.draw(canvas);
+ canvas.restore();
+
+ // Mask off the original if iconMask is not null
+ if (iconInfo.iconMask != 0) {
+ Drawable mask = res.getDrawable(iconInfo.iconMask);
+ if (mask != null) {
+ mask.setBounds(icon.getBounds());
+ ((BitmapDrawable) mask).getPaint().setXfermode(
+ new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
+ mask.draw(canvas);
+ }
+ }
+ // Draw the iconBacks if not null and then the original (scaled and masked) icon on top
+ if (iconBack != 0) {
+ Drawable back = res.getDrawable(iconBack);
+ if (back != null) {
+ back.setBounds(icon.getBounds());
+ Paint paint = ((BitmapDrawable) back).getPaint();
+ paint.setXfermode(
+ new PorterDuffXfermode(PorterDuff.Mode.DST_OVER));
+ if (backTintColor != 0) {
+ paint.setColorFilter(new PorterDuffColorFilter(backTintColor,
+ PorterDuff.Mode.MULTIPLY));
+ }
+ back.draw(canvas);
+ }
+ }
+ // Finally draw the foreground if one was supplied
+ if (iconInfo.iconUpon != 0) {
+ Drawable upon = res.getDrawable(iconInfo.iconUpon);
+ if (upon != null) {
+ upon.setBounds(icon.getBounds());
+ upon.draw(canvas);
+ }
+ }
+ icon.setBounds(oldBounds);
+ bitmap.setDensity(canvas.getDensity());
+
+ return bitmap;
+ }
+
+ private static boolean cacheComposedIcon(Bitmap bmp, String path) {
+ try {
+ return sThemeService.cacheComposedIcon(bmp, path);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Unable to cache icon.", e);
+ }
+
+ return false;
+ }
+
+ private static String getCachedIconPath(String pkgName, int resId, int density) {
+ return String.format("%s/%s", ThemeUtils.SYSTEM_THEME_ICON_CACHE_DIR,
+ getCachedIconName(pkgName, resId, density));
+ }
+
+ private static String getCachedIconName(String pkgName, int resId, int density) {
+ return String.format("%s_%08x_%d.png", pkgName, resId, density);
+ }
+ }
+
+ public static class ColorFilterUtils {
+ private static final String TAG_FILTER = "filter";
+ private static final String FILTER_HUE = "hue";
+ private static final String FILTER_SATURATION = "saturation";
+ private static final String FILTER_INVERT = "invert";
+ private static final String FILTER_BRIGHTNESS = "brightness";
+ private static final String FILTER_CONTRAST = "contrast";
+ private static final String FILTER_ALPHA = "alpha";
+ private static final String FILTER_TINT = "tint";
+
+ private static final int MIN_HUE = -180;
+ private static final int MAX_HUE = 180;
+ private static final int MIN_SATURATION = 0;
+ private static final int MAX_SATURATION = 200;
+ private static final int MIN_BRIGHTNESS = 0;
+ private static final int MAX_BRIGHTNESS = 200;
+ private static final int MIN_CONTRAST = -100;
+ private static final int MAX_CONTRAST = 100;
+ private static final int MIN_ALPHA = 0;
+ private static final int MAX_ALPHA = 100;
+
+ public static boolean parseIconFilter(XmlPullParser parser, Builder builder)
+ throws IOException, XmlPullParserException {
+ String tag = parser.getName();
+ if (!TAG_FILTER.equals(tag)) return false;
+
+ int attrCount = parser.getAttributeCount();
+ String attrName;
+ String attr = null;
+ int intValue;
+ while (attrCount-- > 0) {
+ attrName = parser.getAttributeName(attrCount);
+ if (attrName.equals("name")) {
+ attr = parser.getAttributeValue(attrCount);
+ }
+ }
+ String content = parser.nextText();
+ if (attr != null && content != null && content.length() > 0) {
+ content = content.trim();
+ if (FILTER_HUE.equalsIgnoreCase(attr)) {
+ intValue = clampValue(getInt(content, 0),MIN_HUE, MAX_HUE);
+ builder.hue(intValue);
+ } else if (FILTER_SATURATION.equalsIgnoreCase(attr)) {
+ intValue = clampValue(getInt(content, 100),
+ MIN_SATURATION, MAX_SATURATION);
+ builder.saturate(intValue);
+ } else if (FILTER_INVERT.equalsIgnoreCase(attr)) {
+ if ("true".equalsIgnoreCase(content)) {
+ builder.invertColors();
+ }
+ } else if (FILTER_BRIGHTNESS.equalsIgnoreCase(attr)) {
+ intValue = clampValue(getInt(content, 100),
+ MIN_BRIGHTNESS, MAX_BRIGHTNESS);
+ builder.brightness(intValue);
+ } else if (FILTER_CONTRAST.equalsIgnoreCase(attr)) {
+ intValue = clampValue(getInt(content, 0),
+ MIN_CONTRAST, MAX_CONTRAST);
+ builder.contrast(intValue);
+ } else if (FILTER_ALPHA.equalsIgnoreCase(attr)) {
+ intValue = clampValue(getInt(content, 100), MIN_ALPHA, MAX_ALPHA);
+ builder.alpha(intValue);
+ } else if (FILTER_TINT.equalsIgnoreCase(attr)) {
+ try {
+ intValue = Color.parseColor(content);
+ builder.tint(intValue);
+ } catch (IllegalArgumentException e) {
+ Log.w(TAG, "Cannot apply tint, invalid argument: " + content);
+ }
+ }
+ }
+ return true;
+ }
+
+ private static int getInt(String value, int defaultValue) {
+ try {
+ return Integer.valueOf(value);
+ } catch (NumberFormatException e) {
+ return defaultValue;
+ }
+ }
+
+ private static int clampValue(int value, int min, int max) {
+ return Math.min(max, Math.max(min, value));
+ }
+
+ /**
+ * See the following links for reference
+ * http://groups.google.com/group/android-developers/browse_thread/thread/9e215c83c3819953
+ * http://gskinner.com/blog/archives/2007/12/colormatrix_cla.html
+ * @param value
+ */
+ public static ColorMatrix adjustHue(float value) {
+ ColorMatrix cm = new ColorMatrix();
+ value = value / 180 * (float) Math.PI;
+ if (value != 0) {
+ float cosVal = (float) Math.cos(value);
+ float sinVal = (float) Math.sin(value);
+ float lumR = 0.213f;
+ float lumG = 0.715f;
+ float lumB = 0.072f;
+ float[] mat = new float[]{
+ lumR + cosVal * (1 - lumR) + sinVal * (-lumR),
+ lumG + cosVal * (-lumG) + sinVal * (-lumG),
+ lumB + cosVal * (-lumB) + sinVal * (1 - lumB), 0, 0,
+ lumR + cosVal * (-lumR) + sinVal * (0.143f),
+ lumG + cosVal * (1 - lumG) + sinVal * (0.140f),
+ lumB + cosVal * (-lumB) + sinVal * (-0.283f), 0, 0,
+ lumR + cosVal * (-lumR) + sinVal * (-(1 - lumR)),
+ lumG + cosVal * (-lumG) + sinVal * (lumG),
+ lumB + cosVal * (1 - lumB) + sinVal * (lumB), 0, 0,
+ 0, 0, 0, 1, 0,
+ 0, 0, 0, 0, 1};
+ cm.set(mat);
+ }
+ return cm;
+ }
+
+ public static ColorMatrix adjustSaturation(float saturation) {
+ saturation = saturation / 100;
+ ColorMatrix cm = new ColorMatrix();
+ cm.setSaturation(saturation);
+
+ return cm;
+ }
+
+ public static ColorMatrix invertColors() {
+ float[] matrix = {
+ -1, 0, 0, 0, 255, //red
+ 0, -1, 0, 0, 255, //green
+ 0, 0, -1, 0, 255, //blue
+ 0, 0, 0, 1, 0 //alpha
+ };
+
+ return new ColorMatrix(matrix);
+ }
+
+ public static ColorMatrix adjustBrightness(float brightness) {
+ brightness = brightness / 100;
+ ColorMatrix cm = new ColorMatrix();
+ cm.setScale(brightness, brightness, brightness, 1);
+
+ return cm;
+ }
+
+ public static ColorMatrix adjustContrast(float contrast) {
+ contrast = contrast / 100 + 1;
+ float o = (-0.5f * contrast + 0.5f) * 255;
+ float[] matrix = {
+ contrast, 0, 0, 0, o, //red
+ 0, contrast, 0, 0, o, //green
+ 0, 0, contrast, 0, o, //blue
+ 0, 0, 0, 1, 0 //alpha
+ };
+
+ return new ColorMatrix(matrix);
+ }
+
+ public static ColorMatrix adjustAlpha(float alpha) {
+ alpha = alpha / 100;
+ ColorMatrix cm = new ColorMatrix();
+ cm.setScale(1, 1, 1, alpha);
+
+ return cm;
+ }
+
+ public static ColorMatrix applyTint(int color) {
+ float alpha = Color.alpha(color) / 255f;
+ float red = Color.red(color) * alpha;
+ float green = Color.green(color) * alpha;
+ float blue = Color.blue(color) * alpha;
+
+ float[] matrix = {
+ 1, 0, 0, 0, red, //red
+ 0, 1, 0, 0, green, //green
+ 0, 0, 1, 0, blue, //blue
+ 0, 0, 0, 1, 0 //alpha
+ };
+
+ return new ColorMatrix(matrix);
+ }
+
+ public static class Builder {
+ private List<ColorMatrix> mMatrixList;
+
+ public Builder() {
+ mMatrixList = new ArrayList<ColorMatrix>();
+ }
+
+ public Builder hue(float value) {
+ mMatrixList.add(adjustHue(value));
+ return this;
+ }
+
+ public Builder saturate(float saturation) {
+ mMatrixList.add(adjustSaturation(saturation));
+ return this;
+ }
+
+ public Builder brightness(float brightness) {
+ mMatrixList.add(adjustBrightness(brightness));
+ return this;
+ }
+
+ public Builder contrast(float contrast) {
+ mMatrixList.add(adjustContrast(contrast));
+ return this;
+ }
+
+ public Builder alpha(float alpha) {
+ mMatrixList.add(adjustAlpha(alpha));
+ return this;
+ }
+
+ public Builder invertColors() {
+ mMatrixList.add(ColorFilterUtils.invertColors());
+ return this;
+ }
+
+ public Builder tint(int color) {
+ mMatrixList.add(applyTint(color));
+ return this;
+ }
+
+ public ColorMatrix build() {
+ if (mMatrixList == null || mMatrixList.size() == 0) return null;
+
+ ColorMatrix colorMatrix = new ColorMatrix();
+ for (ColorMatrix cm : mMatrixList) {
+ colorMatrix.postConcat(cm);
+ }
+ return colorMatrix;
+ }
+ }
+ }
+}
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index 69b8b95..cddcd9f 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -374,6 +374,7 @@ public class Instrumentation {
* @see Context#startActivity
*/
public Activity startActivitySync(Intent intent) {
+ android.util.SeempLog.record_str(376, intent.toString());
validateNotAppThread();
synchronized (mSync) {
@@ -1481,6 +1482,7 @@ public class Instrumentation {
public ActivityResult execStartActivity(
Context who, IBinder contextThread, IBinder token, Activity target,
Intent intent, int requestCode, Bundle options) {
+ android.util.SeempLog.record_str(377, intent.toString());
IApplicationThread whoThread = (IApplicationThread) contextThread;
Uri referrer = target != null ? target.onProvideReferrer() : null;
if (referrer != null) {
@@ -1541,6 +1543,7 @@ public class Instrumentation {
public void execStartActivitiesAsUser(Context who, IBinder contextThread,
IBinder token, Activity target, Intent[] intents, Bundle options,
int userId) {
+ android.util.SeempLog.record_str(378, intents.toString());
IApplicationThread whoThread = (IApplicationThread) contextThread;
if (mActivityMonitors != null) {
synchronized (mSync) {
@@ -1604,6 +1607,7 @@ public class Instrumentation {
public ActivityResult execStartActivity(
Context who, IBinder contextThread, IBinder token, String target,
Intent intent, int requestCode, Bundle options) {
+ android.util.SeempLog.record_str(377, intent.toString());
IApplicationThread whoThread = (IApplicationThread) contextThread;
if (mActivityMonitors != null) {
synchronized (mSync) {
@@ -1664,6 +1668,7 @@ public class Instrumentation {
public ActivityResult execStartActivity(
Context who, IBinder contextThread, IBinder token, Activity target,
Intent intent, int requestCode, Bundle options, UserHandle user) {
+ android.util.SeempLog.record_str(377, intent.toString());
IApplicationThread whoThread = (IApplicationThread) contextThread;
if (mActivityMonitors != null) {
synchronized (mSync) {
@@ -1703,6 +1708,7 @@ public class Instrumentation {
Context who, IBinder contextThread, IBinder token, Activity target,
Intent intent, int requestCode, Bundle options, boolean ignoreTargetSecurity,
int userId) {
+ android.util.SeempLog.record_str(379, intent.toString());
IApplicationThread whoThread = (IApplicationThread) contextThread;
if (mActivityMonitors != null) {
synchronized (mSync) {
@@ -1741,6 +1747,7 @@ public class Instrumentation {
public void execStartActivityFromAppTask(
Context who, IBinder contextThread, IAppTask appTask,
Intent intent, Bundle options) {
+ android.util.SeempLog.record_str(380, intent.toString());
IApplicationThread whoThread = (IApplicationThread) contextThread;
if (mActivityMonitors != null) {
synchronized (mSync) {
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index c2bf28a..76e55b7 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -546,7 +546,8 @@ public final class LoadedApk {
public Resources getResources(ActivityThread mainThread) {
if (mResources == null) {
mResources = mainThread.getTopLevelResources(mResDir, mSplitResDirs, mOverlayDirs,
- mApplicationInfo.sharedLibraryFiles, Display.DEFAULT_DISPLAY, null, this);
+ mApplicationInfo.sharedLibraryFiles, Display.DEFAULT_DISPLAY, null, this,
+ mainThread.getSystemContext(), mPackageName);
}
return mResources;
}
@@ -601,7 +602,7 @@ public final class LoadedApk {
final int N = packageIdentifiers.size();
for (int i = 0; i < N; i++) {
final int id = packageIdentifiers.keyAt(i);
- if (id == 0x01 || id == 0x7f) {
+ if (id == 0x01 || id == 0x7f || id == 0x3f) {
continue;
}
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 6a4f6a1..cd07c9c 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -895,6 +895,13 @@ public class Notification implements Parcelable
private Icon mLargeIcon;
/**
+ * Used by light picker in Settings to force
+ * notification lights on when screen is on
+ * @hide
+ */
+ public static final String EXTRA_FORCE_SHOW_LIGHTS = "android.forceShowLights";
+
+ /**
* Structure to encapsulate a named action that can be shown as part of this notification.
* It must include an icon, a label, and a {@link PendingIntent} to be fired when the action is
* selected by the user.
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/ResourcesManager.java b/core/java/android/app/ResourcesManager.java
index 2117597..7492cd0 100644
--- a/core/java/android/app/ResourcesManager.java
+++ b/core/java/android/app/ResourcesManager.java
@@ -18,22 +18,38 @@ package android.app;
import static android.app.ActivityThread.DEBUG_CONFIGURATION;
+import android.content.Context;
import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.IPackageManager;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageItemInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ThemeUtils;
import android.content.res.AssetManager;
import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
+import android.content.res.ThemeConfig;
import android.content.res.Resources;
import android.content.res.ResourcesKey;
+import android.graphics.Typeface;
import android.hardware.display.DisplayManagerGlobal;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.UserHandle;
+import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.Pair;
import android.util.Slog;
+import android.util.SparseArray;
import android.view.Display;
import android.view.DisplayAdjustments;
import java.lang.ref.WeakReference;
+import java.util.List;
import java.util.Locale;
/** @hide */
@@ -48,9 +64,16 @@ public class ResourcesManager {
new ArrayMap<>();
CompatibilityInfo mResCompatibilityInfo;
+ static IPackageManager sPackageManager;
Configuration mResConfiguration;
+ /**
+ * Number of default assets attached to a Resource object's AssetManager
+ * This currently includes framework and cmsdk resources
+ */
+ private static final int NUM_DEFAULT_ASSETS = 2;
+
public static ResourcesManager getInstance() {
synchronized (ResourcesManager.class) {
if (sResourcesManager == null) {
@@ -156,12 +179,15 @@ public class ResourcesManager {
* @param compatInfo the compatibility info. Must not be null.
*/
Resources getTopLevelResources(String resDir, String[] splitResDirs,
- String[] overlayDirs, String[] libDirs, int displayId,
- Configuration overrideConfiguration, CompatibilityInfo compatInfo) {
+ String[] overlayDirs, String[] libDirs, int displayId, String packageName,
+ Configuration overrideConfiguration, CompatibilityInfo compatInfo, Context context,
+ boolean isThemeable) {
final float scale = compatInfo.applicationScale;
+ ThemeConfig themeConfig = getThemeConfig();
Configuration overrideConfigCopy = (overrideConfiguration != null)
? new Configuration(overrideConfiguration) : null;
- ResourcesKey key = new ResourcesKey(resDir, displayId, overrideConfigCopy, scale);
+ ResourcesKey key = new ResourcesKey(resDir, displayId, overrideConfiguration, scale,
+ isThemeable, getThemeConfig());
Resources r;
synchronized (this) {
// Resources is app scale dependent.
@@ -184,6 +210,8 @@ public class ResourcesManager {
//}
AssetManager assets = new AssetManager();
+ assets.setAppName(packageName);
+ assets.setThemeSupport(isThemeable);
// resDir can be null if the 'android' package is creating a new Resources object.
// This is fine, since each AssetManager automatically loads the 'android' package
// already.
@@ -203,7 +231,7 @@ public class ResourcesManager {
if (overlayDirs != null) {
for (String idmapPath : overlayDirs) {
- assets.addOverlayPath(idmapPath);
+ assets.addOverlayPath(idmapPath, null, null, null, null);
}
}
@@ -213,7 +241,7 @@ public class ResourcesManager {
// Avoid opening files we know do not have resources,
// like code-only .jar files.
if (assets.addAssetPath(libDir) == 0) {
- Log.w(TAG, "Asset path '" + libDir +
+ Slog.w(TAG, "Asset path '" + libDir +
"' does not exist or contains no resources.");
}
}
@@ -237,10 +265,38 @@ public class ResourcesManager {
} else {
config = getConfiguration();
}
+
+ boolean iconsAttached = false;
+ /* Attach theme information to the resulting AssetManager when appropriate. */
+ if (config != null && !context.getPackageManager().isSafeMode()) {
+ if (themeConfig == null) {
+ try {
+ themeConfig = ThemeConfig.getBootTheme(context.getContentResolver());
+ } catch (Exception e) {
+ Slog.d(TAG, "ThemeConfig.getBootTheme failed, falling back to system theme", e);
+ themeConfig = ThemeConfig.getSystemTheme();
+ }
+ }
+
+ if (isThemeable) {
+ if (themeConfig != null) {
+ attachThemeAssets(assets, themeConfig);
+ attachCommonAssets(assets, themeConfig);
+ iconsAttached = attachIconAssets(assets, themeConfig);
+ }
+ } else if (themeConfig != null &&
+ !ThemeConfig.SYSTEM_DEFAULT.equals(themeConfig.getFontPkgName())) {
+ // use system fonts if not themeable and a theme font is currently in use
+ Typeface.recreateDefaults(true);
+ }
+ }
+
r = new Resources(assets, dm, config, compatInfo);
+ if (iconsAttached) setActivityIcons(r);
if (DEBUG) Slog.i(TAG, "Created app resources " + resDir + " " + r + ": "
+ r.getConfiguration() + " appScale=" + r.getCompatibilityInfo().applicationScale);
+
synchronized (this) {
WeakReference<Resources> wr = mActiveResources.get(key);
Resources existing = wr != null ? wr.get() : null;
@@ -258,6 +314,152 @@ public class ResourcesManager {
}
}
+ /**
+ * Creates the top level Resources for applications with the given compatibility info.
+ *
+ * @param resDir the resource directory.
+ * @param compatInfo the compability info. Must not be null.
+ *
+ * @hide
+ */
+ public Resources getTopLevelThemedResources(String resDir, int displayId, String packageName,
+ String themePackageName, CompatibilityInfo compatInfo, boolean isThemeable) {
+ Resources r;
+
+ ThemeConfig.Builder builder = new ThemeConfig.Builder();
+ builder.defaultOverlay(themePackageName);
+ builder.defaultIcon(themePackageName);
+ builder.defaultFont(themePackageName);
+ ThemeConfig themeConfig = builder.build();
+
+ ResourcesKey key = new ResourcesKey(resDir, displayId, null, compatInfo.applicationScale,
+ isThemeable, themeConfig);
+
+ synchronized (this) {
+ WeakReference<Resources> wr = mActiveResources.get(key);
+ r = wr != null ? wr.get() : null;
+ if (r != null && r.getAssets().isUpToDate()) {
+ if (false) {
+ Slog.w(TAG, "Returning cached resources " + r + " " + resDir
+ + ": appScale=" + r.getCompatibilityInfo().applicationScale);
+ }
+ return r;
+ }
+ }
+
+ AssetManager assets = new AssetManager();
+ assets.setAppName(packageName);
+ assets.setThemeSupport(isThemeable);
+ if (assets.addAssetPath(resDir) == 0) {
+ return null;
+ }
+
+ //Slog.i(TAG, "Resource: key=" + key + ", display metrics=" + metrics);
+ DisplayMetrics dm = getDisplayMetricsLocked(displayId);
+ Configuration config;
+ boolean isDefaultDisplay = (displayId == Display.DEFAULT_DISPLAY);
+ final boolean hasOverrideConfig = key.hasOverrideConfiguration();
+ if (!isDefaultDisplay || hasOverrideConfig) {
+ config = new Configuration(getConfiguration());
+ if (!isDefaultDisplay) {
+ applyNonDefaultDisplayMetricsToConfigurationLocked(dm, config);
+ }
+ if (hasOverrideConfig) {
+ config.updateFrom(key.mOverrideConfiguration);
+ }
+ } else {
+ config = getConfiguration();
+ }
+
+ boolean iconsAttached = false;
+ if (isThemeable) {
+ /* Attach theme information to the resulting AssetManager when appropriate. */
+ attachThemeAssets(assets, themeConfig);
+ attachCommonAssets(assets, themeConfig);
+ iconsAttached = attachIconAssets(assets, themeConfig);
+ }
+ r = new Resources(assets, dm, config, compatInfo);
+ if (iconsAttached) setActivityIcons(r);
+
+ if (false) {
+ Slog.i(TAG, "Created THEMED app resources " + resDir + " " + r + ": "
+ + r.getConfiguration() + " appScale="
+ + r.getCompatibilityInfo().applicationScale);
+ }
+
+ synchronized (this) {
+ WeakReference<Resources> wr = mActiveResources.get(key);
+ Resources existing = wr != null ? wr.get() : null;
+ if (existing != null && existing.getAssets().isUpToDate()) {
+ // Someone else already created the resources while we were
+ // unlocked; go ahead and use theirs.
+ r.getAssets().close();
+ return existing;
+ }
+
+ // XXX need to remove entries when weak references go away
+ mActiveResources.put(key, new WeakReference<Resources>(r));
+ return r;
+ }
+ }
+
+ /**
+ * Creates a map between an activity & app's icon ids to its component info. This map
+ * is then stored in the resource object.
+ * When resource.getDrawable(id) is called it will check this mapping and replace
+ * the id with the themed resource id if one is available
+ * @param r
+ */
+ private void setActivityIcons(Resources r) {
+ SparseArray<PackageItemInfo> iconResources = new SparseArray<PackageItemInfo>();
+ String pkgName = r.getAssets().getAppName();
+ PackageInfo pkgInfo = null;
+ ApplicationInfo appInfo = null;
+
+ try {
+ pkgInfo = getPackageManager().getPackageInfo(pkgName, PackageManager.GET_ACTIVITIES,
+ UserHandle.getCallingUserId());
+ } catch (RemoteException e1) {
+ Slog.e(TAG, "Unable to get pkg " + pkgName, e1);
+ return;
+ }
+
+ final ThemeConfig themeConfig = r.getConfiguration().themeConfig;
+ if (pkgName != null && themeConfig != null &&
+ pkgName.equals(themeConfig.getIconPackPkgName())) {
+ return;
+ }
+
+ //Map application icon
+ if (pkgInfo != null && pkgInfo.applicationInfo != null) {
+ appInfo = pkgInfo.applicationInfo;
+ if (appInfo.themedIcon != 0 || iconResources.get(appInfo.icon) == null) {
+ iconResources.put(appInfo.icon, appInfo);
+ }
+ }
+
+ //Map activity icons.
+ if (pkgInfo != null && pkgInfo.activities != null) {
+ for (ActivityInfo ai : pkgInfo.activities) {
+ if (ai.icon != 0 && (ai.themedIcon != 0 || iconResources.get(ai.icon) == null)) {
+ iconResources.put(ai.icon, ai);
+ } else if (appInfo != null && appInfo.icon != 0 &&
+ (ai.themedIcon != 0 || iconResources.get(appInfo.icon) == null)) {
+ iconResources.put(appInfo.icon, ai);
+ }
+ }
+ }
+
+ r.setIconResources(iconResources);
+ final IPackageManager pm = getPackageManager();
+ try {
+ ComposedIconInfo iconInfo = pm.getComposedIconInfo();
+ r.setComposedIconInfo(iconInfo);
+ } catch (Exception e) {
+ Slog.wtf(TAG, "Failed to retrieve ComposedIconInfo", e);
+ }
+ }
+
final boolean applyConfigurationToResourcesLocked(Configuration config,
CompatibilityInfo compat) {
if (mResConfiguration == null) {
@@ -303,6 +505,22 @@ public class ResourcesManager {
boolean isDefaultDisplay = (displayId == Display.DEFAULT_DISPLAY);
DisplayMetrics dm = defaultDisplayMetrics;
final boolean hasOverrideConfiguration = key.hasOverrideConfiguration();
+ boolean themeChanged = (changes & ActivityInfo.CONFIG_THEME_RESOURCE) != 0;
+ if (themeChanged) {
+ AssetManager am = r.getAssets();
+ if (am.hasThemeSupport()) {
+ r.setIconResources(null);
+ r.setComposedIconInfo(null);
+ detachThemeAssets(am);
+ if (config.themeConfig != null) {
+ attachThemeAssets(am, config.themeConfig);
+ attachCommonAssets(am, config.themeConfig);
+ if (attachIconAssets(am, config.themeConfig)) {
+ setActivityIcons(r);
+ }
+ }
+ }
+ }
if (!isDefaultDisplay || hasOverrideConfiguration) {
if (tmpConfig == null) {
tmpConfig = new Configuration();
@@ -319,6 +537,9 @@ public class ResourcesManager {
} else {
r.updateConfiguration(config, dm, compat);
}
+ if (themeChanged) {
+ r.updateStringCache();
+ }
//Slog.i(TAG, "Updated app resources " + v.getKey()
// + " " + r + ": " + r.getConfiguration());
} else {
@@ -330,4 +551,240 @@ public class ResourcesManager {
return changes != 0;
}
+ public static IPackageManager getPackageManager() {
+ if (sPackageManager != null) {
+ return sPackageManager;
+ }
+ IBinder b = ServiceManager.getService("package");
+ sPackageManager = IPackageManager.Stub.asInterface(b);
+ return sPackageManager;
+ }
+
+
+ /**
+ * Attach the necessary theme asset paths and meta information to convert an
+ * AssetManager to being globally "theme-aware".
+ *
+ * @param assets
+ * @param theme
+ * @return true if the AssetManager is now theme-aware; false otherwise.
+ * This can fail, for example, if the theme package has been been
+ * removed and the theme manager has yet to revert formally back to
+ * the framework default.
+ */
+ private boolean attachThemeAssets(AssetManager assets, ThemeConfig theme) {
+ PackageInfo piTheme = null;
+ PackageInfo piTarget = null;
+ PackageInfo piAndroid = null;
+
+ // Some apps run in process of another app (eg keyguard/systemUI) so we must get the
+ // package name from the res tables. The 0th base package name will be the android group.
+ // The 1st base package name will be the app group if one is attached. Check if it is there
+ // first or else the system will crash!
+ String basePackageName = null;
+ String resourcePackageName = null;
+ int count = assets.getBasePackageCount();
+ if (count > NUM_DEFAULT_ASSETS) {
+ basePackageName = assets.getBasePackageName(NUM_DEFAULT_ASSETS);
+ resourcePackageName = assets.getBaseResourcePackageName(NUM_DEFAULT_ASSETS);
+ } else if (count == NUM_DEFAULT_ASSETS) {
+ basePackageName = assets.getBasePackageName(0);
+ } else {
+ return false;
+ }
+
+ try {
+ piTheme = getPackageManager().getPackageInfo(
+ theme.getOverlayPkgNameForApp(basePackageName), 0,
+ UserHandle.getCallingUserId());
+ piTarget = getPackageManager().getPackageInfo(
+ basePackageName, 0, UserHandle.getCallingUserId());
+
+ // Handle special case where a system app (ex trebuchet) may have had its pkg name
+ // renamed during an upgrade. basePackageName would be the manifest value which will
+ // fail on getPackageInfo(). resource pkg is assumed to have the original name
+ if (piTarget == null && resourcePackageName != null) {
+ piTarget = getPackageManager().getPackageInfo(resourcePackageName,
+ 0, UserHandle.getCallingUserId());
+ }
+ piAndroid = getPackageManager().getPackageInfo("android", 0,
+ UserHandle.getCallingUserId());
+ } catch (RemoteException e) {
+ }
+
+ if (piTheme == null || piTheme.applicationInfo == null ||
+ piTarget == null || piTarget.applicationInfo == null ||
+ piAndroid == null || piAndroid.applicationInfo == null ||
+ piTheme.mOverlayTargets == null) {
+ return false;
+ }
+
+ String themePackageName = piTheme.packageName;
+ String themePath = piTheme.applicationInfo.publicSourceDir;
+ if (!piTarget.isThemeApk && piTheme.mOverlayTargets.contains(basePackageName)) {
+ String targetPackagePath = piTarget.applicationInfo.sourceDir;
+ String prefixPath = ThemeUtils.getOverlayPathToTarget(basePackageName);
+
+ String resCachePath = ThemeUtils.getTargetCacheDir(piTarget.packageName, piTheme);
+ String resApkPath = resCachePath + "/resources.apk";
+ String idmapPath = ThemeUtils.getIdmapPath(piTarget.packageName, piTheme.packageName);
+ int cookie = assets.addOverlayPath(idmapPath, themePath, resApkPath,
+ targetPackagePath, prefixPath);
+
+ if (cookie != 0) {
+ assets.setThemePackageName(themePackageName);
+ assets.addThemeCookie(cookie);
+ }
+ }
+
+ if (!piTarget.isThemeApk && !"android".equals(basePackageName) &&
+ piTheme.mOverlayTargets.contains("android")) {
+ String resCachePath= ThemeUtils.getTargetCacheDir(piAndroid.packageName, piTheme);
+ String prefixPath = ThemeUtils.getOverlayPathToTarget(piAndroid.packageName);
+ String targetPackagePath = piAndroid.applicationInfo.publicSourceDir;
+ String resApkPath = resCachePath + "/resources.apk";
+ String idmapPath = ThemeUtils.getIdmapPath("android", piTheme.packageName);
+ int cookie = assets.addOverlayPath(idmapPath, themePath,
+ resApkPath, targetPackagePath, prefixPath);
+ if (cookie != 0) {
+ assets.setThemePackageName(themePackageName);
+ assets.addThemeCookie(cookie);
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Attach the necessary icon asset paths. Icon assets should be in a different
+ * namespace than the standard 0x7F.
+ *
+ * @param assets
+ * @param theme
+ * @return true if succes, false otherwise
+ */
+ private boolean attachIconAssets(AssetManager assets, ThemeConfig theme) {
+ PackageInfo piIcon = null;
+ try {
+ piIcon = getPackageManager().getPackageInfo(theme.getIconPackPkgName(), 0,
+ UserHandle.getCallingUserId());
+ } catch (RemoteException e) {
+ }
+
+ if (piIcon == null || piIcon.applicationInfo == null) {
+ return false;
+ }
+
+ String iconPkg = theme.getIconPackPkgName();
+ if (iconPkg != null && !iconPkg.isEmpty()) {
+ String themeIconPath = piIcon.applicationInfo.publicSourceDir;
+ String prefixPath = ThemeUtils.ICONS_PATH;
+ String iconDir = ThemeUtils.getIconPackDir(iconPkg);
+ String resTablePath = iconDir + "/resources.arsc";
+ String resApkPath = iconDir + "/resources.apk";
+
+ // Legacy Icon packs have everything in their APK
+ if (piIcon.isLegacyIconPackApk) {
+ prefixPath = "";
+ resApkPath = "";
+ resTablePath = "";
+ }
+
+ int cookie = assets.addIconPath(themeIconPath, resApkPath, prefixPath,
+ Resources.THEME_ICON_PKG_ID);
+ if (cookie != 0) {
+ assets.setIconPackCookie(cookie);
+ assets.setIconPackageName(iconPkg);
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Attach the necessary common asset paths. Common assets should be in a different
+ * namespace than the standard 0x7F.
+ *
+ * @param assets
+ * @param theme
+ * @return true if succes, false otherwise
+ */
+ private boolean attachCommonAssets(AssetManager assets, ThemeConfig theme) {
+ // Some apps run in process of another app (eg keyguard/systemUI) so we must get the
+ // package name from the res tables. The 0th base package name will be the android group.
+ // The 1st base package name will be the app group if one is attached. Check if it is there
+ // first or else the system will crash!
+ String basePackageName;
+ int count = assets.getBasePackageCount();
+ if (count > NUM_DEFAULT_ASSETS) {
+ basePackageName = assets.getBasePackageName(NUM_DEFAULT_ASSETS);
+ } else if (count == NUM_DEFAULT_ASSETS) {
+ basePackageName = assets.getBasePackageName(0);
+ } else {
+ return false;
+ }
+
+ PackageInfo piTheme = null;
+ try {
+ piTheme = getPackageManager().getPackageInfo(
+ theme.getOverlayPkgNameForApp(basePackageName), 0,
+ UserHandle.getCallingUserId());
+ } catch (RemoteException e) {
+ }
+
+ if (piTheme == null || piTheme.applicationInfo == null) {
+ return false;
+ }
+
+ String themePackageName =
+ ThemeUtils.getCommonPackageName(piTheme.applicationInfo.packageName);
+ if (themePackageName != null && !themePackageName.isEmpty()) {
+ String themePath = piTheme.applicationInfo.publicSourceDir;
+ String prefixPath = ThemeUtils.COMMON_RES_PATH;
+ String resCachePath =
+ ThemeUtils.getTargetCacheDir(ThemeUtils.COMMON_RES_TARGET, piTheme);
+ String resApkPath = resCachePath + "/resources.apk";
+ int cookie = assets.addCommonOverlayPath(themePath, resApkPath,
+ prefixPath);
+ if (cookie != 0) {
+ assets.setCommonResCookie(cookie);
+ assets.setCommonResPackageName(themePackageName);
+ }
+ }
+
+ return true;
+ }
+
+ private void detachThemeAssets(AssetManager assets) {
+ String themePackageName = assets.getThemePackageName();
+ String iconPackageName = assets.getIconPackageName();
+ String commonResPackageName = assets.getCommonResPackageName();
+
+ //Remove Icon pack if it exists
+ if (!TextUtils.isEmpty(iconPackageName) && assets.getIconPackCookie() > 0) {
+ assets.removeOverlayPath(iconPackageName, assets.getIconPackCookie());
+ assets.setIconPackageName(null);
+ assets.setIconPackCookie(0);
+ }
+ //Remove common resources if it exists
+ if (!TextUtils.isEmpty(commonResPackageName) && assets.getCommonResCookie() > 0) {
+ assets.removeOverlayPath(commonResPackageName, assets.getCommonResCookie());
+ assets.setCommonResPackageName(null);
+ assets.setCommonResCookie(0);
+ }
+ final List<Integer> themeCookies = assets.getThemeCookies();
+ if (!TextUtils.isEmpty(themePackageName) && !themeCookies.isEmpty()) {
+ // remove overlays in reverse order
+ for (int i = themeCookies.size() - 1; i >= 0; i--) {
+ assets.removeOverlayPath(themePackageName, themeCookies.get(i));
+ }
+ }
+ assets.getThemeCookies().clear();
+ assets.setThemePackageName(null);
+ }
+
+ private ThemeConfig getThemeConfig() {
+ final Configuration config = getConfiguration();
+ return config != null ? config.themeConfig : null;
+ }
}
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 3d264c6..08f4efd 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -37,7 +37,9 @@ import android.content.IRestrictionsManager;
import android.content.RestrictionsManager;
import android.content.pm.ILauncherApps;
import android.content.pm.LauncherApps;
+import android.content.res.IThemeService;
import android.content.res.Resources;
+import android.content.res.ThemeManager;
import android.hardware.ConsumerIrManager;
import android.hardware.ISerialManager;
import android.hardware.SensorManager;
@@ -704,6 +706,15 @@ final class SystemServiceRegistry {
public RadioManager createService(ContextImpl ctx) {
return new RadioManager(ctx);
}});
+
+ registerService(Context.THEME_SERVICE, ThemeManager.class,
+ new CachedServiceFetcher<ThemeManager>() {
+ public ThemeManager createService(ContextImpl ctx) {
+ IBinder b = ServiceManager.getService(Context.THEME_SERVICE);
+ IThemeService service = IThemeService.Stub.asInterface(b);
+ return new ThemeManager(ctx.getOuterContext(),
+ service);
+ }});
}
/**
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index 22e79b6..045ee39 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -33,6 +33,7 @@ import android.graphics.ColorFilter;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PixelFormat;
+import android.graphics.Point;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
@@ -230,9 +231,10 @@ public class WallpaperManager {
private IWallpaperManager mService;
private Bitmap mWallpaper;
private Bitmap mDefaultWallpaper;
+ private Bitmap mKeyguardWallpaper;
private static final int MSG_CLEAR_WALLPAPER = 1;
-
+
Globals(Looper looper) {
IBinder b = ServiceManager.getService(Context.WALLPAPER_SERVICE);
mService = IWallpaperManager.Stub.asInterface(b);
@@ -250,6 +252,12 @@ public class WallpaperManager {
}
}
+ public void onKeyguardWallpaperChanged() {
+ synchronized (this) {
+ mKeyguardWallpaper = null;
+ }
+ }
+
public Bitmap peekWallpaperBitmap(Context context, boolean returnDefault) {
synchronized (this) {
if (mService != null) {
@@ -285,6 +293,23 @@ public class WallpaperManager {
}
}
+ /**
+ * @hide
+ */
+ public Bitmap peekKeyguardWallpaperBitmap(Context context) {
+ synchronized (this) {
+ if (mKeyguardWallpaper != null) {
+ return mKeyguardWallpaper;
+ }
+ try {
+ mKeyguardWallpaper = getCurrentKeyguardWallpaperLocked(context);
+ } catch (OutOfMemoryError e) {
+ Log.w(TAG, "No memory load current keyguard wallpaper", e);
+ }
+ return mKeyguardWallpaper;
+ }
+ }
+
public void forgetLoadedWallpaper() {
synchronized (this) {
mWallpaper = null;
@@ -292,6 +317,12 @@ public class WallpaperManager {
}
}
+ public void forgetLoadedKeyguardWallpaper() {
+ synchronized (this) {
+ mKeyguardWallpaper = null;
+ }
+ }
+
private Bitmap getCurrentWallpaperLocked(Context context) {
if (mService == null) {
Log.w(TAG, "WallpaperService not running");
@@ -321,7 +352,37 @@ public class WallpaperManager {
}
return null;
}
-
+
+ private Bitmap getCurrentKeyguardWallpaperLocked(Context context) {
+ if (mService == null) {
+ Log.w(TAG, "WallpaperService not running");
+ return null;
+ }
+ try {
+ Bundle params = new Bundle();
+ ParcelFileDescriptor fd = mService.getKeyguardWallpaper(this, params);
+ if (fd != null) {
+ try {
+ BitmapFactory.Options options = new BitmapFactory.Options();
+ Bitmap bm = BitmapFactory.decodeFileDescriptor(
+ fd.getFileDescriptor(), null, options);
+ return bm;
+ } catch (OutOfMemoryError e) {
+ Log.w(TAG, "Can't decode file", e);
+ } finally {
+ try {
+ fd.close();
+ } catch (IOException e) {
+ // Ignore
+ }
+ }
+ }
+ } catch (RemoteException e) {
+ // Ignore
+ }
+ return null;
+ }
+
private Bitmap getDefaultWallpaperLocked(Context context) {
InputStream is = openDefaultWallpaper(context);
if (is != null) {
@@ -340,6 +401,18 @@ public class WallpaperManager {
}
return null;
}
+
+ /** @hide */
+ public void clearKeyguardWallpaper() {
+ synchronized (this) {
+ try {
+ mService.clearKeyguardWallpaper();
+ } catch (RemoteException e) {
+ // ignore
+ }
+ mKeyguardWallpaper = null;
+ }
+ }
}
private static final Object sSync = new Object[0];
@@ -599,6 +672,15 @@ public class WallpaperManager {
return null;
}
+ /** @hide */
+ public Drawable getFastKeyguardDrawable() {
+ Bitmap bm = sGlobals.peekKeyguardWallpaperBitmap(mContext);
+ if (bm != null) {
+ return new FastBitmapDrawable(bm);
+ }
+ return null;
+ }
+
/**
* Like {@link #getFastDrawable()}, but if there is no wallpaper set,
* a null pointer is returned.
@@ -624,6 +706,13 @@ public class WallpaperManager {
}
/**
+ * @hide
+ */
+ public Bitmap getKeyguardBitmap() {
+ return sGlobals.peekKeyguardWallpaperBitmap(mContext);
+ }
+
+ /**
* Remove all internal references to the last loaded wallpaper. Useful
* for apps that want to reduce memory usage when they only temporarily
* need to have the wallpaper. After calling, the next request for the
@@ -636,6 +725,13 @@ public class WallpaperManager {
}
/**
+ * @hide
+ */
+ public void forgetLoadedKeyguardWallpaper() {
+ sGlobals.forgetLoadedKeyguardWallpaper();
+ }
+
+ /**
* If the current wallpaper is a live wallpaper component, return the
* information about that wallpaper. Otherwise, if it is a static image,
* simply return null.
@@ -787,6 +883,36 @@ public class WallpaperManager {
}
/**
+ * @param bitmap
+ * @throws IOException
+ * @hide
+ */
+ public void setKeyguardBitmap(Bitmap bitmap) throws IOException {
+ if (sGlobals.mService == null) {
+ Log.w(TAG, "WallpaperService not running");
+ return;
+ }
+ try {
+ ParcelFileDescriptor fd = sGlobals.mService.setKeyguardWallpaper(null,
+ mContext.getOpPackageName());
+ if (fd == null) {
+ return;
+ }
+ FileOutputStream fos = null;
+ try {
+ fos = new ParcelFileDescriptor.AutoCloseOutputStream(fd);
+ bitmap.compress(Bitmap.CompressFormat.PNG, 90, fos);
+ } finally {
+ if (fos != null) {
+ fos.close();
+ }
+ }
+ } catch (RemoteException e) {
+ // Ignore
+ }
+ }
+
+ /**
* Change the current system wallpaper to a specific byte stream. The
* give InputStream is copied into persistent storage and will now be
* used as the wallpaper. Currently it must be either a JPEG or PNG
@@ -826,6 +952,34 @@ public class WallpaperManager {
}
}
+ /**
+ * @hide
+ */
+ public void setKeyguardStream(InputStream data) throws IOException {
+ if (sGlobals.mService == null) {
+ Log.w(TAG, "WallpaperService not running");
+ return;
+ }
+ try {
+ ParcelFileDescriptor fd = sGlobals.mService.setKeyguardWallpaper(null,
+ mContext.getOpPackageName());
+ if (fd == null) {
+ return;
+ }
+ FileOutputStream fos = null;
+ try {
+ fos = new ParcelFileDescriptor.AutoCloseOutputStream(fd);
+ setWallpaper(data, fos);
+ } finally {
+ if (fos != null) {
+ fos.close();
+ }
+ }
+ } catch (RemoteException e) {
+ // Ignore
+ }
+ }
+
private void setWallpaper(InputStream data, FileOutputStream fos)
throws IOException {
byte[] buffer = new byte[32768];
@@ -1088,7 +1242,29 @@ public class WallpaperManager {
mWallpaperXStep = xStep;
mWallpaperYStep = yStep;
}
-
+
+ /** @hide */
+ public int getLastWallpaperX() {
+ try {
+ return WindowManagerGlobal.getWindowSession().getLastWallpaperX();
+ } catch (RemoteException e) {
+ // Ignore.
+ }
+
+ return -1;
+ }
+
+ /** @hide */
+ public int getLastWallpaperY() {
+ try {
+ return WindowManagerGlobal.getWindowSession().getLastWallpaperY();
+ } catch (RemoteException e) {
+ // Ignore.
+ }
+
+ return -1;
+ }
+
/**
* Send an arbitrary command to the current active wallpaper.
*
@@ -1162,7 +1338,25 @@ public class WallpaperManager {
* wallpaper.
*/
public void clear() throws IOException {
- setStream(openDefaultWallpaper(mContext));
+ clear(true);
+ }
+
+ /** @hide */
+ public void clear(boolean setToDefault) throws IOException {
+ if (setToDefault) {
+ setStream(openDefaultWallpaper(mContext));
+ } else {
+ Bitmap blackBmp = Bitmap.createBitmap(1, 1, Bitmap.Config.RGB_565);
+ blackBmp.setPixel(0, 0, mContext.getResources().getColor(android.R.color.black));
+ setBitmap(blackBmp);
+ }
+ }
+
+ /**
+ * @hide
+ */
+ public void clearKeyguardWallpaper() {
+ sGlobals.clearKeyguardWallpaper();
}
/**
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index e3414d9..5b9d9d5 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -4461,4 +4461,24 @@ public class DevicePolicyManager {
return PERMISSION_GRANT_STATE_DEFAULT;
}
}
+
+ /**
+ * CM: check if secure keyguard is required
+ * @hide
+ */
+ public boolean requireSecureKeyguard() {
+ return requireSecureKeyguard(UserHandle.myUserId());
+ }
+
+ /** @hide */
+ public boolean requireSecureKeyguard(int userHandle) {
+ if (mService != null) {
+ try {
+ return mService.requireSecureKeyguard(userHandle);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed to get secure keyguard requirement");
+ }
+ }
+ return true;
+ }
}
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 376a3d8..a40507b 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -234,4 +234,6 @@ interface IDevicePolicyManager {
boolean setPermissionGrantState(in ComponentName admin, String packageName,
String permission, int grantState);
int getPermissionGrantState(in ComponentName admin, String packageName, String permission);
+
+ boolean requireSecureKeyguard(int userHandle);
}
diff --git a/core/java/android/bluetooth/BluetoothA2dpSink.java b/core/java/android/bluetooth/BluetoothA2dpSink.java
index 2e27345..74302f2 100644..100755
--- a/core/java/android/bluetooth/BluetoothA2dpSink.java
+++ b/core/java/android/bluetooth/BluetoothA2dpSink.java
@@ -371,6 +371,89 @@ public final class BluetoothA2dpSink implements BluetoothProfile {
}
/**
+ * Set priority of the profile
+ *
+ * <p> The device should already be paired.
+ * Priority can be one of {@link #PRIORITY_ON} orgetBluetoothManager
+ * {@link #PRIORITY_OFF},
+ *
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
+ * permission.
+ *
+ * @param device Paired bluetooth device
+ * @param priority
+ * @return true if priority is set, false on error
+ * @hide
+ */
+ public boolean setPriority(BluetoothDevice device, int priority) {
+ if (DBG) log("setPriority(" + device + ", " + priority + ")");
+ if (mService != null && isEnabled()
+ && isValidDevice(device)) {
+ if (priority != BluetoothProfile.PRIORITY_OFF &&
+ priority != BluetoothProfile.PRIORITY_ON){
+ return false;
+ }
+ try {
+ return mService.setPriority(device, priority);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return false;
+ }
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return false;
+ }
+
+ /**
+ * Get the priority of the profile.
+ *
+ * <p> The priority can be any of:
+ * {@link #PRIORITY_AUTO_CONNECT}, {@link #PRIORITY_OFF},
+ * {@link #PRIORITY_ON}, {@link #PRIORITY_UNDEFINED}
+ *
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
+ *
+ * @param device Bluetooth device
+ * @return priority of the device
+ * @hide
+ */
+ public int getPriority(BluetoothDevice device) {
+ if (VDBG) log("getPriority(" + device + ")");
+ if (mService != null && isEnabled()
+ && isValidDevice(device)) {
+ try {
+ return mService.getPriority(device);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return BluetoothProfile.PRIORITY_OFF;
+ }
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return BluetoothProfile.PRIORITY_OFF;
+ }
+
+ /**
+ * Check if A2DP profile is streaming music.
+ *
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
+ *
+ * @param device BluetoothDevice device
+ */
+ public boolean isA2dpPlaying(BluetoothDevice device) {
+ if (mService != null && isEnabled()
+ && isValidDevice(device)) {
+ try {
+ return mService.isA2dpPlaying(device);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return false;
+ }
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return false;
+ }
+
+ /**
* Helper for converting a state to a string.
*
* For debug use only - strings are not internationalized.
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index 1f3ff51..24beba6 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -1,6 +1,8 @@
/*
* Copyright (C) 2009-2015 The Android Open Source Project
* Copyright (C) 2015 Samsung LSI
+ * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -23,6 +25,7 @@ import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.annotation.SystemApi;
+import android.app.ActivityThread;
import android.bluetooth.le.BluetoothLeAdvertiser;
import android.bluetooth.le.BluetoothLeScanner;
import android.bluetooth.le.ScanCallback;
@@ -538,6 +541,7 @@ public final class BluetoothAdapter {
* @throws IllegalArgumentException if address is invalid
*/
public BluetoothDevice getRemoteDevice(String address) {
+ android.util.SeempLog.record(62);
return new BluetoothDevice(address);
}
@@ -553,6 +557,7 @@ public final class BluetoothAdapter {
* @throws IllegalArgumentException if address is invalid
*/
public BluetoothDevice getRemoteDevice(byte[] address) {
+ android.util.SeempLog.record(62);
if (address == null || address.length != 6) {
throw new IllegalArgumentException("Bluetooth address must have 6 bytes");
}
@@ -762,7 +767,7 @@ public final class BluetoothAdapter {
try {
if (DBG) Log.d(TAG, "Calling enableBLE");
mManagerService.updateBleAppCount(mToken, true);
- return mManagerService.enable();
+ return mManagerService.enable(ActivityThread.currentPackageName());
} catch (RemoteException e) {
Log.e(TAG, "", e);
}
@@ -784,6 +789,7 @@ public final class BluetoothAdapter {
@RequiresPermission(Manifest.permission.BLUETOOTH)
@AdapterState
public int getState() {
+ android.util.SeempLog.record(63);
try {
synchronized(mManagerCallback) {
if (mService != null)
@@ -880,6 +886,7 @@ public final class BluetoothAdapter {
*/
@RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
public boolean enable() {
+ android.util.SeempLog.record(56);
int state = STATE_OFF;
if (isEnabled() == true){
if (DBG) Log.d(TAG, "enable(): BT is already enabled..!");
@@ -898,7 +905,7 @@ public final class BluetoothAdapter {
return true;
}
try {
- return mManagerService.enable();
+ return mManagerService.enable(ActivityThread.currentPackageName());
} catch (RemoteException e) {Log.e(TAG, "", e);}
return false;
}
@@ -929,6 +936,7 @@ public final class BluetoothAdapter {
*/
@RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
public boolean disable() {
+ android.util.SeempLog.record(57);
try {
return mManagerService.disable(true);
} catch (RemoteException e) {Log.e(TAG, "", e);}
@@ -946,6 +954,7 @@ public final class BluetoothAdapter {
* @hide
*/
public boolean disable(boolean persist) {
+ android.util.SeempLog.record(57);
try {
return mManagerService.disable(persist);
@@ -1190,6 +1199,7 @@ public final class BluetoothAdapter {
*/
@RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
public boolean startDiscovery() {
+ android.util.SeempLog.record(58);
if (getState() != STATE_ON) return false;
try {
synchronized(mManagerCallback) {
@@ -1408,6 +1418,7 @@ public final class BluetoothAdapter {
*/
@RequiresPermission(Manifest.permission.BLUETOOTH)
public Set<BluetoothDevice> getBondedDevices() {
+ android.util.SeempLog.record(61);
if (getState() != STATE_ON) {
return toDeviceSet(new BluetoothDevice[0]);
}
@@ -1460,6 +1471,7 @@ public final class BluetoothAdapter {
*/
@RequiresPermission(Manifest.permission.BLUETOOTH)
public int getProfileConnectionState(int profile) {
+ android.util.SeempLog.record(64);
if (getState() != STATE_ON) return BluetoothProfile.STATE_DISCONNECTED;
try {
synchronized(mManagerCallback) {
@@ -1582,6 +1594,7 @@ public final class BluetoothAdapter {
@RequiresPermission(Manifest.permission.BLUETOOTH)
public BluetoothServerSocket listenUsingInsecureRfcommWithServiceRecord(String name, UUID uuid)
throws IOException {
+ android.util.SeempLog.record(59);
return createNewRfcommSocketAndRecord(name, uuid, false, false);
}
@@ -1754,6 +1767,117 @@ public final class BluetoothAdapter {
return listenUsingL2capOn(port, false, false);
}
+
+ /**
+ * Construct an insecure L2CAP server socket.
+ * Call #accept to retrieve connections to this socket.
+ * <p>To auto assign a port without creating a SDP record use
+ * {@link SOCKET_CHANNEL_AUTO_STATIC_NO_SDP} as port number.
+ * @param port the PSM to listen on
+ * @return An L2CAP BluetoothServerSocket
+ * @throws IOException On error, for example Bluetooth not available, or
+ * insufficient permissions.
+ * @hide
+ */
+ public BluetoothServerSocket listenUsingInsecureL2capOn(int port) throws IOException {
+ BluetoothServerSocket socket = new BluetoothServerSocket(
+ BluetoothSocket.TYPE_L2CAP, false, false, port, false, false);
+ int errno = socket.mSocket.bindListen();
+ if(port == SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) {
+ socket.setChannel(socket.mSocket.getPort());
+ }
+ if (errno != 0) {
+ //TODO(BT): Throw the same exception error code
+ // that the previous code was using.
+ //socket.mSocket.throwErrnoNative(errno);
+ throw new IOException("Error: " + errno);
+ }
+ return socket;
+
+ }
+
+ /**
+ * Create a client side Message Access Profile Service Record.
+ * Create the record once, and reuse it for all connections.
+ * If changes to a record is needed remove the old record using {@link removeSdpRecord}
+ * and then create a new one.
+ * WARNING: This API requires removeSdpRecord() to be called, to avoid leaking resources!
+ * A second call to this function - either from two different apps or from the
+ * same app, without first calling removeSdpRecord() - will make the device
+ * break the Bluetooth spec, which could lead to severe IOP issues.
+ * @param serviceName The textual name of the service
+ * @param rfcommChannel The RFCOMM channel that clients can connect to
+ * (obtain from BluetoothServerSocket)
+ * @param l2capPsm The L2CAP PSM channel that clients can connect to
+ * (obtain from BluetoothServerSocket)
+ * Supply -1 to omit the L2CAP PSM from the record.
+ * @param version The Profile version number (As specified in the Bluetooth
+ * MAP specification)
+ * @param features The feature bit mask (As specified in the Bluetooth
+ * MAP specification)
+ * @return a handle to the record created. The record can be removed again
+ * using {@link removeSdpRecord}(). The record is not linked to the
+ * creation/destruction of BluetoothSockets, hence SDP record cleanup
+ * is a separate process.
+ * returns -1 if an error occure and the record was not created.
+ * @hide
+ */
+ public int createMapMnsSdpRecord(String serviceName, int rfcommChannel,
+ int l2capPsm, int version, int features) {
+ try {
+ return mService.createMapMnsSdpRecord(serviceName, rfcommChannel,
+ l2capPsm, version, features);
+ } catch (RemoteException e) {
+ Log.e(TAG, "createMapMnsSdpRecord: ", e);
+ }
+ return -1;
+ }
+
+ /**
+ * Create a client side Phonebook Access Profile Service Record.
+ * Create the record once, and reuse it for all connections.
+ * If changes to a record is needed remove the old record using {@link removeSdpRecord}
+ * and then create a new one.
+ * WARNING: This API requires removeSdpRecord() to be called, to avoid leaking resources!
+ * A second call to this function - either from two different apps or from the
+ * same app, without first calling removeSdpRecord() - will make the device
+ * break the Bluetooth spec, which could lead to severe IOP issues.
+ * @param serviceName The textual name of the service
+ * @param version The Profile version number (As specified in the Bluetooth
+ * PBAP specification)
+ * @return a handle to the record created. The record can be removed again
+ * using {@link removeSdpRecord}(). The record is not linked to the
+ * creation/destruction of BluetoothSockets, hence SDP record cleanup
+ * is a separate process.
+ * returns -1 if an error occure and the record was not created.
+ * @hide
+ */
+ public int createPbapPceSdpRecord(String serviceName, int version) {
+ try {
+ return mService.createPbapPceSdpRecord(serviceName, version);
+ } catch (RemoteException e) {
+ Log.e(TAG, "createPbapPceSdpRecord: ", e);
+ }
+ return -1;
+ }
+
+ /**
+ * Remove a SDP record created using createSdpRecord().
+ * This function shall be called before a new call to createSdpRecord for the same record
+ * type can be made, unless the record type created supports multiple instances.
+ * @param recordHandle handle of the record to remove - provided by createSdpRecord()
+ * @return true if success
+ * @hide
+ */
+ public boolean removeSdpRecord(int recordHandle){
+ try {
+ return mService.removeSdpRecord(recordHandle);
+ } catch (RemoteException e) {
+ Log.e(TAG, "removeSdpRecord: ", e);
+ }
+ return false;
+ }
+
/**
* Read the local Out of Band Pairing Data
* <p>Requires {@link android.Manifest.permission#BLUETOOTH}
@@ -1825,6 +1949,9 @@ public final class BluetoothAdapter {
} else if (profile == BluetoothProfile.PAN) {
BluetoothPan pan = new BluetoothPan(context, listener);
return true;
+ } else if (profile == BluetoothProfile.DUN) {
+ BluetoothDun dun = new BluetoothDun(context, listener);
+ return true;
} else if (profile == BluetoothProfile.HEALTH) {
BluetoothHealth health = new BluetoothHealth(context, listener);
return true;
@@ -1837,6 +1964,9 @@ public final class BluetoothAdapter {
} else if (profile == BluetoothProfile.SAP) {
BluetoothSap sap = new BluetoothSap(context, listener);
return true;
+ } else if (profile == BluetoothProfile.HID_DEVICE) {
+ BluetoothHidDevice hidd = new BluetoothHidDevice(context, listener);
+ return true;
} else {
return false;
}
@@ -1881,6 +2011,10 @@ public final class BluetoothAdapter {
BluetoothPan pan = (BluetoothPan)proxy;
pan.close();
break;
+ case BluetoothProfile.DUN:
+ BluetoothDun dun = (BluetoothDun)proxy;
+ dun.close();
+ break;
case BluetoothProfile.HEALTH:
BluetoothHealth health = (BluetoothHealth)proxy;
health.close();
@@ -1905,6 +2039,10 @@ public final class BluetoothAdapter {
BluetoothSap sap = (BluetoothSap)proxy;
sap.close();
break;
+ case BluetoothProfile.HID_DEVICE:
+ BluetoothHidDevice hidd = (BluetoothHidDevice) proxy;
+ hidd.close();
+ break;
}
}
diff --git a/core/java/android/bluetooth/BluetoothAvrcpController.java b/core/java/android/bluetooth/BluetoothAvrcpController.java
index b53a8fc..4851087 100644
--- a/core/java/android/bluetooth/BluetoothAvrcpController.java
+++ b/core/java/android/bluetooth/BluetoothAvrcpController.java
@@ -1,4 +1,5 @@
/*
+ * Copyright (c) 2015, The Linux Foundation. All rights reserved.
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -210,7 +211,7 @@ public final class BluetoothAvrcpController implements BluetoothProfile {
}
public void sendPassThroughCmd(BluetoothDevice device, int keyCode, int keyState) {
- if (DBG) Log.d(TAG, "sendPassThroughCmd");
+ if (DBG) Log.d(TAG, "sendPassThroughCmd dev = " + device + " key " + keyCode + " State = " + keyState);
if (mService != null && isEnabled()) {
try {
mService.sendPassThroughCmd(device, keyCode, keyState);
@@ -223,6 +224,90 @@ public final class BluetoothAvrcpController implements BluetoothProfile {
if (mService == null) Log.w(TAG, "Proxy not attached to service");
}
+ public void getMetaData(int[] attributeIds) {
+ if (DBG) Log.d(TAG, "getMetaData num requested Ids = " + attributeIds.length);
+ if (mService != null && isEnabled()) {
+ try {
+ mService.getMetaData(attributeIds);
+ return;
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error talking to BT service in getMetaData", e);
+ return;
+ }
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ }
+
+ public void getPlayStatus(int[] playStatusIds) {
+ if (DBG) Log.d(TAG, "getPlayStatus num requested Ids = "+ playStatusIds.length);
+ if (mService != null && isEnabled()) {
+ try {
+ mService.getPlayStatus(playStatusIds);
+ return;
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error talking to BT service in getPlayStatus()", e);
+ return;
+ }
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ }
+
+ public void getPlayerApplicationSetting() {
+ if (DBG) Log.d(TAG, "getPlayerApplicationSetting");
+ if (mService != null && isEnabled()) {
+ try {
+ mService.getPlayerApplicationSetting();
+ return;
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error talking to BT service in getPlayerApplicationSetting()", e);
+ return;
+ }
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ }
+
+ public void setPlayerApplicationSetting(int attributeId, int attributeVal) {
+ if (DBG) Log.d(TAG, "setPlayerApplicationSetting attribId = " + attributeId + " attribVal = " + attributeVal);
+ if (mService != null && isEnabled()) {
+ try {
+ mService.setPlayerApplicationSetting(attributeId, attributeVal);
+ return;
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error talking to BT service in setPlayerApplicationSetting()", e);
+ return;
+ }
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ }
+
+ public BluetoothAvrcpInfo getSupportedPlayerAppSetting(BluetoothDevice device) {
+ if (DBG) Log.d(TAG, "getSupportedPlayerAppSetting dev = " + device);
+ if (mService != null && isEnabled()) {
+ try {
+ return mService.getSupportedPlayerAppSetting(device);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error talking to BT service in getSupportedPlayerAppSetting()", e);
+ return null;
+ }
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return null;
+ }
+
+ public int getSupportedFeatures(BluetoothDevice device) {
+ if (DBG) Log.d(TAG, "getSupportedFeatures dev = " + device);
+ if (mService != null && isEnabled()) {
+ try {
+ return mService.getSupportedFeatures(device);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error talking to BT service in getSupportedFeatures()", e);
+ return 0;
+ }
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return 0;
+ }
+
private final ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
if (DBG) Log.d(TAG, "Proxy object connected");
diff --git a/core/java/android/bluetooth/BluetoothAvrcpInfo.aidl b/core/java/android/bluetooth/BluetoothAvrcpInfo.aidl
new file mode 100644
index 0000000..9b85c80
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothAvrcpInfo.aidl
@@ -0,0 +1,34 @@
+/*
+/*
+ * Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+package android.bluetooth;
+
+parcelable BluetoothAvrcpInfo;
diff --git a/core/java/android/bluetooth/BluetoothAvrcpInfo.java b/core/java/android/bluetooth/BluetoothAvrcpInfo.java
new file mode 100644
index 0000000..a815d10
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothAvrcpInfo.java
@@ -0,0 +1,306 @@
+/*
+ * Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+package android.bluetooth;
+
+import java.util.ArrayList;
+import android.util.Log;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.provider.BaseColumns;
+import android.net.Uri;
+
+/**
+ * Represents the AVRCP Metadata of remote Bluetooth Device.
+ *
+ * {@see BluetoothAvrcpController}
+ *
+ * {@hide}
+ */
+public final class BluetoothAvrcpInfo implements Parcelable, BaseColumns{
+
+ private byte[] supportedPlayerAttributes;// attributes supported
+ private byte[] numSupportedPlayerAttribValues; // number of values of each attribute
+ private String TAG = "BluetoothAvrcpInfo";
+ /*
+ * This would a list of values of all AttributeIds
+ */
+ private byte[] supportedPlayerAtribValues; // actual values lies here.
+
+ /* Default Constructor */
+ public BluetoothAvrcpInfo() {
+ supportedPlayerAttributes = null;
+ numSupportedPlayerAttribValues = null;
+ supportedPlayerAtribValues = null;
+ }
+ public BluetoothAvrcpInfo(byte[] attribIds, byte[] numValueSupported, byte[] valuesSupported) {
+ int numAttributes = attribIds.length;
+ int zz = 0;
+ supportedPlayerAttributes = new byte[numAttributes];
+ numSupportedPlayerAttribValues = new byte[numAttributes];
+ supportedPlayerAtribValues = new byte[valuesSupported.length];
+ for (zz = 0; zz < numAttributes; zz++) {
+ supportedPlayerAttributes[zz] = attribIds[zz];
+ numSupportedPlayerAttribValues[zz] = numValueSupported[zz];
+ }
+ for (zz = 0; zz < supportedPlayerAtribValues.length; zz++)
+ supportedPlayerAtribValues[zz] = valuesSupported[zz];
+ }
+ /*
+ * Reading Structure back from Paracel
+ */
+ public BluetoothAvrcpInfo(Parcel source){
+ ArrayList<Byte> attribs = new ArrayList<Byte>();
+ ArrayList<Byte> numAttribVal = new ArrayList<Byte>();
+ ArrayList<Byte> attribVals = new ArrayList<Byte>();
+ Byte numAttributes = source.readByte();
+ /*
+ * Read from Source
+ */
+ for(int xx = 0; xx < numAttributes ; xx++) {
+ attribs.add(source.readByte());
+ numAttribVal.add(source.readByte());
+ for (int zz = 0; zz < numAttribVal.get(xx); zz++) {
+ attribVals.add(source.readByte());
+ }
+ }
+
+ /*
+ * Write Back to Private Data Structures
+ */
+ supportedPlayerAttributes = new byte[attribs.size()];
+ for (int zz = 0; zz< attribs.size(); zz++) {
+ supportedPlayerAttributes[zz] = attribs.get(zz);
+ }
+
+ numSupportedPlayerAttribValues = new byte[numAttribVal.size()];
+ for (int zz = 0; zz< numAttribVal.size(); zz++) {
+ numSupportedPlayerAttribValues[zz] = numAttribVal.get(zz);
+ }
+
+ supportedPlayerAtribValues = new byte[attribVals.size()];
+ for (int zz = 0; zz< attribVals.size(); zz++) {
+ supportedPlayerAtribValues[zz] = attribVals.get(zz);
+ }
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ /* While flatenning the structure we would use the follwing way
+ * NumAttributes,ID, numValues, Values
+ */
+ public void writeToParcel(Parcel out, int flags) {
+ byte numSuppAttributes = (byte)supportedPlayerAttributes.length;
+ out.writeByte(numSuppAttributes);
+ for (int xx = 0; xx < numSuppAttributes; xx++) {
+ out.writeByte(supportedPlayerAttributes[xx]);
+ out.writeByte(numSupportedPlayerAttribValues[xx]);
+ for (int zz = 0; zz < numSupportedPlayerAttribValues[xx]; zz++) {
+ out.writeByte(supportedPlayerAtribValues[zz]);
+ }
+ }
+ }
+
+ public byte[] getSupportedPlayerAttributes() {
+ return supportedPlayerAttributes;
+ }
+
+ public byte getNumSupportedPlayerAttributeVal(byte playerAttributeId) {
+ for (int zz = 0; zz < supportedPlayerAttributes.length; zz++) {
+ if (playerAttributeId == supportedPlayerAttributes[zz]) {
+ return numSupportedPlayerAttribValues[zz];
+ }
+ }
+ return 0;
+ }
+
+ public byte[] getSupportedPlayerAttributeVlaues (byte playerAttributeId) {
+ int index = 0;
+ int zz = 0;
+ boolean attributeFound = false;
+ for (zz = 0; zz < supportedPlayerAttributes.length; zz++) {
+ if (playerAttributeId == supportedPlayerAttributes[zz]) {
+ attributeFound = true;
+ break;
+ }
+ else
+ index = index + numSupportedPlayerAttribValues[zz];
+ }
+ if (attributeFound) {
+ byte[] supportedValues = new byte[numSupportedPlayerAttribValues[zz]];
+ for (int xx = 0; xx < numSupportedPlayerAttribValues[zz]; xx++)
+ supportedValues[xx] = supportedPlayerAtribValues[xx + index];
+ return supportedValues;
+ }
+ else
+ return new byte[0];
+ }
+ public void putPlayerSettingAttributes(byte[] attribIds, byte[] numValueSupported, byte[] valuesSupported) {
+ int numAttributes = attribIds.length;
+ int zz = 0;
+ supportedPlayerAttributes = new byte[numAttributes];
+ numSupportedPlayerAttribValues = new byte[numAttributes];
+ supportedPlayerAtribValues = new byte[valuesSupported.length];
+ for (zz = 0; zz < numAttributes; zz++) {
+ supportedPlayerAttributes[zz] = attribIds[zz];
+ numSupportedPlayerAttribValues[zz] = numValueSupported[zz];
+ }
+ for (zz = 0; zz < supportedPlayerAtribValues.length; zz++)
+ supportedPlayerAtribValues[zz] = valuesSupported[zz];
+ }
+ public static final Parcelable.Creator<BluetoothAvrcpInfo> CREATOR =
+ new Parcelable.Creator<BluetoothAvrcpInfo>() {
+ public BluetoothAvrcpInfo createFromParcel(Parcel in) {
+ return new BluetoothAvrcpInfo(in);
+ }
+ public BluetoothAvrcpInfo[] newArray(int size) {
+ return new BluetoothAvrcpInfo[size];
+ }
+ };
+
+ public static final String PERMISSION_ACCESS = "android.permission.ACCESS_BLUETOOTH_AVRCP_CT_DATA";
+ public static final Uri CONTENT_URI = Uri.parse("content://com.android.bluetooth.avrcp/btavrcp_ct");
+
+ /*
+ * BaseColumns already has _ID and COUNT values
+ * Below mentioned strings are used to implement different columns
+ * of AVRCP MetaData table.
+ * TRACK_NUM : Ineteger value containing the order number of
+ * the audio-file on its original recording.
+ * Numeric ASCII string converted to Integer
+ * TITLE : Text field representing the title, song name
+ * ARTIST_NAME : Text field representing artist(s), performer(s)
+ * ALBUM_NAME : Text field representing the title of the recording
+ * (source) from which the audio in the file is taken.
+ * TOTAL_TRACKS : Integet value containing the total number of tracks
+ * or elements on the original recording.
+ * GENRE : Text field representing the category of the composition
+ * characterized by a particular style.
+ * PLAYING_TIME : Integer containing the length of the audio file in
+ * milliseconds for eg 02:30 = 150000
+ * PLAY_STATUS : Text feild showing current state of track. Possible
+ * values would be Playing, Stopped, Paused, Forward_Seek
+ * REV_SEEK
+ * REPEAT_STATUS : String describing Repeat mode status on remote Media Player
+ * Posible values "NOT SUPPORTED", "OFF" "Single Track Repeat"
+ * "All Track Repeat" "Group Repeat"
+ * SHUFFLE_STATUS : String describing Shuffle mode status on remote Media Player
+ * Posible values "NOT SUPPORTED", "OFF" "All Track Shuffle"
+ * "Group Shuffle"
+ * SCAN_STAUS : String describing SCAN mode status on remote Media Player
+ * Possible values "NOT SUPPORTED", "OFF","ALL Tracks Scan"
+ * "Group Scan"
+ *
+ * EQUALIZER_STATUS: String describing EQUALIZER mode status on remote Media Player
+ * Possible values "NOT SUPPORTED", "OFF","ON"
+ */
+ public static final String TRACK_NUM = "track_num";
+ public static final String TITLE = "title";
+ public static final String ARTIST_NAME = "artist_name";
+ public static final String ALBUM_NAME = "album_name";
+ public static final String TOTAL_TRACKS = "total_tracks";
+ public static final String GENRE = "genre";
+ public static final String PLAYING_TIME = "playing_time";
+ public static final String TOTAL_TRACK_TIME = "total_track_time";
+ public static final String PLAY_STATUS = "play_status";
+ public static final String REPEAT_STATUS = "repeat_status";
+ public static final String SHUFFLE_STATUS = "shuffle_status";
+ public static final String SCAN_STATUS = "scan_status";
+ public static final String EQUALIZER_STATUS = "equalizer_status";
+
+ /*
+ * Default values for each of the items
+ */
+ public static final int TRACK_NUM_INVALID = 0xFF;
+ public static final String TITLE_INVALID = "NOT_SUPPORTED";
+ public static final String ARTIST_NAME_INVALID = "NOT_SUPPORTED";
+ public static final String ALBUM_NAME_INVALID = "NOT_SUPPORTED";
+ public static final int TOTAL_TRACKS_INVALID = 0xFF;
+ public static final String GENRE_INVALID = "NOT_SUPPORTED";
+ public static final int PLAYING_TIME_INVALID = 0xFF;
+ public static final int TOTAL_TRACK_TIME_INVALID = 0xFF;
+ public static final String PLAY_STATUS_INVALID = "NOT_SUPPORTED";
+ public static final String REPEAT_STATUS_INVALID = "NOT_SUPPORTED";
+ public static final String SHUFFLE_STATUS_INVALID = "NOT_SUPPORTED";
+ public static final String SCAN_STATUS_INVALID = "NOT_SUPPORTED";
+ public static final String EQUALIZER_STATUS_INVALID = "NOT_SUPPORTED";
+
+ /*
+ *Element Id Values for GetMetaData
+ */
+ public static final int MEDIA_ATTRIBUTE_ALL = 0x00;
+ public static final int MEDIA_ATTRIBUTE_TITLE = 0x01;
+ public static final int MEDIA_ATTRIBUTE_ARTIST_NAME = 0x02;
+ public static final int MEDIA_ATTRIBUTE_ALBUM_NAME = 0x03;
+ public static final int MEDIA_ATTRIBUTE_TRACK_NUMBER = 0x04;
+ public static final int MEDIA_ATTRIBUTE_TOTAL_TRACK_NUMBER = 0x05;
+ public static final int MEDIA_ATTRIBUTE_GENRE = 0x06;
+ public static final int MEDIA_ATTRIBUTE_PLAYING_TIME = 0x07;
+
+ /*
+ *PlayStatusId Values for GetPlayStatus
+ */
+ public static final int MEDIA_PLAYSTATUS_ALL = 0x08;
+ public static final int MEDIA_PLAYSTATUS_SONG_TOTAL_LEN = 0x09;
+ public static final int MEDIA_PLAYSTATUS_SONG_CUR_POS = 0x0a;
+ public static final int MEDIA_PLAYSTATUS_SONG_PLAY_STATUS = 0x0b;
+
+ /*
+ * Values for SetPlayerApplicationSettings
+ */
+ public static final byte ATTRIB_EQUALIZER_STATUS = 0x01;
+ public static final byte ATTRIB_REPEAT_STATUS = 0x02;
+ public static final byte ATTRIB_SHUFFLE_STATUS = 0x03;
+ public static final byte ATTRIB_SCAN_STATUS = 0x04;
+
+ public static final byte EQUALIZER_STATUS_OFF = 0x01;
+ public static final byte EQUALIZER_STATUS_ON = 0x02;
+
+ public static final byte REPEAT_STATUS_OFF = 0x01;
+ public static final byte REPEAT_STATUS_SINGLE_TRACK_REPEAT = 0x02;
+ public static final byte REPEAT_STATUS_ALL_TRACK_REPEAT = 0x03;
+ public static final byte REPEAT_STATUS_GROUP_REPEAT = 0x04;
+
+ public static final byte SHUFFLE_STATUS_OFF = 0x01;
+ public static final byte SHUFFLE_STATUS_ALL_TRACK_SHUFFLE = 0x02;
+ public static final byte SHUFFLE_STATUS_GROUP_SHUFFLE = 0x03;
+
+ public static final byte SCAN_STATUS_OFF = 0x01;
+ public static final byte SCAN_STATUS_ALL_TRACK_SCAN = 0x02;
+ public static final byte SCAN_STATUS_GROUP_SCAN = 0x03;
+
+ public static final int BTRC_FEAT_METADATA = 0x01;
+ public static final int BTRC_FEAT_ABSOLUTE_VOLUME = 0x02;
+ public static final int BTRC_FEAT_BROWSE = 0x04;
+
+}
diff --git a/core/java/android/bluetooth/BluetoothClass.java b/core/java/android/bluetooth/BluetoothClass.java
index 54bf4af..4a38287 100644..100755
--- a/core/java/android/bluetooth/BluetoothClass.java
+++ b/core/java/android/bluetooth/BluetoothClass.java
@@ -283,6 +283,8 @@ public final class BluetoothClass implements Parcelable {
public static final int PROFILE_PANU = 4;
/** @hide */
public static final int PROFILE_NAP = 5;
+ /** @hide */
+ public static final int PROFILE_A2DP_SINK = 6;
/**
* Check class bits for possible bluetooth profile support.
@@ -310,6 +312,21 @@ public final class BluetoothClass implements Parcelable {
default:
return false;
}
+ } else if (profile == PROFILE_A2DP_SINK) {
+ if (hasService(Service.CAPTURE)) {
+ return true;
+ }
+ // By the A2DP spec, srcs must indicate the CAPTURE service.
+ // However if some device that do not, we try to
+ // match on some other class bits.
+ switch (getDeviceClass()) {
+ case Device.AUDIO_VIDEO_HIFI_AUDIO:
+ case Device.AUDIO_VIDEO_SET_TOP_BOX:
+ case Device.AUDIO_VIDEO_VCR :
+ return true;
+ default:
+ return false;
+ }
} else if (profile == PROFILE_HEADSET) {
// The render service class is required by the spec for HFP, so is a
// pretty good signal
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index d27dfa0..e742b2b 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -1390,6 +1390,27 @@ public final class BluetoothDevice implements Parcelable {
}
/**
+ * Create an L2cap {@link BluetoothSocket} ready to start an insecure
+ * outgoing connection to this remote device on given channel.
+ * <p>The remote device will be not authenticated and communication on this
+ * socket will not be encrypted.
+ * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing
+ * connection.
+ * <p>Valid L2CAP PSM channels are in range 1 to 2^16.
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
+ *
+ * @param channel L2cap PSM/channel to connect to
+ * @return a RFCOMM BluetoothServerSocket ready for an outgoing connection
+ * @throws IOException on error, for example Bluetooth not available, or
+ * insufficient permissions
+ * @hide
+ */
+ public BluetoothSocket createInsecureL2capSocket(int channel) throws IOException {
+ return new BluetoothSocket(BluetoothSocket.TYPE_L2CAP, -1, false, false, this, channel,
+ null);
+ }
+
+ /**
* Create an RFCOMM {@link BluetoothSocket} ready to start a secure
* outgoing connection to this remote device using SDP lookup of uuid.
* <p>This is designed to be used with {@link
diff --git a/core/java/android/bluetooth/BluetoothDevicePicker.java b/core/java/android/bluetooth/BluetoothDevicePicker.java
index c794be2..51d14cc 100644
--- a/core/java/android/bluetooth/BluetoothDevicePicker.java
+++ b/core/java/android/bluetooth/BluetoothDevicePicker.java
@@ -44,6 +44,14 @@ public interface BluetoothDevicePicker {
"android.bluetooth.devicepicker.action.DEVICE_SELECTED";
/**
+ * Broadcast when no BT device is selected from BT device picker screen.
+ * This happens when user presses back button.
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_DEVICE_NOT_SELECTED =
+ "org.codeaurora.bluetooth.devicepicker.action.DEVICE_NOT_SELECTED";
+
+ /**
* Broadcast when someone want to select one BT device from devices list.
* This intent contains below extra data:
* - {@link #EXTRA_NEED_AUTH} (boolean): if need authentication
diff --git a/core/java/android/bluetooth/BluetoothDun.java b/core/java/android/bluetooth/BluetoothDun.java
new file mode 100644
index 0000000..0912061
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothDun.java
@@ -0,0 +1,296 @@
+/*
+*Copyright (c) 2013, The Linux Foundation. All rights reserved.
+*
+*Redistribution and use in source and binary forms, with or without
+*modification, are permitted provided that the following conditions are
+*met:
+* * Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+* * Redistributions in binary form must reproduce the above
+* copyright notice, this list of conditions and the following
+* disclaimer in the documentation and/or other materials provided
+* with the distribution.
+* * Neither the name of The Linux Foundation nor the names of its
+* contributors may be used to endorse or promote products derived
+* from this software without specific prior written permission.
+*
+*THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+*WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+*MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+*ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+*BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+*CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+*SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+*BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+*WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+*OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+*IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+package android.bluetooth;
+
+import android.annotation.SdkConstant;
+import android.annotation.SdkConstant.SdkConstantType;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * This class provides the APIs to control the Bluetooth Dun
+ * Profile.
+ *
+ *<p>BluetoothDun is a proxy object for controlling the Bluetooth DUN
+ * Service via IPC. Use {@link BluetoothAdapter#getProfileProxy} to get
+ * the BluetoothDun proxy object.
+ *
+ *<p>Each method is protected with its appropriate permission.
+ *@hide
+ */
+public final class BluetoothDun implements BluetoothProfile {
+ private static final String TAG = "BluetoothDun";
+ private static final boolean DBG = false;
+ private static final boolean VDBG = false;
+
+ /**
+ * Intent used to broadcast the change in connection state of the Dun
+ * profile.
+ *
+ * <p>This intent will have 3 extras:
+ * <ul>
+ * <li> {@link #EXTRA_STATE} - The current state of the profile. </li>
+ * <li> {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile.</li>
+ * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li>
+ * </ul>
+ *
+ * <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of
+ * {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTED}.
+ *
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
+ * receive.
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_CONNECTION_STATE_CHANGED =
+ "codeaurora.bluetooth.dun.profile.action.CONNECTION_STATE_CHANGED";
+
+ private Context mContext;
+ private ServiceListener mServiceListener;
+ private BluetoothAdapter mAdapter;
+ private IBluetoothDun mDunService;
+
+ /**
+ * Create a BluetoothDun proxy object for interacting with the local
+ * Bluetooth Service which handles the Dun profile
+ *
+ */
+ /*package*/ BluetoothDun(Context context, ServiceListener l) {
+ mContext = context;
+ mServiceListener = l;
+ mAdapter = BluetoothAdapter.getDefaultAdapter();
+ try {
+ mAdapter.getBluetoothManager().registerStateChangeCallback(mStateChangeCallback);
+ } catch (RemoteException re) {
+ Log.w(TAG,"Unable to register BluetoothStateChangeCallback",re);
+ }
+ Log.d(TAG, "BluetoothDun() call bindService");
+ doBind();
+ }
+
+ boolean doBind() {
+ Intent intent = new Intent(IBluetoothDun.class.getName());
+ ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
+ intent.setComponent(comp);
+ if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0,
+ android.os.Process.myUserHandle())) {
+ Log.e(TAG, "Could not bind to Bluetooth Dun Service with " + intent);
+ return false;
+ }
+ return true;
+ }
+
+
+ /*package*/ void close() {
+ if (VDBG) log("close()");
+ mServiceListener = null;
+ IBluetoothManager mgr = mAdapter.getBluetoothManager();
+ if (mgr != null) {
+ try {
+ mgr.unregisterStateChangeCallback(mStateChangeCallback);
+ } catch (RemoteException re) {
+ Log.w(TAG,"Unable to unregister BluetoothStateChangeCallback",re);
+ }
+ }
+
+ synchronized (mConnection) {
+ if ( mDunService != null) {
+ try {
+ mDunService = null;
+ mContext.unbindService(mConnection);
+ } catch (Exception re) {
+ Log.e(TAG,"",re);
+ }
+ }
+ }
+ }
+
+ protected void finalize() {
+ close();
+ }
+
+ private IBluetoothStateChangeCallback mStateChangeCallback =
+ new IBluetoothStateChangeCallback.Stub() {
+
+ @Override
+ public void onBluetoothStateChange(boolean on) {
+ //Handle enable request to bind again.
+ Log.d(TAG, "onBluetoothStateChange on: " + on);
+ if (on) {
+ try {
+ if (mDunService == null) {
+ Log.d(TAG, "onBluetoothStateChange call bindService");
+ doBind();
+ }
+ } catch (IllegalStateException e) {
+ Log.e(TAG,"onBluetoothStateChange: could not bind to DUN service: ", e);
+ } catch (SecurityException e) {
+ Log.e(TAG,"onBluetoothStateChange: could not bind to DUN service: ", e);
+ }
+ } else {
+ if (VDBG) Log.d(TAG,"Unbinding service...");
+ synchronized (mConnection) {
+ if ( mDunService != null) {
+ try {
+ mDunService = null;
+ mContext.unbindService(mConnection);
+ } catch (Exception re) {
+ Log.e(TAG,"",re);
+ }
+ }
+ }
+ }
+ }
+ };
+
+ /**
+ * Initiate disconnection from DUN server.
+ *
+ * <p> Once the disconnection is initiated by any device either local host
+ * or remote device, the state will transition from {@link #STATE_CONNECTED}
+ * to {@link #STATE_DISCONNECTED}.
+ *
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
+ * permission.
+ *
+ * @param device Remote Bluetooth Device
+ * @return false on immediate error,
+ * true otherwise
+ * @hide
+ */
+ public boolean disconnect(BluetoothDevice device) {
+ if (DBG) log("disconnect(" + device + ")");
+ if (mDunService != null && isEnabled() &&
+ isValidDevice(device)) {
+ try {
+ return mDunService.disconnect(device);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return false;
+ }
+ }
+ if (mDunService == null) Log.w(TAG, "Proxy not attached to service");
+ return false;
+ }
+ /**
+ * {@inheritDoc}
+ */
+ public List<BluetoothDevice> getConnectedDevices() {
+ if (VDBG) log("getConnectedDevices()");
+ if (mDunService != null && isEnabled()) {
+ try {
+ return mDunService.getConnectedDevices();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return new ArrayList<BluetoothDevice>();
+ }
+ }
+ if (mDunService == null) Log.w(TAG, "Proxy not attached to service");
+ return new ArrayList<BluetoothDevice>();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
+ if (VDBG) log("getDevicesMatchingStates()");
+ if (mDunService != null && isEnabled()) {
+ try {
+ return mDunService.getDevicesMatchingConnectionStates(states);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return new ArrayList<BluetoothDevice>();
+ }
+ }
+ if (mDunService == null) Log.w(TAG, "Proxy not attached to service");
+ return new ArrayList<BluetoothDevice>();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public int getConnectionState(BluetoothDevice device) {
+ if (VDBG) log("getState(" + device + ")");
+ if (mDunService != null && isEnabled()
+ && isValidDevice(device)) {
+ try {
+ return mDunService.getConnectionState(device);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return BluetoothProfile.STATE_DISCONNECTED;
+ }
+ }
+ if (mDunService == null) Log.w(TAG, "Proxy not attached to service");
+ return BluetoothProfile.STATE_DISCONNECTED;
+ }
+
+ private ServiceConnection mConnection = new ServiceConnection() {
+ public void onServiceConnected(ComponentName className, IBinder service) {
+ if (DBG) Log.d(TAG, "BluetoothDUN Proxy object connected");
+ mDunService = IBluetoothDun.Stub.asInterface(service);
+
+ if (mServiceListener != null) {
+ mServiceListener.onServiceConnected(BluetoothProfile.DUN,
+ BluetoothDun.this);
+ }
+ }
+ public void onServiceDisconnected(ComponentName className) {
+ if (DBG) Log.d(TAG, "BluetoothDUN Proxy object disconnected");
+ mDunService = null;
+ if (mServiceListener != null) {
+ mServiceListener.onServiceDisconnected(BluetoothProfile.DUN);
+ }
+ }
+ };
+
+ private boolean isEnabled() {
+ if (mAdapter.getState() == BluetoothAdapter.STATE_ON) return true;
+ return false;
+ }
+
+ private boolean isValidDevice(BluetoothDevice device) {
+ if (device == null) return false;
+
+ if (BluetoothAdapter.checkBluetoothAddress(device.getAddress())) return true;
+ return false;
+ }
+
+ private static void log(String msg) {
+ Log.d(TAG, msg);
+ }
+}
diff --git a/core/java/android/bluetooth/BluetoothHeadset.java b/core/java/android/bluetooth/BluetoothHeadset.java
index 25d9aa9..8d4742b 100644
--- a/core/java/android/bluetooth/BluetoothHeadset.java
+++ b/core/java/android/bluetooth/BluetoothHeadset.java
@@ -20,10 +20,9 @@ import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.content.ComponentName;
import android.content.Context;
-import android.os.Handler;
+import android.content.Intent;
+import android.content.ServiceConnection;
import android.os.IBinder;
-import android.os.Looper;
-import android.os.Message;
import android.os.RemoteException;
import android.util.Log;
@@ -47,7 +46,7 @@ import java.util.List;
public final class BluetoothHeadset implements BluetoothProfile {
private static final String TAG = "BluetoothHeadset";
private static final boolean DBG = true;
- private static final boolean VDBG = false;
+ private static final boolean VDBG = true;
/**
* Intent used to broadcast the change in connection state of the Headset
@@ -129,6 +128,13 @@ public final class BluetoothHeadset implements BluetoothProfile {
"android.bluetooth.headset.action.VENDOR_SPECIFIC_HEADSET_EVENT";
/**
+ * @hide Broadcast intent when HF indicator value changed is updated by HS.
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_HF_INDICATOR_VALUE_CHANGED =
+ "codeaurora.bluetooth.headset.action.ACTION_HF_INDICATOR_VALUE_CHANGED";
+
+ /**
* A String extra field in {@link #ACTION_VENDOR_SPECIFIC_HEADSET_EVENT}
* intents that contains the name of the vendor-specific command.
*/
@@ -199,6 +205,20 @@ public final class BluetoothHeadset implements BluetoothProfile {
public static final String VENDOR_RESULT_CODE_COMMAND_ANDROID = "+ANDROID";
/**
+ * @hide Used for sharing the HF indicator assigned number.
+ */
+ public static final String HF_INDICATOR_ASSIGNED_NUMBER =
+ "codeaurora.bluetooth.headset.intent.category.anum";
+
+
+ /**
+ * @hide Used for sharing the HF indicator assigned number's value.
+ */
+ public static final String HF_INDICATOR_ASSIGNED_NUMBER_VALUE =
+ "codeaurora.bluetooth.headset.intent.category.anumvalue";
+
+
+ /**
* Headset state when SCO audio is not connected.
* This state can be one of
* {@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} of
@@ -222,8 +242,6 @@ public final class BluetoothHeadset implements BluetoothProfile {
*/
public static final int STATE_AUDIO_CONNECTED = 12;
- private static final int MESSAGE_HEADSET_SERVICE_CONNECTED = 100;
- private static final int MESSAGE_HEADSET_SERVICE_DISCONNECTED = 101;
private Context mContext;
private ServiceListener mServiceListener;
@@ -236,7 +254,14 @@ public final class BluetoothHeadset implements BluetoothProfile {
if (DBG) Log.d(TAG, "onBluetoothStateChange: up=" + up);
if (!up) {
if (VDBG) Log.d(TAG,"Unbinding service...");
- doUnbind();
+ synchronized (mConnection) {
+ try {
+ mService = null;
+ mContext.unbindService(mConnection);
+ } catch (Exception re) {
+ Log.e(TAG,"",re);
+ }
+ }
} else {
synchronized (mConnection) {
try {
@@ -273,26 +298,15 @@ public final class BluetoothHeadset implements BluetoothProfile {
}
boolean doBind() {
- try {
- return mAdapter.getBluetoothManager().bindBluetoothProfileService(
- BluetoothProfile.HEADSET, mConnection);
- } catch (RemoteException e) {
- Log.e(TAG, "Unable to bind HeadsetService", e);
- }
- return false;
- }
-
- void doUnbind() {
- synchronized (mConnection) {
- if (mService != null) {
- try {
- mAdapter.getBluetoothManager().unbindBluetoothProfileService(
- BluetoothProfile.HEADSET, mConnection);
- } catch (RemoteException e) {
- Log.e(TAG,"Unable to unbind HeadsetService", e);
- }
- }
+ Intent intent = new Intent(IBluetoothHeadset.class.getName());
+ ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
+ intent.setComponent(comp);
+ if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0,
+ android.os.Process.myUserHandle())) {
+ Log.e(TAG, "Could not bind to Bluetooth Headset Service with " + intent);
+ return false;
}
+ return true;
}
/**
@@ -312,8 +326,18 @@ public final class BluetoothHeadset implements BluetoothProfile {
Log.e(TAG,"",e);
}
}
+
+ synchronized (mConnection) {
+ if (mService != null) {
+ try {
+ mService = null;
+ mContext.unbindService(mConnection);
+ } catch (Exception re) {
+ Log.e(TAG,"",re);
+ }
+ }
+ }
mServiceListener = null;
- doUnbind();
}
/**
@@ -927,21 +951,21 @@ public final class BluetoothHeadset implements BluetoothProfile {
return false;
}
- private final IBluetoothProfileServiceConnection mConnection
- = new IBluetoothProfileServiceConnection.Stub() {
- @Override
+ private final ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
if (DBG) Log.d(TAG, "Proxy object connected");
mService = IBluetoothHeadset.Stub.asInterface(service);
- mHandler.sendMessage(mHandler.obtainMessage(
- MESSAGE_HEADSET_SERVICE_CONNECTED));
+
+ if (mServiceListener != null) {
+ mServiceListener.onServiceConnected(BluetoothProfile.HEADSET, BluetoothHeadset.this);
+ }
}
- @Override
public void onServiceDisconnected(ComponentName className) {
if (DBG) Log.d(TAG, "Proxy object disconnected");
mService = null;
- mHandler.sendMessage(mHandler.obtainMessage(
- MESSAGE_HEADSET_SERVICE_DISCONNECTED));
+ if (mServiceListener != null) {
+ mServiceListener.onServiceDisconnected(BluetoothProfile.HEADSET);
+ }
}
};
@@ -965,25 +989,4 @@ public final class BluetoothHeadset implements BluetoothProfile {
private static void log(String msg) {
Log.d(TAG, msg);
}
-
- private final Handler mHandler = new Handler(Looper.getMainLooper()) {
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case MESSAGE_HEADSET_SERVICE_CONNECTED: {
- if (mServiceListener != null) {
- mServiceListener.onServiceConnected(BluetoothProfile.HEADSET,
- BluetoothHeadset.this);
- }
- break;
- }
- case MESSAGE_HEADSET_SERVICE_DISCONNECTED: {
- if (mServiceListener != null) {
- mServiceListener.onServiceDisconnected(BluetoothProfile.HEADSET);
- }
- break;
- }
- }
- }
- };
}
diff --git a/core/java/android/bluetooth/BluetoothHeadsetClient.java b/core/java/android/bluetooth/BluetoothHeadsetClient.java
index ff4ebee..10d851f 100644
--- a/core/java/android/bluetooth/BluetoothHeadsetClient.java
+++ b/core/java/android/bluetooth/BluetoothHeadsetClient.java
@@ -100,7 +100,9 @@ public final class BluetoothHeadsetClient implements BluetoothProfile {
* {@link #EXTRA_BATTERY_LEVEL},
* {@link #EXTRA_OPERATOR_NAME},
* {@link #EXTRA_VOICE_RECOGNITION},
- * {@link #EXTRA_IN_BAND_RING}</p>
+ * {@link #EXTRA_IN_BAND_RING}
+ * {@link #EXTRA_MANF_ID}
+ * {@link #EXTRA_MANF_MODEL}</p>
*/
public static final String ACTION_AG_EVENT =
"android.bluetooth.headsetclient.profile.action.AG_EVENT";
@@ -206,6 +208,21 @@ public final class BluetoothHeadsetClient implements BluetoothProfile {
"android.bluetooth.headsetclient.extra.SUBSCRIBER_INFO";
/**
+ * Extra for AG_EVENT intent indicates manufacturer identification.
+ * <p>Value: <code>String</code> containing manufacturer identification.</p>
+ */
+ public static final String EXTRA_MANF_ID =
+ "android.bluetooth.headsetclient.extra.MANF_ID";
+
+ /**
+ * Extra for AG_EVENT intent indicates manufacturer model.
+ * <p>Value: <code>String</code> containing manufacturer model.</p>
+ */
+ public static final String EXTRA_MANF_MODEL =
+ "android.bluetooth.headsetclient.extra.MANF_MODEL";
+
+
+ /**
* Extra for AG_CALL_CHANGED intent indicates the
* {@link BluetoothHeadsetClientCall} object that has changed.
*/
diff --git a/core/java/android/bluetooth/BluetoothHidDevice.java b/core/java/android/bluetooth/BluetoothHidDevice.java
new file mode 100644
index 0000000..468df4d
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothHidDevice.java
@@ -0,0 +1,502 @@
+/*
+ * Copyright (C) 2013 The Linux Foundation. All rights reserved
+ * Not a Contribution.
+ * 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.bluetooth;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Log;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * @hide
+ */
+public final class BluetoothHidDevice implements BluetoothProfile {
+
+ private static final String TAG = BluetoothHidDevice.class.getSimpleName();
+
+ public static final String ACTION_CONNECTION_STATE_CHANGED =
+ "codeaurora.bluetooth.hid.profile.action.CONNECTION_STATE_CHANGED";
+
+ /**
+ * Constants representing device subclass.
+ *
+ * @see #registerApp(String, String, String, byte, byte[],
+ * BluetoothHidDeviceCallback)
+ */
+ public static final byte SUBCLASS1_NONE = (byte) 0x00;
+ public static final byte SUBCLASS1_KEYBOARD = (byte) 0x40;
+ public static final byte SUBCLASS1_MOUSE = (byte) 0x80;
+ public static final byte SUBCLASS1_COMBO = (byte) 0xC0;
+
+ public static final byte SUBCLASS2_UNCATEGORIZED = (byte) 0x00;
+ public static final byte SUBCLASS2_JOYSTICK = (byte) 0x01;
+ public static final byte SUBCLASS2_GAMEPAD = (byte) 0x02;
+ public static final byte SUBCLASS2_REMOTE_CONTROL = (byte) 0x03;
+ public static final byte SUBCLASS2_SENSING_DEVICE = (byte) 0x04;
+ public static final byte SUBCLASS2_DIGITIZER_TABLED = (byte) 0x05;
+ public static final byte SUBCLASS2_CARD_READER = (byte) 0x06;
+
+ /**
+ * Constants representing report types.
+ *
+ * @see BluetoothHidDeviceCallback#onGetReport(byte, byte, int)
+ * @see BluetoothHidDeviceCallback#onSetReport(byte, byte, byte[])
+ * @see BluetoothHidDeviceCallback#onIntrData(byte, byte[])
+ */
+ public static final byte REPORT_TYPE_INPUT = (byte) 1;
+ public static final byte REPORT_TYPE_OUTPUT = (byte) 2;
+ public static final byte REPORT_TYPE_FEATURE = (byte) 3;
+
+ /**
+ * Constants representing error response for Set Report.
+ *
+ * @see BluetoothHidDeviceCallback#onSetReport(byte, byte, byte[])
+ */
+ public static final byte ERROR_RSP_SUCCESS = (byte) 0;
+ public static final byte ERROR_RSP_NOT_READY = (byte) 1;
+ public static final byte ERROR_RSP_INVALID_RPT_ID = (byte) 2;
+ public static final byte ERROR_RSP_UNSUPPORTED_REQ = (byte) 3;
+ public static final byte ERROR_RSP_INVALID_PARAM = (byte) 4;
+ public static final byte ERROR_RSP_UNKNOWN = (byte) 14;
+
+ /**
+ * Constants representing protocol mode used set by host. Default is always
+ * {@link #PROTOCOL_REPORT_MODE} unless notified otherwise.
+ *
+ * @see BluetoothHidDeviceCallback#onSetProtocol(byte)
+ */
+ public static final byte PROTOCOL_BOOT_MODE = (byte) 0;
+ public static final byte PROTOCOL_REPORT_MODE = (byte) 1;
+
+ private Context mContext;
+
+ private ServiceListener mServiceListener;
+
+ private IBluetoothHidDevice mService;
+
+ private BluetoothAdapter mAdapter;
+
+ private static class BluetoothHidDeviceCallbackWrapper extends IBluetoothHidDeviceCallback.Stub {
+
+ private BluetoothHidDeviceCallback mCallback;
+
+ public BluetoothHidDeviceCallbackWrapper(BluetoothHidDeviceCallback callback) {
+ mCallback = callback;
+ }
+
+ @Override
+ public void onAppStatusChanged(BluetoothDevice pluggedDevice,
+ BluetoothHidDeviceAppConfiguration config, boolean registered) {
+ mCallback.onAppStatusChanged(pluggedDevice, config, registered);
+ }
+
+ @Override
+ public void onConnectionStateChanged(BluetoothDevice device, int state) {
+ mCallback.onConnectionStateChanged(device, state);
+ }
+
+ @Override
+ public void onGetReport(byte type, byte id, int bufferSize) {
+ mCallback.onGetReport(type, id, bufferSize);
+ }
+
+ @Override
+ public void onSetReport(byte type, byte id, byte[] data) {
+ mCallback.onSetReport(type, id, data);
+ }
+
+ @Override
+ public void onSetProtocol(byte protocol) {
+ mCallback.onSetProtocol(protocol);
+ }
+
+ @Override
+ public void onIntrData(byte reportId, byte[] data) {
+ mCallback.onIntrData(reportId, data);
+ }
+
+ @Override
+ public void onVirtualCableUnplug() {
+ mCallback.onVirtualCableUnplug();
+ }
+ }
+
+ final private IBluetoothStateChangeCallback mBluetoothStateChangeCallback =
+ new IBluetoothStateChangeCallback.Stub() {
+
+ public void onBluetoothStateChange(boolean up) {
+ Log.d(TAG, "onBluetoothStateChange: up=" + up);
+ synchronized (mConnection) {
+ if (!up) {
+ Log.d(TAG,"Unbinding service...");
+ if (mService != null) {
+ mService = null;
+ try {
+ mContext.unbindService(mConnection);
+ } catch (IllegalArgumentException e) {
+ Log.e(TAG,"onBluetoothStateChange: could not unbind service:", e);
+ }
+ }
+ } else {
+ try {
+ if (mService == null) {
+ Log.d(TAG,"Binding HID Device service...");
+ doBind();
+ }
+ } catch (IllegalStateException e) {
+ Log.e(TAG,"onBluetoothStateChange: could not bind to HID Dev service: ", e);
+ } catch (SecurityException e) {
+ Log.e(TAG,"onBluetoothStateChange: could not bind to HID Dev service: ", e);
+ }
+ }
+ }
+ }
+ };
+
+ private ServiceConnection mConnection = new ServiceConnection() {
+
+ public void onServiceConnected(ComponentName className, IBinder service) {
+ Log.d(TAG, "onServiceConnected()");
+
+ mService = IBluetoothHidDevice.Stub.asInterface(service);
+
+ if (mServiceListener != null) {
+ mServiceListener.onServiceConnected(BluetoothProfile.HID_DEVICE,
+ BluetoothHidDevice.this);
+ }
+ }
+
+ public void onServiceDisconnected(ComponentName className) {
+ Log.d(TAG, "onServiceDisconnected()");
+
+ mService = null;
+
+ if (mServiceListener != null) {
+ mServiceListener.onServiceDisconnected(BluetoothProfile.HID_DEVICE);
+ }
+ }
+ };
+
+ BluetoothHidDevice(Context context, ServiceListener listener) {
+ Log.v(TAG, "BluetoothHidDevice");
+
+ mContext = context;
+ mServiceListener = listener;
+ mAdapter = BluetoothAdapter.getDefaultAdapter();
+
+ IBluetoothManager mgr = mAdapter.getBluetoothManager();
+ if (mgr != null) {
+ try {
+ mgr.registerStateChangeCallback(mBluetoothStateChangeCallback);
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ }
+ }
+
+ doBind();
+ }
+
+ boolean doBind() {
+ Intent intent = new Intent(IBluetoothHidDevice.class.getName());
+ ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
+ intent.setComponent(comp);
+ if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0,
+ android.os.Process.myUserHandle())) {
+ Log.e(TAG, "Could not bind to Bluetooth HID Device Service with " + intent);
+ return false;
+ }
+ Log.d(TAG, "Bound to HID Device Service");
+ return true;
+ }
+
+ void close() {
+ Log.v(TAG, "close()");
+
+ IBluetoothManager mgr = mAdapter.getBluetoothManager();
+ if (mgr != null) {
+ try {
+ mgr.unregisterStateChangeCallback(mBluetoothStateChangeCallback);
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ }
+ }
+
+ synchronized (mConnection) {
+ if (mService != null) {
+ mService = null;
+ try {
+ mContext.unbindService(mConnection);
+ } catch (IllegalArgumentException e) {
+ Log.e(TAG,"close: could not unbind HID Dev service: ", e);
+ }
+ }
+ }
+
+ mServiceListener = null;
+ }
+
+ @Override
+ public List<BluetoothDevice> getConnectedDevices() {
+ Log.v(TAG, "getConnectedDevices()");
+ return null;
+ }
+
+ @Override
+ public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
+ Log.v(TAG, "getDevicesMatchingConnectionStates(): states=" + Arrays.toString(states));
+ return null;
+ }
+
+ @Override
+ public int getConnectionState(BluetoothDevice device) {
+ Log.v(TAG, "getConnectionState(): device=" + device.getAddress());
+
+ return STATE_DISCONNECTED;
+ }
+
+ /**
+ * Registers application to be used for HID device. Connections to HID
+ * Device are only possible when application is registered. Only one
+ * application can be registered at time. When no longer used, application
+ * should be unregistered using
+ * {@link #unregisterApp(BluetoothHidDeviceAppConfiguration)}.
+ *
+ * @param sdp {@link BluetoothHidDeviceAppSdpSettings} object of
+ * HID Device SDP record.
+ * @param inQos {@link BluetoothHidDeviceAppQosSettings} object of
+ * Incoming QoS Settings.
+ * @param outQos {@link BluetoothHidDeviceAppQosSettings} object of
+ * Outgoing QoS Settings.
+ * @param callback {@link BluetoothHidDeviceCallback} object to which
+ * callback messages will be sent.
+ * @return
+ */
+ public boolean registerApp(BluetoothHidDeviceAppSdpSettings sdp,
+ BluetoothHidDeviceAppQosSettings inQos, BluetoothHidDeviceAppQosSettings outQos,
+ BluetoothHidDeviceCallback callback) {
+ Log.v(TAG, "registerApp(): sdp=" + sdp + " inQos=" + inQos + " outQos=" + outQos
+ + " callback=" + callback);
+
+ boolean result = false;
+
+ if (sdp == null || callback == null) {
+ return false;
+ }
+
+ if (mService != null) {
+ try {
+ BluetoothHidDeviceAppConfiguration config =
+ new BluetoothHidDeviceAppConfiguration();
+ BluetoothHidDeviceCallbackWrapper cbw =
+ new BluetoothHidDeviceCallbackWrapper(callback);
+ result = mService.registerApp(config, sdp, inQos, outQos, cbw);
+ } catch (RemoteException e) {
+ Log.e(TAG, e.toString());
+ }
+ } else {
+ Log.w(TAG, "Proxy not attached to service");
+ }
+
+ return result;
+ }
+
+ /**
+ * Unregisters application. Active connection will be disconnected and no
+ * new connections will be allowed until registered again using
+ * {@link #registerApp(String, String, String, byte, byte[], BluetoothHidDeviceCallback)}
+ *
+ * @param config {@link BluetoothHidDeviceAppConfiguration} object as
+ * obtained from
+ * {@link BluetoothHidDeviceCallback#onAppStatusChanged(BluetoothDevice,
+ * BluetoothHidDeviceAppConfiguration, boolean)}
+ *
+ * @return
+ */
+ public boolean unregisterApp(BluetoothHidDeviceAppConfiguration config) {
+ Log.v(TAG, "unregisterApp()");
+
+ boolean result = false;
+
+ if (mService != null) {
+ try {
+ result = mService.unregisterApp(config);
+ } catch (RemoteException e) {
+ Log.e(TAG, e.toString());
+ }
+ } else {
+ Log.w(TAG, "Proxy not attached to service");
+ }
+
+ return result;
+ }
+
+ /**
+ * Sends report to remote host using interrupt channel.
+ *
+ * @param id Report Id, as defined in descriptor. Can be 0 in case Report Id
+ * are not defined in descriptor.
+ * @param data Report data, not including Report Id.
+ * @return
+ */
+ public boolean sendReport(int id, byte[] data) {
+ Log.v(TAG, "sendReport(): id=" + id);
+
+ boolean result = false;
+
+ if (mService != null) {
+ try {
+ result = mService.sendReport(id, data);
+ } catch (RemoteException e) {
+ Log.e(TAG, e.toString());
+ }
+ } else {
+ Log.w(TAG, "Proxy not attached to service");
+ }
+
+ return result;
+ }
+
+ /**
+ * Sends report to remote host as reply for GET_REPORT request from
+ * {@link BluetoothHidDeviceCallback#onGetReport(byte, byte, int)}.
+ *
+ * @param type Report Type, as in request.
+ * @param id Report Id, as in request.
+ * @param data Report data, not including Report Id.
+ * @return
+ */
+ public boolean replyReport(byte type, byte id, byte[] data) {
+ Log.v(TAG, "replyReport(): type=" + type + " id=" + id);
+
+ boolean result = false;
+
+ if (mService != null) {
+ try {
+ result = mService.replyReport(type, id, data);
+ } catch (RemoteException e) {
+ Log.e(TAG, e.toString());
+ }
+ } else {
+ Log.w(TAG, "Proxy not attached to service");
+ }
+
+ return result;
+ }
+
+ /**
+ * Sends error handshake message as reply for invalid SET_REPORT request
+ * from {@link BluetoothHidDeviceCallback#onSetReport(byte, byte, byte[])}.
+ *
+ * @param error Error to be sent for SET_REPORT via HANDSHAKE.
+ * @return
+ */
+ public boolean reportError(byte error) {
+ Log.v(TAG, "reportError(): error = " + error);
+
+ boolean result = false;
+
+ if (mService != null) {
+ try {
+ result = mService.reportError(error);
+ } catch (RemoteException e) {
+ Log.e(TAG, e.toString());
+ }
+ } else {
+ Log.w(TAG, "Proxy not attached to service");
+ }
+
+ return result;
+ }
+
+ /**
+ * Sends Virtual Cable Unplug to currently connected host.
+ *
+ * @return
+ */
+ public boolean unplug() {
+ Log.v(TAG, "unplug()");
+
+ boolean result = false;
+
+ if (mService != null) {
+ try {
+ result = mService.unplug();
+ } catch (RemoteException e) {
+ Log.e(TAG, e.toString());
+ }
+ } else {
+ Log.w(TAG, "Proxy not attached to service");
+ }
+
+ return result;
+ }
+
+ /**
+ * Initiates connection to host which currently has Virtual Cable
+ * established with device.
+ *
+ * @return
+ */
+ public boolean connect() {
+ Log.v(TAG, "connect()");
+
+ boolean result = false;
+
+ if (mService != null) {
+ try {
+ result = mService.connect();
+ } catch (RemoteException e) {
+ Log.e(TAG, e.toString());
+ }
+ } else {
+ Log.w(TAG, "Proxy not attached to service");
+ }
+
+ return result;
+ }
+
+ /**
+ * Disconnects from currently connected host.
+ *
+ * @return
+ */
+ public boolean disconnect() {
+ Log.v(TAG, "disconnect()");
+
+ boolean result = false;
+
+ if (mService != null) {
+ try {
+ result = mService.disconnect();
+ } catch (RemoteException e) {
+ Log.e(TAG, e.toString());
+ }
+ } else {
+ Log.w(TAG, "Proxy not attached to service");
+ }
+
+ return result;
+ }
+}
diff --git a/core/java/android/bluetooth/BluetoothHidDeviceAppConfiguration.aidl b/core/java/android/bluetooth/BluetoothHidDeviceAppConfiguration.aidl
new file mode 100644
index 0000000..1af309c
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothHidDeviceAppConfiguration.aidl
@@ -0,0 +1,21 @@
+/*
+** Copyright (C) 2013 The Linux Foundation. All rights reserved
+** Not a Contribution.
+** Copyright 2011, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package android.bluetooth;
+
+parcelable BluetoothHidDeviceAppConfiguration;
diff --git a/core/java/android/bluetooth/BluetoothHidDeviceAppConfiguration.java b/core/java/android/bluetooth/BluetoothHidDeviceAppConfiguration.java
new file mode 100644
index 0000000..9f3cd3c
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothHidDeviceAppConfiguration.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2013 The Linux Foundation. All rights reserved
+ * Not a Contribution.
+ * 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.bluetooth;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Random;
+
+/** @hide */
+public final class BluetoothHidDeviceAppConfiguration implements Parcelable {
+ private final long mHash;
+
+ BluetoothHidDeviceAppConfiguration() {
+ Random rnd = new Random();
+ mHash = rnd.nextLong();
+ }
+
+ BluetoothHidDeviceAppConfiguration(long hash) {
+ mHash = hash;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o instanceof BluetoothHidDeviceAppConfiguration) {
+ BluetoothHidDeviceAppConfiguration config = (BluetoothHidDeviceAppConfiguration) o;
+ return mHash == config.mHash;
+ }
+ return false;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ public static final Parcelable.Creator<BluetoothHidDeviceAppConfiguration> CREATOR =
+ new Parcelable.Creator<BluetoothHidDeviceAppConfiguration>() {
+
+ @Override
+ public BluetoothHidDeviceAppConfiguration createFromParcel(Parcel in) {
+ long hash = in.readLong();
+ return new BluetoothHidDeviceAppConfiguration(hash);
+ }
+
+ @Override
+ public BluetoothHidDeviceAppConfiguration[] newArray(int size) {
+ return new BluetoothHidDeviceAppConfiguration[size];
+ }
+ };
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeLong(mHash);
+ }
+}
diff --git a/core/java/android/bluetooth/BluetoothHidDeviceAppQosSettings.aidl b/core/java/android/bluetooth/BluetoothHidDeviceAppQosSettings.aidl
new file mode 100644
index 0000000..ae93235
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothHidDeviceAppQosSettings.aidl
@@ -0,0 +1,21 @@
+/*
+** Copyright (C) 2013 The Linux Foundation. All rights reserved
+** Not a Contribution.
+** Copyright 2011, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package android.bluetooth;
+
+parcelable BluetoothHidDeviceAppQosSettings;
diff --git a/core/java/android/bluetooth/BluetoothHidDeviceAppQosSettings.java b/core/java/android/bluetooth/BluetoothHidDeviceAppQosSettings.java
new file mode 100644
index 0000000..a4044d9
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothHidDeviceAppQosSettings.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2013 The Linux Foundation. All rights reserved
+ * Not a Contribution.
+ * 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.bluetooth;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Random;
+
+/** @hide */
+public final class BluetoothHidDeviceAppQosSettings implements Parcelable {
+
+ final public int serviceType;
+ final public int tokenRate;
+ final public int tokenBucketSize;
+ final public int peakBandwidth;
+ final public int latency;
+ final public int delayVariation;
+
+ final static public int SERVICE_NO_TRAFFIC = 0x00;
+ final static public int SERVICE_BEST_EFFORT = 0x01;
+ final static public int SERVICE_GUARANTEED = 0x02;
+
+ final static public int MAX = (int) 0xffffffff;
+
+ public BluetoothHidDeviceAppQosSettings(int serviceType, int tokenRate, int tokenBucketSize,
+ int peakBandwidth,
+ int latency, int delayVariation) {
+ this.serviceType = serviceType;
+ this.tokenRate = tokenRate;
+ this.tokenBucketSize = tokenBucketSize;
+ this.peakBandwidth = peakBandwidth;
+ this.latency = latency;
+ this.delayVariation = delayVariation;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o instanceof BluetoothHidDeviceAppQosSettings) {
+ BluetoothHidDeviceAppQosSettings qos = (BluetoothHidDeviceAppQosSettings) o;
+ return false;
+ }
+ return false;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ public static final Parcelable.Creator<BluetoothHidDeviceAppQosSettings> CREATOR =
+ new Parcelable.Creator<BluetoothHidDeviceAppQosSettings>() {
+
+ @Override
+ public BluetoothHidDeviceAppQosSettings createFromParcel(Parcel in) {
+
+ return new BluetoothHidDeviceAppQosSettings(in.readInt(), in.readInt(), in.readInt(),
+ in.readInt(),
+ in.readInt(), in.readInt());
+ }
+
+ @Override
+ public BluetoothHidDeviceAppQosSettings[] newArray(int size) {
+ return new BluetoothHidDeviceAppQosSettings[size];
+ }
+ };
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeInt(serviceType);
+ out.writeInt(tokenRate);
+ out.writeInt(tokenBucketSize);
+ out.writeInt(peakBandwidth);
+ out.writeInt(latency);
+ out.writeInt(delayVariation);
+ }
+
+ public int[] toArray() {
+ return new int[] {
+ serviceType, tokenRate, tokenBucketSize, peakBandwidth, latency, delayVariation
+ };
+ }
+}
diff --git a/core/java/android/bluetooth/BluetoothHidDeviceAppSdpSettings.aidl b/core/java/android/bluetooth/BluetoothHidDeviceAppSdpSettings.aidl
new file mode 100644
index 0000000..38ac1ec
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothHidDeviceAppSdpSettings.aidl
@@ -0,0 +1,21 @@
+/*
+** Copyright (C) 2013 The Linux Foundation. All rights reserved
+** Not a Contribution.
+** Copyright 2011, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package android.bluetooth;
+
+parcelable BluetoothHidDeviceAppSdpSettings;
diff --git a/core/java/android/bluetooth/BluetoothHidDeviceAppSdpSettings.java b/core/java/android/bluetooth/BluetoothHidDeviceAppSdpSettings.java
new file mode 100644
index 0000000..db88f0d
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothHidDeviceAppSdpSettings.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2013 The Linux Foundation. All rights reserved
+ * Not a Contribution.
+ * 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.bluetooth;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Random;
+
+/** @hide */
+public final class BluetoothHidDeviceAppSdpSettings implements Parcelable {
+
+ final public String name;
+ final public String description;
+ final public String provider;
+ final public byte subclass;
+ final public byte[] descriptors;
+
+ public BluetoothHidDeviceAppSdpSettings(String name, String description, String provider,
+ byte subclass, byte[] descriptors) {
+ this.name = name;
+ this.description = description;
+ this.provider = provider;
+ this.subclass = subclass;
+ this.descriptors = descriptors.clone();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o instanceof BluetoothHidDeviceAppSdpSettings) {
+ BluetoothHidDeviceAppSdpSettings sdp = (BluetoothHidDeviceAppSdpSettings) o;
+ return false;
+ }
+ return false;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ public static final Parcelable.Creator<BluetoothHidDeviceAppSdpSettings> CREATOR =
+ new Parcelable.Creator<BluetoothHidDeviceAppSdpSettings>() {
+
+ @Override
+ public BluetoothHidDeviceAppSdpSettings createFromParcel(Parcel in) {
+
+ return new BluetoothHidDeviceAppSdpSettings(in.readString(), in.readString(),
+ in.readString(), in.readByte(), in.createByteArray());
+ }
+
+ @Override
+ public BluetoothHidDeviceAppSdpSettings[] newArray(int size) {
+ return new BluetoothHidDeviceAppSdpSettings[size];
+ }
+ };
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeString(name);
+ out.writeString(description);
+ out.writeString(provider);
+ out.writeByte(subclass);
+ out.writeByteArray(descriptors);
+ }
+}
diff --git a/core/java/android/bluetooth/BluetoothHidDeviceCallback.java b/core/java/android/bluetooth/BluetoothHidDeviceCallback.java
new file mode 100644
index 0000000..cc60833
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothHidDeviceCallback.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2013 The Linux Foundation. All rights reserved
+ * Not a Contribution.
+ * 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.bluetooth;
+
+import android.util.Log;
+
+/** @hide */
+public abstract class BluetoothHidDeviceCallback {
+
+ private static final String TAG = BluetoothHidDeviceCallback.class.getSimpleName();
+
+ /**
+ * Callback called when application registration state changes. Usually it's
+ * called due to either
+ * {@link BluetoothHidDevice#registerApp(String, String, String, byte, byte[],
+ * BluetoothHidDeviceCallback)}
+ * or
+ * {@link BluetoothHidDevice#unregisterApp(BluetoothHidDeviceAppConfiguration)}
+ * , but can be also unsolicited in case e.g. Bluetooth was turned off in
+ * which case application is unregistered automatically.
+ *
+ * @param pluggedDevice {@link BluetoothDevice} object which represents host
+ * that currently has Virtual Cable established with device. Only
+ * valid when application is registered, can be <code>null</code>
+ * .
+ * @param config {@link BluetoothHidDeviceAppConfiguration} object which
+ * represents token required to unregister application using
+ * {@link BluetoothHidDevice#unregisterApp(BluetoothHidDeviceAppConfiguration)}
+ * .
+ * @param registered <code>true</code> if application is registered,
+ * <code>false</code> otherwise.
+ */
+ public void onAppStatusChanged(BluetoothDevice pluggedDevice,
+ BluetoothHidDeviceAppConfiguration config, boolean registered) {
+ Log.d(TAG, "onAppStatusChanged: pluggedDevice=" + (pluggedDevice == null ?
+ null : pluggedDevice.toString()) + " registered=" + registered);
+ }
+
+ /**
+ * Callback called when connection state with remote host was changed.
+ * Application can assume than Virtual Cable is established when called with
+ * {@link BluetoothProfile#STATE_CONNECTED} <code>state</code>.
+ *
+ * @param device {@link BluetoothDevice} object representing host device
+ * which connection state was changed.
+ * @param state Connection state as defined in {@link BluetoothProfile}.
+ */
+ public void onConnectionStateChanged(BluetoothDevice device, int state) {
+ Log.d(TAG, "onConnectionStateChanged: device=" + device.toString() + " state=" + state);
+ }
+
+ /**
+ * Callback called when GET_REPORT is received from remote host. Should be
+ * replied by application using
+ * {@link BluetoothHidDevice#replyReport(byte, byte, byte[])}.
+ *
+ * @param type Requested Report Type.
+ * @param id Requested Report Id, can be 0 if no Report Id are defined in
+ * descriptor.
+ * @param bufferSize Requested buffer size, application shall respond with
+ * at least given number of bytes.
+ */
+ public void onGetReport(byte type, byte id, int bufferSize) {
+ Log.d(TAG, "onGetReport: type=" + type + " id=" + id + " bufferSize=" + bufferSize);
+ }
+
+ /**
+ * Callback called when SET_REPORT is received from remote host. In case
+ * received data are invalid, application shall respond with
+ * {@link BluetoothHidDevice#reportError()}.
+ *
+ * @param type Report Type.
+ * @param id Report Id.
+ * @param data Report data.
+ */
+ public void onSetReport(byte type, byte id, byte[] data) {
+ Log.d(TAG, "onSetReport: type=" + type + " id=" + id);
+ }
+
+ /**
+ * Callback called when SET_PROTOCOL is received from remote host.
+ * Application shall use this information to send only reports valid for
+ * given protocol mode. By default,
+ * {@link BluetoothHidDevice#PROTOCOL_REPORT_MODE} shall be assumed.
+ *
+ * @param protocol Protocol Mode.
+ */
+ public void onSetProtocol(byte protocol) {
+ Log.d(TAG, "onSetProtocol: protocol=" + protocol);
+ }
+
+ /**
+ * Callback called when report data is received over interrupt channel.
+ * Report Type is assumed to be
+ * {@link BluetoothHidDevice#REPORT_TYPE_OUTPUT}.
+ *
+ * @param reportId Report Id.
+ * @param data Report data.
+ */
+ public void onIntrData(byte reportId, byte[] data) {
+ Log.d(TAG, "onIntrData: reportId=" + reportId);
+ }
+
+ /**
+ * Callback called when Virtual Cable is removed. This can be either due to
+ * {@link BluetoothHidDevice#unplug()} or request from remote side. After
+ * this callback is received connection will be disconnected automatically.
+ */
+ public void onVirtualCableUnplug() {
+ Log.d(TAG, "onVirtualCableUnplug");
+ }
+}
diff --git a/core/java/android/bluetooth/BluetoothInputDevice.java b/core/java/android/bluetooth/BluetoothInputDevice.java
index 252e3d2..db23ef5 100644
--- a/core/java/android/bluetooth/BluetoothInputDevice.java
+++ b/core/java/android/bluetooth/BluetoothInputDevice.java
@@ -96,6 +96,12 @@ public final class BluetoothInputDevice implements BluetoothProfile {
public static final String ACTION_VIRTUAL_UNPLUG_STATUS =
"android.bluetooth.input.profile.action.VIRTUAL_UNPLUG_STATUS";
+ /**
+ * @hide
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_IDLE_TIME_CHANGED =
+ "codeaurora.bluetooth.input.profile.action.IDLE_TIME_CHANGED";
/**
* Return codes for the connect and disconnect Bluez / Dbus calls.
@@ -199,6 +205,11 @@ public final class BluetoothInputDevice implements BluetoothProfile {
*/
public static final String EXTRA_VIRTUAL_UNPLUG_STATUS = "android.bluetooth.BluetoothInputDevice.extra.VIRTUAL_UNPLUG_STATUS";
+ /**
+ * @hide
+ */
+ public static final String EXTRA_IDLE_TIME = "codeaurora.bluetooth.BluetoothInputDevice.extra.IDLE_TIME";
+
private Context mContext;
private ServiceListener mServiceListener;
private BluetoothAdapter mAdapter;
@@ -658,6 +669,56 @@ public final class BluetoothInputDevice implements BluetoothProfile {
if (mService == null) Log.w(TAG, "Proxy not attached to service");
return false;
}
+
+ /**
+ * Send Get_Idle_Time command to the connected HID input device.
+ *
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
+ *
+ * @param device Remote Bluetooth Device
+ * @return false on immediate error,
+ * true otherwise
+ * @hide
+ */
+ public boolean getIdleTime(BluetoothDevice device) {
+ if (DBG) log("getIdletime(" + device + ")");
+ if (mService != null && isEnabled() && isValidDevice(device)) {
+ try {
+ return mService.getIdleTime(device);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return false;
+ }
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return false;
+ }
+
+ /**
+ * Send Set_Idle_Time command to the connected HID input device.
+ *
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
+ *
+ * @param device Remote Bluetooth Device
+ * @param idleTime Idle time to be set on HID Device
+ * @return false on immediate error,
+ * true otherwise
+ * @hide
+ */
+ public boolean setIdleTime(BluetoothDevice device, byte idleTime) {
+ if (DBG) log("setIdletime(" + device + "), idleTime=" + idleTime);
+ if (mService != null && isEnabled() && isValidDevice(device)) {
+ try {
+ return mService.setIdleTime(device, idleTime);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return false;
+ }
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return false;
+ }
+
private static void log(String msg) {
Log.d(TAG, msg);
}
diff --git a/core/java/android/bluetooth/BluetoothProfile.java b/core/java/android/bluetooth/BluetoothProfile.java
index cbce22c..9ef931e 100644
--- a/core/java/android/bluetooth/BluetoothProfile.java
+++ b/core/java/android/bluetooth/BluetoothProfile.java
@@ -131,6 +131,18 @@ public interface BluetoothProfile {
public static final int HEADSET_CLIENT = 16;
/**
+ * HID device
+ * @hide
+ */
+ public static final int HID_DEVICE = 17;
+
+ /**
+ * DUN
+ * @hide
+ */
+ public static final int DUN = 21;
+
+ /**
* Default priority for devices that we try to auto-connect to and
* and allow incoming connections for the profile
* @hide
diff --git a/core/java/android/bluetooth/BluetoothSocket.java b/core/java/android/bluetooth/BluetoothSocket.java
index fb81fd1..2eb4953 100644
--- a/core/java/android/bluetooth/BluetoothSocket.java
+++ b/core/java/android/bluetooth/BluetoothSocket.java
@@ -247,6 +247,7 @@ public final class BluetoothSocket implements Closeable {
as.mSocketOS = as.mSocket.getOutputStream();
as.mAddress = RemoteAddr;
as.mDevice = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(RemoteAddr);
+ as.mPort = mPort;
return as;
}
/**
@@ -468,6 +469,61 @@ public final class BluetoothSocket implements Closeable {
return acceptedSocket;
}
+ /**
+ * setSocketOpt for the Buetooth Socket.
+ *
+ * @param optionName socket option name
+ * @param optionVal socket option value
+ * @param optionLen socket option length
+ * @return -1 on immediate error,
+ * 0 otherwise
+ * @hide
+ */
+ public int setSocketOpt(int optionName, byte [] optionVal, int optionLen) throws IOException {
+ int ret = 0;
+ if (mSocketState == SocketState.CLOSED) throw new IOException("socket closed");
+ IBluetooth bluetoothProxy = BluetoothAdapter.getDefaultAdapter().getBluetoothService(null);
+ if (bluetoothProxy == null) {
+ Log.e(TAG, "setSocketOpt fail, reason: bluetooth is off");
+ return -1;
+ }
+ try {
+ if(VDBG) Log.d(TAG, "setSocketOpt(), mType: " + mType + " mPort: " + mPort);
+ ret = bluetoothProxy.setSocketOpt(mType, mPort, optionName, optionVal, optionLen);
+ } catch (RemoteException e) {
+ Log.e(TAG, Log.getStackTraceString(new Throwable()));
+ return -1;
+ }
+ return ret;
+ }
+
+ /**
+ * getSocketOpt for the Buetooth Socket.
+ *
+ * @param optionName socket option name
+ * @param optionVal socket option value
+ * @return -1 on immediate error,
+ * length of returned socket option otherwise
+ * @hide
+ */
+ public int getSocketOpt(int optionName, byte [] optionVal) throws IOException {
+ int ret = 0;
+ if (mSocketState == SocketState.CLOSED) throw new IOException("socket closed");
+ IBluetooth bluetoothProxy = BluetoothAdapter.getDefaultAdapter().getBluetoothService(null);
+ if (bluetoothProxy == null) {
+ Log.e(TAG, "getSocketOpt fail, reason: bluetooth is off");
+ return -1;
+ }
+ try {
+ if(VDBG) Log.d(TAG, "getSocketOpt(), mType: " + mType + " mPort: " + mPort);
+ ret = bluetoothProxy.getSocketOpt(mType, mPort, optionName, optionVal);
+ } catch (RemoteException e) {
+ Log.e(TAG, Log.getStackTraceString(new Throwable()));
+ return -1;
+ }
+ return ret;
+ }
+
/*package*/ int available() throws IOException {
if (VDBG) Log.d(TAG, "available: " + mSocketIS);
return mSocketIS.available();
diff --git a/core/java/android/bluetooth/IBluetooth.aidl b/core/java/android/bluetooth/IBluetooth.aidl
index 66f3418..2f1e8b4 100644
--- a/core/java/android/bluetooth/IBluetooth.aidl
+++ b/core/java/android/bluetooth/IBluetooth.aidl
@@ -70,6 +70,11 @@ interface IBluetooth
boolean fetchRemoteUuids(in BluetoothDevice device);
boolean sdpSearch(in BluetoothDevice device, in ParcelUuid uuid);
+ int createMapMnsSdpRecord(in String serviceName, in int rfcommChannel,
+ in int l2capPsm, in int version, in int features);
+ int createPbapPceSdpRecord(in String serviceName, in int version);
+ boolean removeSdpRecord(in int recordHandle);
+
boolean setPin(in BluetoothDevice device, boolean accept, int len, in byte[] pinCode);
boolean setPasskey(in BluetoothDevice device, boolean accept, int len, in byte[]
passkey);
@@ -106,4 +111,7 @@ interface IBluetooth
void dump(in ParcelFileDescriptor fd);
void onLeServiceUp();
void onBrEdrDown();
+
+ int setSocketOpt(int type, int port, int optionName, in byte [] optionVal, int optionLen);
+ int getSocketOpt(int type, int port, int optionName, out byte [] optionVal);
}
diff --git a/core/java/android/bluetooth/IBluetoothA2dpSink.aidl b/core/java/android/bluetooth/IBluetoothA2dpSink.aidl
index b7c6476..774a1ec 100644..100755
--- a/core/java/android/bluetooth/IBluetoothA2dpSink.aidl
+++ b/core/java/android/bluetooth/IBluetoothA2dpSink.aidl
@@ -30,5 +30,8 @@ interface IBluetoothA2dpSink {
List<BluetoothDevice> getConnectedDevices();
List<BluetoothDevice> getDevicesMatchingConnectionStates(in int[] states);
int getConnectionState(in BluetoothDevice device);
+ boolean setPriority(in BluetoothDevice device, int priority);
+ int getPriority(in BluetoothDevice device);
+ boolean isA2dpPlaying(in BluetoothDevice device);
BluetoothAudioConfig getAudioConfig(in BluetoothDevice device);
}
diff --git a/core/java/android/bluetooth/IBluetoothAvrcpController.aidl b/core/java/android/bluetooth/IBluetoothAvrcpController.aidl
index f917a50..fb61c98 100644
--- a/core/java/android/bluetooth/IBluetoothAvrcpController.aidl
+++ b/core/java/android/bluetooth/IBluetoothAvrcpController.aidl
@@ -1,4 +1,5 @@
/*
+ * Copyright (c) 2015, The Linux Foundation. All rights reserved.
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,6 +18,7 @@
package android.bluetooth;
import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothAvrcpInfo;
/**
* APIs for Bluetooth AVRCP controller service
@@ -28,4 +30,10 @@ interface IBluetoothAvrcpController {
List<BluetoothDevice> getDevicesMatchingConnectionStates(in int[] states);
int getConnectionState(in BluetoothDevice device);
void sendPassThroughCmd(in BluetoothDevice device, int keyCode, int keyState);
+ void getMetaData(in int[] attributeIds);
+ void getPlayStatus(in int[] playStatusIds);
+ void getPlayerApplicationSetting();
+ void setPlayerApplicationSetting(in int attributeId, in int attribVal);
+ BluetoothAvrcpInfo getSupportedPlayerAppSetting(in BluetoothDevice device);
+ int getSupportedFeatures(in BluetoothDevice device);
}
diff --git a/core/java/android/bluetooth/IBluetoothDun.aidl b/core/java/android/bluetooth/IBluetoothDun.aidl
new file mode 100644
index 0000000..a4f2017
--- /dev/null
+++ b/core/java/android/bluetooth/IBluetoothDun.aidl
@@ -0,0 +1,45 @@
+/*
+*Copyright (c) 2013, The Linux Foundation. All rights reserved.
+*
+*Redistribution and use in source and binary forms, with or without
+*modification, are permitted provided that the following conditions are
+*met:
+* * Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+* * Redistributions in binary form must reproduce the above
+* copyright notice, this list of conditions and the following
+* disclaimer in the documentation and/or other materials provided
+* with the distribution.
+* * Neither the name of The Linux Foundation nor the names of its
+* contributors may be used to endorse or promote products derived
+* from this software without specific prior written permission.
+*
+*THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+*WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+*MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+*ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+*BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+*CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+*SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+*BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+*WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+*OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+*IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+package android.bluetooth;
+
+import android.bluetooth.BluetoothDevice;
+
+/**
+ * API for Bluetooth Dun service
+ *
+ * {@hide}
+ */
+interface IBluetoothDun {
+ // Public API
+ boolean disconnect(in BluetoothDevice device);
+ int getConnectionState(in BluetoothDevice device);
+ List<BluetoothDevice> getConnectedDevices();
+ List<BluetoothDevice> getDevicesMatchingConnectionStates(in int[] states);
+}
diff --git a/core/java/android/bluetooth/IBluetoothHidDevice.aidl b/core/java/android/bluetooth/IBluetoothHidDevice.aidl
new file mode 100644
index 0000000..60358c5
--- /dev/null
+++ b/core/java/android/bluetooth/IBluetoothHidDevice.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2013 The Linux Foundation. All rights reserved
+ * Not a Contribution.
+ * Copyright (C) 2012 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.bluetooth;
+
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothHidDeviceAppConfiguration;
+import android.bluetooth.IBluetoothHidDeviceCallback;
+import android.bluetooth.BluetoothHidDeviceAppSdpSettings;
+import android.bluetooth.BluetoothHidDeviceAppQosSettings;
+
+/** @hide */
+interface IBluetoothHidDevice {
+ boolean registerApp(in BluetoothHidDeviceAppConfiguration config,
+ in BluetoothHidDeviceAppSdpSettings sdp, in BluetoothHidDeviceAppQosSettings inQos,
+ in BluetoothHidDeviceAppQosSettings outQos, in IBluetoothHidDeviceCallback callback);
+ boolean unregisterApp(in BluetoothHidDeviceAppConfiguration config);
+ boolean sendReport(in int id, in byte[] data);
+ boolean replyReport(in byte type, in byte id, in byte[] data);
+ boolean reportError(byte error);
+ boolean unplug();
+ boolean connect();
+ boolean disconnect();
+}
diff --git a/core/java/android/bluetooth/IBluetoothHidDeviceCallback.aidl b/core/java/android/bluetooth/IBluetoothHidDeviceCallback.aidl
new file mode 100644
index 0000000..7c71a17
--- /dev/null
+++ b/core/java/android/bluetooth/IBluetoothHidDeviceCallback.aidl
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2013 The Linux Foundation. All rights reserved
+ * Not a Contribution.
+ * 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.bluetooth;
+
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothHidDeviceAppConfiguration;
+
+/** @hide */
+interface IBluetoothHidDeviceCallback {
+ void onAppStatusChanged(in BluetoothDevice device, in BluetoothHidDeviceAppConfiguration config, boolean registered);
+ void onConnectionStateChanged(in BluetoothDevice device, in int state);
+ void onGetReport(in byte type, in byte id, in int bufferSize);
+ void onSetReport(in byte type, in byte id, in byte[] data);
+ void onSetProtocol(in byte protocol);
+ void onIntrData(in byte reportId, in byte[] data);
+ void onVirtualCableUnplug();
+}
diff --git a/core/java/android/bluetooth/IBluetoothInputDevice.aidl b/core/java/android/bluetooth/IBluetoothInputDevice.aidl
index 1ebb9ca..5bd3f78 100644
--- a/core/java/android/bluetooth/IBluetoothInputDevice.aidl
+++ b/core/java/android/bluetooth/IBluetoothInputDevice.aidl
@@ -56,4 +56,12 @@ interface IBluetoothInputDevice {
* @hide
*/
boolean sendData(in BluetoothDevice device, String report);
+ /**
+ * @hide
+ */
+ boolean getIdleTime(in BluetoothDevice device);
+ /**
+ * @hide
+ */
+ boolean setIdleTime(in BluetoothDevice device, byte idleTime);
}
diff --git a/core/java/android/bluetooth/IBluetoothManager.aidl b/core/java/android/bluetooth/IBluetoothManager.aidl
index 0b81ee8..bd8c6c9 100644
--- a/core/java/android/bluetooth/IBluetoothManager.aidl
+++ b/core/java/android/bluetooth/IBluetoothManager.aidl
@@ -19,7 +19,6 @@ package android.bluetooth;
import android.bluetooth.IBluetooth;
import android.bluetooth.IBluetoothGatt;
import android.bluetooth.IBluetoothManagerCallback;
-import android.bluetooth.IBluetoothProfileServiceConnection;
import android.bluetooth.IBluetoothStateChangeCallback;
/**
@@ -34,14 +33,11 @@ interface IBluetoothManager
void registerStateChangeCallback(in IBluetoothStateChangeCallback callback);
void unregisterStateChangeCallback(in IBluetoothStateChangeCallback callback);
boolean isEnabled();
- boolean enable();
+ boolean enable(String callingPackage);
boolean enableNoAutoConnect();
boolean disable(boolean persist);
IBluetoothGatt getBluetoothGatt();
- boolean bindBluetoothProfileService(int profile, IBluetoothProfileServiceConnection proxy);
- void unbindBluetoothProfileService(int profile, IBluetoothProfileServiceConnection proxy);
-
String getAddress();
String getName();
diff --git a/core/java/android/content/BroadcastReceiver.java b/core/java/android/content/BroadcastReceiver.java
index 2260d7e..bf0c48d 100644
--- a/core/java/android/content/BroadcastReceiver.java
+++ b/core/java/android/content/BroadcastReceiver.java
@@ -16,6 +16,7 @@
package android.content;
+import android.app.ActivityManager;
import android.app.ActivityManagerNative;
import android.app.ActivityThread;
import android.app.IActivityManager;
@@ -747,6 +748,17 @@ public abstract class BroadcastReceiver {
return mPendingResult.mSendingUser;
}
+ /** @hide */
+ public String getSendingPackage(Intent intent) {
+ final IActivityManager mgr = ActivityManagerNative.getDefault();
+ try {
+ boolean fg = (intent.getFlags() & Intent.FLAG_RECEIVER_FOREGROUND) != 0;
+ return mgr.getCallingPackageForBroadcast(fg);
+ } catch (RemoteException ex) {
+ return null;
+ }
+ }
+
/**
* Control inclusion of debugging help for mismatched
* calls to {@link Context#registerReceiver(BroadcastReceiver, IntentFilter)
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index 6ede29b..863ca65 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -431,6 +431,7 @@ public abstract class ContentResolver {
public final @Nullable Cursor query(@NonNull Uri uri, @Nullable String[] projection,
@Nullable String selection, @Nullable String[] selectionArgs,
@Nullable String sortOrder) {
+ android.util.SeempLog.record_uri(13, uri);
return query(uri, projection, selection, selectionArgs, sortOrder, null);
}
@@ -471,6 +472,7 @@ public abstract class ContentResolver {
public final @Nullable Cursor query(final @NonNull Uri uri, @Nullable String[] projection,
@Nullable String selection, @Nullable String[] selectionArgs,
@Nullable String sortOrder, @Nullable CancellationSignal cancellationSignal) {
+ android.util.SeempLog.record_uri(13, uri);
Preconditions.checkNotNull(uri, "uri");
IContentProvider unstableProvider = acquireUnstableProvider(uri);
if (unstableProvider == null) {
@@ -984,6 +986,7 @@ public abstract class ContentResolver {
stableProvider = acquireProvider(uri);
}
releaseUnstableProvider(unstableProvider);
+ unstableProvider = null;
ParcelFileDescriptor pfd = new ParcelFileDescriptorInner(
fd.getParcelFileDescriptor(), stableProvider);
@@ -1128,6 +1131,7 @@ public abstract class ContentResolver {
stableProvider = acquireProvider(uri);
}
releaseUnstableProvider(unstableProvider);
+ unstableProvider = null;
ParcelFileDescriptor pfd = new ParcelFileDescriptorInner(
fd.getParcelFileDescriptor(), stableProvider);
@@ -1221,6 +1225,7 @@ public abstract class ContentResolver {
* @return the URL of the newly created row.
*/
public final @Nullable Uri insert(@NonNull Uri url, @Nullable ContentValues values) {
+ android.util.SeempLog.record_uri(37, url);
Preconditions.checkNotNull(url, "url");
IContentProvider provider = acquireProvider(url);
if (provider == null) {
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 758b6ff..fc40a73 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -497,6 +497,9 @@ public abstract class Context {
@ViewDebug.ExportedProperty(deepExport = true)
public abstract Resources.Theme getTheme();
+ /** @hide */
+ public abstract void recreateTheme();
+
/**
* Retrieve styled attribute information in this Context's theme. See
* {@link android.content.res.Resources.Theme#obtainStyledAttributes(int[])}
@@ -3149,6 +3152,16 @@ public abstract class Context {
/**
* Use with {@link #getSystemService} to retrieve a
+ * {@link android.content.res.ThemeManager} for accessing theme service.
+ *
+ * @see #getSystemService
+ * @see android.content.res.ThemeManager
+ * @hide
+ */
+ public static final String THEME_SERVICE = "themes";
+
+ /**
+ * Use with {@link #getSystemService} to retrieve a
* {@link android.nfc.NfcManager} for using NFC.
*
* @see #getSystemService
@@ -3858,6 +3871,26 @@ public abstract class Context {
int flags) throws PackageManager.NameNotFoundException;
/**
+ * Similar to {@link #createPackageContext(String, int)}, but with a
+ * different {@link UserHandle}. For example, {@link #getContentResolver()}
+ * will open any {@link Uri} as the given user. A theme package can be
+ * specified which will be used when adding resources to this context
+ *
+ * @hide
+ */
+ public abstract Context createPackageContextAsUser(
+ String packageName, String themePackageName, int flags, UserHandle user)
+ throws PackageManager.NameNotFoundException;
+
+ /**
+ * Creates a context given an {@link android.content.pm.ApplicationInfo}.
+ *
+ * @hide
+ */
+ public abstract Context createApplicationContext(ApplicationInfo application,
+ String themePackageName, int flags) throws PackageManager.NameNotFoundException;
+
+ /**
* Get the userId associated with this context
* @return user id
*
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index 8359edf..795b9ae 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -123,6 +123,12 @@ public class ContextWrapper extends Context {
return mBase.getTheme();
}
+ /** @hide */
+ @Override
+ public void recreateTheme() {
+ mBase.recreateTheme();
+ }
+
@Override
public ClassLoader getClassLoader() {
return mBase.getClassLoader();
@@ -757,7 +763,20 @@ public class ContextWrapper extends Context {
@Override
public Context createApplicationContext(ApplicationInfo application,
int flags) throws PackageManager.NameNotFoundException {
- return mBase.createApplicationContext(application, flags);
+ return createApplicationContext(application, null, flags);
+ }
+
+ /** @hide */
+ public Context createApplicationContext(ApplicationInfo application,
+ String themePackageName, int flags) throws PackageManager.NameNotFoundException {
+ return mBase.createApplicationContext(application, themePackageName, flags);
+ }
+
+ /** @hide */
+ @Override
+ public Context createPackageContextAsUser(String packageName, String themePackageName,
+ int flags, UserHandle user) throws PackageManager.NameNotFoundException {
+ return mBase.createPackageContextAsUser(packageName, themePackageName, flags, user);
}
/** @hide */
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 87d52e4..2a24fe3 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2006 The Android Open Source Project
+ * This code has been modified. Portions copyright (C) 2010, T-Mobile USA, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -1800,6 +1801,15 @@ public class Intent implements Parcelable, Cloneable {
*/
public static final String ACTION_CLOSE_SYSTEM_DIALOGS = "android.intent.action.CLOSE_SYSTEM_DIALOGS";
/**
+ * Broadcast Action: Update preferences for the power menu dialog. This is to provide a
+ * way for the preferences that need to be enabled/disabled to update because they were
+ * toggled elsewhere in the settings (ie profiles, immersive desktop, etc) so we don't have
+ * to do constant lookups while we wait for the menu to be created. Getting the values once
+ * when necessary is enough.
+ *@hide
+ */
+ public static final String UPDATE_POWER_MENU = "android.intent.action.UPDATE_POWER_MENU";
+ /**
* Broadcast Action: Trigger the download and eventual installation
* of a package.
* <p>Input: {@link #getData} is the URI of the package file to download.
@@ -2075,6 +2085,15 @@ public class Intent implements Parcelable, Cloneable {
*/
@Deprecated @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_WALLPAPER_CHANGED = "android.intent.action.WALLPAPER_CHANGED";
+
+ /**
+ * Broadcast Action: The current keyguard wallpaper configuration
+ * has changed and should be re-read.
+ * {@hide}
+ */
+ public static final String ACTION_KEYGUARD_WALLPAPER_CHANGED =
+ "android.intent.action.KEYGUARD_WALLPAPER_CHANGED";
+
/**
* Broadcast Action: The current device {@link android.content.res.Configuration}
* (orientation, locale, etc) has changed. When such a change happens, the
@@ -2659,6 +2678,45 @@ public class Intent implements Parcelable, Cloneable {
"android.intent.action.GET_RESTRICTION_ENTRIES";
/**
+ * <p>Broadcast Action: The state of the HOTWORD audio input has changed.:</p>
+ * <ul>
+ * <li><em>state</em> - A String value indicating the state of the input.
+ * {@link #EXTRA_HOTWORD_INPUT_STATE}. The value will be one of:
+ * {@link android.media.AudioRecord#RECORDSTATE_RECORDING} or
+ * {@link android.media.AudioRecord#RECORDSTATE_STOPPED}.
+ * </li>
+ * <li><em>package</em> - A String value indicating the package name of the application
+ * that currently holds the HOTWORD input.
+ * {@link #EXTRA_CURRENT_PACKAGE_NAME}
+ * </li>
+ * </ul>
+ *
+ * <p class="note">This is a protected intent that can only be sent
+ * by the system. It can only be received by packages that hold
+ * {@link android.Manifest.permission#CAPTURE_AUDIO_HOTWORD}.
+ *
+ * @hide
+ */
+ //@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_HOTWORD_INPUT_CHANGED
+ = "com.cyanogenmod.intent.action.HOTWORD_INPUT_CHANGED";
+
+ /**
+ * @hide
+ * Activity to challenge the user for a PIN that was configured when setting up
+ * restrictions. Restrictions include blocking of apps and preventing certain user operations,
+ * controlled by {@link android.os.UserManager#setUserRestrictions(Bundle).
+ * Launch the activity using
+ * {@link android.app.Activity#startActivityForResult(Intent, int)} and check if the
+ * result is {@link android.app.Activity#RESULT_OK} for a successful response to the
+ * challenge.<p/>
+ * Before launching this activity, make sure that there is a PIN in effect, by calling
+ * {@link android.os.UserManager#hasRestrictionsChallenge()}.
+ */
+ public static final String ACTION_RESTRICTIONS_CHALLENGE =
+ "android.intent.action.RESTRICTIONS_CHALLENGE";
+
+ /**
* Sent the first time a user is starting, to allow system apps to
* perform one time initialization. (This will not be seen by third
* party applications because a newly initialized user does not have any
@@ -2823,6 +2881,21 @@ public class Intent implements Parcelable, Cloneable {
"android.intent.action.QUICK_CLOCK";
/**
+ * Broadcast Action: Indicate that unrecoverable error happened during app launch.
+ * Could indicate that curently applied theme is malicious.
+ * @hide
+ */
+ public static final String ACTION_APP_FAILURE =
+ "com.tmobile.intent.action.APP_FAILURE";
+
+ /**
+ * Broadcast Action: Request to reset the unrecoverable errors count to 0.
+ * @hide
+ */
+ public static final String ACTION_APP_FAILURE_RESET =
+ "com.tmobile.intent.action.APP_FAILURE_RESET";
+
+ /**
* Activity Action: Shows the brightness setting dialog.
* @hide
*/
@@ -2830,6 +2903,13 @@ public class Intent implements Parcelable, Cloneable {
"android.intent.action.SHOW_BRIGHTNESS_DIALOG";
/**
+ * Activity Action: Shows the notification brightness setting dialog.
+ * @hide
+ */
+ public static final String ACTION_SHOW_NOTIFICATION_BRIGHTNESS_DIALOG =
+ "android.intent.action.SHOW_NOTIFICATION_BRIGHTNESS_DIALOG";
+
+ /**
* Broadcast Action: A global button was pressed. Includes a single
* extra field, {@link #EXTRA_KEY_EVENT}, containing the key event that
* caused the broadcast.
@@ -2918,6 +2998,19 @@ public class Intent implements Parcelable, Cloneable {
public static final String ACTION_CREATE_DOCUMENT = "android.intent.action.CREATE_DOCUMENT";
/**
+ * Broadcast Action: A theme's resources were cached. Includes two extra fields,
+ * {@link #EXTRA_THEME_PACKAGE_NAME}, containing the package name of the theme that was
+ * processed, and {@link #EXTRA_THEME_RESULT}, containing the result code.
+ *
+ * <p class="note">This is a protected intent that can only be sent
+ * by the system.</p>
+ *
+ * @hide
+ */
+ public static final String ACTION_THEME_RESOURCES_CACHED =
+ "android.intent.action.THEME_RESOURCES_CACHED";
+
+ /**
* Activity Action: Allow the user to pick a directory subtree. When
* invoked, the system will display the various {@link DocumentsProvider}
* instances installed on the device, letting the user navigate through
@@ -2984,6 +3077,10 @@ public class Intent implements Parcelable, Cloneable {
public static final String EXTRA_PROCESS_TEXT_READONLY =
"android.intent.extra.PROCESS_TEXT_READONLY";
+ /** {@hide} */
+ public static final String ACTION_DOZE_PULSE_STARTING =
+ "android.intent.action.DOZE_PULSE_STARTING";
+
// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
// Standard intent categories (see addCategory()).
@@ -3185,6 +3282,14 @@ public class Intent implements Parcelable, Cloneable {
@SdkConstant(SdkConstantType.INTENT_CATEGORY)
public static final String CATEGORY_CAR_MODE = "android.intent.category.CAR_MODE";
+ /**
+ * Used to indicate that a theme package has been installed or un-installed.
+ *
+ * @hide
+ */
+ public static final String CATEGORY_THEME_PACKAGE_INSTALLED_STATE_CHANGE =
+ "com.tmobile.intent.category.THEME_PACKAGE_INSTALL_STATE_CHANGE";
+
// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
// Application launch intent categories (see addCategory()).
@@ -3795,6 +3900,42 @@ public class Intent implements Parcelable, Cloneable {
public static final String EXTRA_SIM_ACTIVATION_RESPONSE =
"android.intent.extra.SIM_ACTIVATION_RESPONSE";
+ /**
+ * Extra for {@link #ACTION_THEME_RESOURCES_CACHED} that provides the return value
+ * from processThemeResources. A value of 0 indicates a successful caching of resources.
+ * Error results are:
+ * {@link android.content.pm.PackageManager#INSTALL_FAILED_THEME_AAPT_ERROR}
+ * {@link android.content.pm.PackageManager#INSTALL_FAILED_THEME_IDMAP_ERROR}
+ * {@link android.content.pm.PackageManager#INSTALL_FAILED_THEME_UNKNOWN_ERROR}
+ *
+ * @hide
+ */
+ public static final String EXTRA_THEME_RESULT = "android.intent.extra.RESULT";
+
+ /**
+ * Extra for {@link #ACTION_THEME_RESOURCES_CACHED} that provides the package name of the
+ * theme that was processed.
+ *
+ * @hide
+ */
+ public static final String EXTRA_THEME_PACKAGE_NAME = "android.intent.extra.PACKAGE_NAME";
+
+ /**
+ * Extra for {@link #ACTION_HOTWORD_INPUT_CHANGED} that provides the state of
+ * the input when the broadcast action was sent.
+ * @hide
+ */
+ public static final String EXTRA_HOTWORD_INPUT_STATE =
+ "com.cyanogenmod.intent.extra.HOTWORD_INPUT_STATE";
+
+ /**
+ * Extra for {@link #ACTION_RECENTS_LONG_PRESS} that provides the package name of the
+ * app in foreground when recents was long pressed. Can be reused for other purposes.
+ * @hide
+ */
+ public static final String EXTRA_CURRENT_PACKAGE_NAME =
+ "com.cyanogenmod.intent.extra.CURRENT_PACKAGE_NAME";
+
// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
// Intent flags (see mFlags variable).
diff --git a/core/java/android/content/ThemeVersion.java b/core/java/android/content/ThemeVersion.java
new file mode 100644
index 0000000..05fbc41
--- /dev/null
+++ b/core/java/android/content/ThemeVersion.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2015 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.content;
+
+/**
+ * Warning: Careful moving/refactoring this class as our SDK references it.
+ * ThemeVersion 1 = CM11
+ * ThemeVersion 2 = CM12/CM12.1 First Release
+ * ThemeVersion 3 = CM12.1 W/ Wallpaper Packs
+ * @hide
+ */
+public class ThemeVersion {
+ /**
+ * Increment this anytime changes are made to:
+ * 1) Changes to ThemesContract
+ * 2) Changes to ThemeService API
+ * 3) Changes to ThemeManager API
+ */
+ public static int THEME_VERSION = 3;
+
+ /**
+ * Change this if a change to the contract or service would break compatibility.
+ * Example: A client app like chooser might be outdated from the framework.
+ * It could then query the FW for this value and determine whether its safe to proceed.
+ */
+ public static int MIN_SUPPORTED_THEME_VERSION = 2;
+
+ /**
+ * Do not change the order of this. See SDK.
+ * Increment the minSupportedVersion when the fw can no longer support a theme's apk structure
+ * Increment currentVersion when a change to the theme's apk structure is changed
+ * For example, CM11 to CM12 introduces new resources to overlay, so the overlays
+ * version should change. Because the changes are not compatible with CM11, the minVersion
+ * must change as well.
+ *
+ * If a new feature is added to a component (ex rotations in icon packs), the current version
+ * for the ICON component would be incremented. If a new component is created, then add it
+ * to the enum list.
+ *
+ * Wallpaper Version 2: Multi wallpaper ability
+ *
+ */
+ public static enum ComponentVersion {
+ OVERLAY(0, 2, 2),
+ BOOT_ANIM(1, 1, 1),
+ WALLPAPER(2, 1, 2),
+ LOCKSCREEN(3, 1, 1),
+ FONT(4, 1, 2),
+ ICON(5, 1, 1),
+ SOUNDS(6, 1, 1);
+
+ public int id;
+ public int minSupportedVersion;
+ public int currentVersion;
+
+ private ComponentVersion(int id, int minSupportedVersion, int currentVersion) {
+ this.id = id;
+ this.minSupportedVersion = minSupportedVersion;
+ this.currentVersion = currentVersion;
+ }
+ }
+}
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index e798eb8..0105e09 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2007 The Android Open Source Project
- *
+ * This code has been modified. Portions copyright (C) 2010, T-Mobile USA, Inc.
+
* 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
@@ -545,6 +546,16 @@ public class ActivityInfo extends ComponentInfo
*/
public static final int CONFIG_LAYOUT_DIRECTION = 0x2000;
/**
+ * Bit in {@link #configChanges} that indicates a theme change occurred
+ * @hide
+ */
+ public static final int CONFIG_THEME_RESOURCE = 0x100000;
+ /**
+ * Bit in {@link #configChanges} that indicates a font change occurred
+ * @hide
+ */
+ public static final int CONFIG_THEME_FONT = 0x200000;
+ /**
* Bit in {@link #configChanges} that indicates that the activity
* can itself handle changes to the font scaling factor. Set from the
* {@link android.R.attr#configChanges} attribute. This is
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 6feb860..1933fc9 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2007 The Android Open Source Project
+ * This code has been modified. Portions copyright (C) 2010, T-Mobile USA, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -654,6 +655,19 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
*/
public int installLocation = PackageInfo.INSTALL_LOCATION_UNSPECIFIED;
+ /**
+ * When true, indicates that any one component within this application is
+ * protected.
+ * @hide
+ */
+ public boolean protect = false;
+
+ /**
+ * Is given application theme agnostic, i.e. behaves properly when default theme is changed.
+ * @hide
+ */
+ public boolean isThemeable = false;
+
public void dump(Printer pw, String prefix) {
super.dumpFront(pw, prefix);
if (className != null) {
@@ -785,6 +799,8 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
uiOptions = orig.uiOptions;
backupAgentName = orig.backupAgentName;
fullBackupContent = orig.fullBackupContent;
+ protect = orig.protect;
+ isThemeable = orig.isThemeable;
}
@@ -838,6 +854,8 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
dest.writeInt(descriptionRes);
dest.writeInt(uiOptions);
dest.writeInt(fullBackupContent);
+ dest.writeInt(protect ? 1 : 0);
+ dest.writeInt(isThemeable ? 1 : 0);
}
public static final Parcelable.Creator<ApplicationInfo> CREATOR
@@ -890,6 +908,8 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
descriptionRes = source.readInt();
uiOptions = source.readInt();
fullBackupContent = source.readInt();
+ protect = source.readInt() != 0;
+ isThemeable = source.readInt() != 0;
}
/**
diff --git a/core/java/android/content/pm/BaseThemeInfo.java b/core/java/android/content/pm/BaseThemeInfo.java
new file mode 100644
index 0000000..8ece42d
--- /dev/null
+++ b/core/java/android/content/pm/BaseThemeInfo.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2010, T-Mobile USA, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.pm;
+
+import android.os.Parcelable;
+import android.os.Parcel;
+import android.util.Log;
+import android.util.AttributeSet;
+import android.content.res.Resources;
+
+/**
+ * @hide
+ */
+public class BaseThemeInfo implements Parcelable {
+ /**
+ * The theme id, which does not change when the theme is modified.
+ * Specifies an Android UI Style using style name.
+ *
+ * @see themeId attribute
+ *
+ */
+ public String themeId;
+
+ /**
+ * The name of the theme (as displayed by UI).
+ *
+ * @see name attribute
+ *
+ */
+ public String name;
+
+ /**
+ * The author name of the theme package.
+ *
+ * @see author attribute
+ *
+ */
+ public String author;
+
+ /*
+ * Describe the kinds of special objects contained in this Parcelable's
+ * marshalled representation.
+ *
+ * @return a bitmask indicating the set of special object types marshalled
+ * by the Parcelable.
+ *
+ * @see android.os.Parcelable#describeContents()
+ */
+ public int describeContents() {
+ return 0;
+ }
+
+ /*
+ * Flatten this object in to a Parcel.
+ *
+ * @param dest The Parcel in which the object should be written.
+ * @param flags Additional flags about how the object should be written.
+ * May be 0 or {@link #PARCELABLE_WRITE_RETURN_VALUE}.
+ *
+ * @see android.os.Parcelable#writeToParcel(android.os.Parcel, int)
+ */
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(themeId);
+ dest.writeString(name);
+ dest.writeString(author);
+ }
+
+ /** @hide */
+ public static final Parcelable.Creator<BaseThemeInfo> CREATOR
+ = new Parcelable.Creator<BaseThemeInfo>() {
+ public BaseThemeInfo createFromParcel(Parcel source) {
+ return new BaseThemeInfo(source);
+ }
+
+ public BaseThemeInfo[] newArray(int size) {
+ return new BaseThemeInfo[size];
+ }
+ };
+
+ /** @hide */
+ public final String getResolvedString(Resources res, AttributeSet attrs, int index) {
+ int resId = attrs.getAttributeResourceValue(index, 0);
+ if (resId !=0 ) {
+ return res.getString(resId);
+ }
+ return attrs.getAttributeValue(index);
+ }
+
+ protected BaseThemeInfo() {
+ }
+
+ protected BaseThemeInfo(Parcel source) {
+ themeId = source.readString();
+ name = source.readString();
+ author = source.readString();
+ }
+}
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index fec2c44..7c77f54 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -17,6 +17,7 @@
package android.content.pm;
+import android.app.ComposedIconInfo;
import android.content.ComponentName;
import android.content.Intent;
import android.content.IntentFilter;
@@ -509,4 +510,13 @@ interface IPackageManager {
boolean isPermissionRevokedByPolicy(String permission, String packageName, int userId);
String getPermissionControllerPackageName();
+
+ /** Protected Apps */
+ void setComponentProtectedSetting(in ComponentName componentName,
+ in boolean newState, int userId);
+
+ /** Themes */
+ void updateIconMapping(String pkgName);
+ ComposedIconInfo getComposedIconInfo();
+ int processThemeResources(String themePkgName);
}
diff --git a/core/java/android/content/pm/PackageInfo.java b/core/java/android/content/pm/PackageInfo.java
index 9e6c6b5..0de867e 100644
--- a/core/java/android/content/pm/PackageInfo.java
+++ b/core/java/android/content/pm/PackageInfo.java
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2007 The Android Open Source Project
+ * This code has been modified. Portions copyright (C) 2010, T-Mobile USA, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,6 +17,11 @@
package android.content.pm;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
import android.os.Parcel;
import android.os.Parcelable;
@@ -254,6 +260,34 @@ public class PackageInfo implements Parcelable {
/** @hide */
public boolean coreApp;
+ // Is Theme Apk
+ /**
+ * {@hide}
+ */
+ public boolean isThemeApk = false;
+
+ /**
+ * {@hide}
+ */
+ public boolean hasIconPack = false;
+
+ /**
+ * {@hide}
+ */
+ public ArrayList<String> mOverlayTargets;
+
+ // Is Legacy Icon Apk
+ /**
+ * {@hide}
+ */
+ public boolean isLegacyIconPackApk = false;
+
+ // ThemeInfo
+ /**
+ * {@hide}
+ */
+ public ThemeInfo themeInfo;
+
/** @hide */
public boolean requiredForAllUsers;
@@ -323,6 +357,13 @@ public class PackageInfo implements Parcelable {
dest.writeString(restrictedAccountType);
dest.writeString(requiredAccountType);
dest.writeString(overlayTarget);
+
+ /* Theme-specific. */
+ dest.writeInt((isThemeApk) ? 1 : 0);
+ dest.writeStringList(mOverlayTargets);
+ dest.writeParcelable(themeInfo, parcelableFlags);
+ dest.writeInt(hasIconPack ? 1 : 0);
+ dest.writeInt((isLegacyIconPackApk) ? 1 : 0);
}
public static final Parcelable.Creator<PackageInfo> CREATOR
@@ -372,5 +413,12 @@ public class PackageInfo implements Parcelable {
restrictedAccountType = source.readString();
requiredAccountType = source.readString();
overlayTarget = source.readString();
+
+ /* Theme-specific. */
+ isThemeApk = (source.readInt() != 0);
+ mOverlayTargets = source.createStringArrayList();
+ themeInfo = source.readParcelable(null);
+ hasIconPack = source.readInt() == 1;
+ isLegacyIconPackApk = source.readInt() == 1;
}
}
diff --git a/core/java/android/content/pm/PackageInfoLite.java b/core/java/android/content/pm/PackageInfoLite.java
index 1efe082..d4f33fb 100644
--- a/core/java/android/content/pm/PackageInfoLite.java
+++ b/core/java/android/content/pm/PackageInfoLite.java
@@ -62,6 +62,7 @@ public class PackageInfoLite implements Parcelable {
*/
public int recommendedInstallLocation;
public int installLocation;
+ public boolean isTheme;
public VerifierInfo[] verifiers;
@@ -87,6 +88,7 @@ public class PackageInfoLite implements Parcelable {
dest.writeInt(recommendedInstallLocation);
dest.writeInt(installLocation);
dest.writeInt(multiArch ? 1 : 0);
+ dest.writeInt(isTheme ? 1 : 0);
if (verifiers == null || verifiers.length == 0) {
dest.writeInt(0);
@@ -116,6 +118,7 @@ public class PackageInfoLite implements Parcelable {
recommendedInstallLocation = source.readInt();
installLocation = source.readInt();
multiArch = (source.readInt() != 0);
+ isTheme = source.readInt() == 1 ? true : false;
final int verifiersLength = source.readInt();
if (verifiersLength == 0) {
diff --git a/core/java/android/content/pm/PackageItemInfo.java b/core/java/android/content/pm/PackageItemInfo.java
index 22a899c..366deb4 100644
--- a/core/java/android/content/pm/PackageItemInfo.java
+++ b/core/java/android/content/pm/PackageItemInfo.java
@@ -66,7 +66,14 @@ public class PackageItemInfo {
* component's icon. From the "icon" attribute or, if not set, 0.
*/
public int icon;
-
+
+ /**
+ * A drawable resource identifier in the icon pack's resources
+ * If there isn't an icon pack or not set, then 0.
+ * @hide
+ */
+ public int themedIcon;
+
/**
* A drawable resource identifier (in the package's resources) of this
* component's banner. From the "banner" attribute or, if not set, 0.
@@ -110,6 +117,7 @@ public class PackageItemInfo {
logo = orig.logo;
metaData = orig.metaData;
showUserIcon = orig.showUserIcon;
+ themedIcon = orig.themedIcon;
}
/**
@@ -309,8 +317,9 @@ public class PackageItemInfo {
dest.writeBundle(metaData);
dest.writeInt(banner);
dest.writeInt(showUserIcon);
+ dest.writeInt(themedIcon);
}
-
+
protected PackageItemInfo(Parcel source) {
name = source.readString();
packageName = source.readString();
@@ -322,6 +331,7 @@ public class PackageItemInfo {
metaData = source.readBundle();
banner = source.readInt();
showUserIcon = source.readInt();
+ themedIcon = source.readInt();
}
/**
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index c8e9402..8928ad3 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -830,6 +830,51 @@ public abstract class PackageManager {
public static final int INSTALL_FAILED_ABORTED = -115;
/**
+ * Used by themes
+ * Installation failed return code: this is passed to the {@link IPackageInstallObserver} by
+ * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)}
+ * if the system failed to install the theme because aapt could not compile the app
+ * @hide
+ */
+ public static final int INSTALL_FAILED_THEME_AAPT_ERROR = -400;
+
+ /**
+ * Used by themes
+ * Installation failed return code: this is passed to the {@link IPackageInstallObserver} by
+ * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)}
+ * if the system failed to install the theme because idmap failed
+ * apps.
+ * @hide
+ */
+ public static final int INSTALL_FAILED_THEME_IDMAP_ERROR = -401;
+
+ /**
+ * Used by themes
+ * Installation failed return code: this is passed to the {@link IPackageInstallObserver} by
+ * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)}
+ * if the system failed to install the theme for an unknown reason
+ * apps.
+ * @hide
+ */
+ public static final int INSTALL_FAILED_THEME_UNKNOWN_ERROR = -402;
+
+ /**
+ * Used for prebundles
+ * Installation failed for a prebundled app because the user previously uninstalled it
+ * and we don't want to bring it back
+ * @hide
+ */
+ public static final int INSTALL_FAILED_UNINSTALLED_PREBUNDLE = -403;
+
+ /**
+ * Used for prebundles
+ * Installation failed for a prebundled app because it wasn't needed in the default
+ * mobile country exported by the hardware
+ * @hide
+ */
+ public static final int INSTALL_FAILED_REGION_LOCKED_PREBUNDLE = -404; //bloat not found
+
+ /**
* Flag parameter for {@link #deletePackage} to indicate that you don't want to delete the
* package's data directory.
*
@@ -1912,6 +1957,20 @@ public abstract class PackageManager {
= "android.content.pm.extra.REQUEST_PERMISSIONS_RESULTS";
/**
+ * Flag for {@link #setComponentProtectedSetting(android.content.ComponentName, boolean)}:
+ * This component or application has set to protected status
+ * @hide
+ */
+ public static final boolean COMPONENT_PROTECTED_STATUS = false;
+
+ /**
+ * Flag for {@link #setComponentProtectedSetting(android.content.ComponentName, boolean)}:
+ * This component or application has been explicitly set to visible status
+ * @hide
+ */
+ public static final boolean COMPONENT_VISIBLE_STATUS = true;
+
+ /**
* String extra for {@link PackageInstallObserver} in the 'extras' Bundle in case of
* {@link #INSTALL_FAILED_DUPLICATE_PERMISSION}. This extra names the package which provides
* the existing definition for the permission.
@@ -3511,6 +3570,18 @@ public abstract class PackageManager {
public abstract Resources getResourcesForApplicationAsUser(String appPackageName, int userId)
throws NameNotFoundException;
+ /** @hide */
+ public abstract Resources getThemedResourcesForApplication(ApplicationInfo app,
+ String themePkgName) throws NameNotFoundException;
+
+ /** @hide */
+ public abstract Resources getThemedResourcesForApplication(String appPackageName,
+ String themePkgName) throws NameNotFoundException;
+
+ /** @hide */
+ public abstract Resources getThemedResourcesForApplicationAsUser(String appPackageName,
+ String themePkgName, int userId) throws NameNotFoundException;
+
/**
* Retrieve overall information about an application package defined
* in a package archive file
@@ -4484,6 +4555,12 @@ public abstract class PackageManager {
public abstract @NonNull PackageInstaller getPackageInstaller();
/**
+ * Update Component protection state
+ * @hide
+ */
+ public abstract void setComponentProtectedSetting(ComponentName componentName, boolean newState);
+
+ /**
* Adds a {@link CrossProfileIntentFilter}. After calling this method all intents sent from the
* user with id sourceUserId can also be be resolved by activities in the user with id
* targetUserId if they match the specified intent filter.
@@ -4709,4 +4786,22 @@ public abstract class PackageManager {
}
}
}
+
+ /**
+ * Updates the theme icon res id for the new theme
+ * @hide
+ */
+ public abstract void updateIconMaps(String pkgName);
+
+ /**
+ * Used to compile theme resources for a given theme
+ * @param themePkgName
+ * @return A value of 0 indicates success. Possible errors returned are:
+ * {@link android.content.pm.PackageManager#INSTALL_FAILED_THEME_AAPT_ERROR},
+ * {@link android.content.pm.PackageManager#INSTALL_FAILED_THEME_IDMAP_ERROR}, or
+ * {@link android.content.pm.PackageManager#INSTALL_FAILED_THEME_UNKNOWN_ERROR}
+ *
+ * @hide
+ */
+ public abstract int processThemeResources(String themePkgName);
}
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 99bd390..dba6d56 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2007 The Android Open Source Project
+ * This code has been modified. Portions copyright (C) 2010, T-Mobile USA, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -61,6 +62,7 @@ import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import java.io.File;
+import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
@@ -77,12 +79,17 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
+import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicReference;
import java.util.jar.StrictJarFile;
import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
/**
* Parser for package files (APKs) on disk. This supports apps packaged either
@@ -112,6 +119,17 @@ public class PackageParser {
/** File name in an APK for the Android manifest. */
private static final String ANDROID_MANIFEST_FILENAME = "AndroidManifest.xml";
+ /** Path to overlay directory in a theme APK */
+ private static final String OVERLAY_PATH = "assets/overlays/";
+ /** Path to icon directory in a theme APK */
+ private static final String ICON_PATH = "assets/icons/";
+
+ private static final String PACKAGE_REDIRECTIONS_XML = "res/xml/redirections.xml";
+
+ private static final String TAG_PACKAGE_REDIRECTIONS = "package-redirections";
+ private static final String TAG_RESOURCE_REDIRECTIONS = "resource-redirections";
+ private static final String TAG_ITEM = "item";
+ private static final String ATTRIBUTE_ITEM_NAME = "name";
/** Path prefix for apps on expanded storage */
private static final String MNT_EXPAND = "/mnt/expand/";
@@ -251,6 +269,7 @@ public class PackageParser {
public final int versionCode;
public final int installLocation;
public final VerifierInfo[] verifiers;
+ public boolean isTheme;
/** Names of any split APKs, ordered by parsed splitName */
public final String[] splitNames;
@@ -276,6 +295,7 @@ public class PackageParser {
public final boolean multiArch;
public final boolean extractNativeLibs;
+
public PackageLite(String codePath, ApkLite baseApk, String[] splitNames,
String[] splitCodePaths, int[] splitRevisionCodes) {
this.packageName = baseApk.packageName;
@@ -291,6 +311,7 @@ public class PackageParser {
this.coreApp = baseApk.coreApp;
this.multiArch = baseApk.multiArch;
this.extractNativeLibs = baseApk.extractNativeLibs;
+ this.isTheme = baseApk.isTheme;
}
public List<String> getAllCodePaths() {
@@ -318,11 +339,12 @@ public class PackageParser {
public final boolean coreApp;
public final boolean multiArch;
public final boolean extractNativeLibs;
+ public final boolean isTheme;
public ApkLite(String codePath, String packageName, String splitName, int versionCode,
int revisionCode, int installLocation, List<VerifierInfo> verifiers,
Signature[] signatures, boolean coreApp, boolean multiArch,
- boolean extractNativeLibs) {
+ boolean extractNativeLibs, boolean isTheme) {
this.codePath = codePath;
this.packageName = packageName;
this.splitName = splitName;
@@ -334,6 +356,7 @@ public class PackageParser {
this.coreApp = coreApp;
this.multiArch = multiArch;
this.extractNativeLibs = extractNativeLibs;
+ this.isTheme = isTheme;
}
}
@@ -424,6 +447,14 @@ public class PackageParser {
pi.versionName = p.mVersionName;
pi.sharedUserId = p.mSharedUserId;
pi.sharedUserLabel = p.mSharedUserLabel;
+ pi.isThemeApk = p.mIsThemeApk;
+ pi.hasIconPack = p.hasIconPack;
+ pi.isLegacyIconPackApk = p.mIsLegacyIconPackApk;
+
+ if (pi.isThemeApk) {
+ pi.mOverlayTargets = p.mOverlayTargets;
+ pi.themeInfo = p.mThemeInfo;
+ }
pi.applicationInfo = generateApplicationInfo(p, flags, state, userId);
pi.installLocation = p.installLocation;
pi.coreApp = p.coreApp;
@@ -614,6 +645,7 @@ public class PackageParser {
public final static int PARSE_IS_PRIVILEGED = 1<<7;
public final static int PARSE_COLLECT_CERTIFICATES = 1<<8;
public final static int PARSE_TRUSTED_OVERLAY = 1<<9;
+ public final static int PARSE_IS_PREBUNDLED_DIR = 1<<10;
private static final Comparator<String> sSplitNameComparator = new SplitNameComparator();
@@ -898,6 +930,18 @@ public class PackageParser {
pkg.baseCodePath = apkPath;
pkg.mSignatures = null;
+ // If the pkg is a theme, we need to know what themes it overlays
+ // and determine if it has an icon pack
+ if (pkg.mIsThemeApk) {
+ //Determine existance of Overlays
+ ArrayList<String> overlayTargets = scanPackageOverlays(apkFile);
+ for(String overlay : overlayTargets) {
+ pkg.mOverlayTargets.add(overlay);
+ }
+
+ pkg.hasIconPack = packageHasIconPack(apkFile);
+ }
+
return pkg;
} catch (PackageParserException e) {
@@ -1020,6 +1064,68 @@ public class PackageParser {
return pkg;
}
+
+ private ArrayList<String> scanPackageOverlays(File originalFile) {
+ Set<String> overlayTargets = new HashSet<String>();
+ ZipFile privateZip = null;
+ try {
+ privateZip = new ZipFile(originalFile.getPath());
+ final Enumeration<? extends ZipEntry> privateZipEntries = privateZip.entries();
+ while (privateZipEntries.hasMoreElements()) {
+ final ZipEntry zipEntry = privateZipEntries.nextElement();
+ final String zipEntryName = zipEntry.getName();
+
+ if (zipEntryName.startsWith(OVERLAY_PATH) && zipEntryName.length() > 16) {
+ String[] subdirs = zipEntryName.split("/");
+ overlayTargets.add(subdirs[2]);
+ }
+ }
+ } catch(Exception e) {
+ e.printStackTrace();
+ overlayTargets.clear();
+ } finally {
+ if (privateZip != null) {
+ try {
+ privateZip.close();
+ } catch (Exception e) {
+ //Ignore
+ }
+ }
+ }
+
+ ArrayList<String> overlays = new ArrayList<String>();
+ overlays.addAll(overlayTargets);
+ return overlays;
+ }
+
+ private boolean packageHasIconPack(File originalFile) {
+ ZipFile privateZip = null;
+ try {
+ privateZip = new ZipFile(originalFile.getPath());
+ final Enumeration<? extends ZipEntry> privateZipEntries = privateZip.entries();
+ while (privateZipEntries.hasMoreElements()) {
+ final ZipEntry zipEntry = privateZipEntries.nextElement();
+ final String zipEntryName = zipEntry.getName();
+
+ if (zipEntryName.startsWith(ICON_PATH) &&
+ zipEntryName.length() > ICON_PATH.length()) {
+ return true;
+ }
+ }
+ } catch(Exception e) {
+ Log.e(TAG, "Could not read zip entries while checking if apk has icon pack", e);
+ } finally {
+ if (privateZip != null) {
+ try {
+ privateZip.close();
+ } catch (Exception e) {
+ //Ignore
+ }
+ }
+ }
+ return false;
+ }
+
/**
* Gathers the {@link ManifestDigest} for {@code pkg} if it exists in the
* APK. If it successfully scanned the package and found the
@@ -1035,6 +1141,7 @@ public class PackageParser {
final ZipEntry je = jarFile.findEntry(ANDROID_MANIFEST_FILENAME);
if (je != null) {
pkg.manifestDigest = ManifestDigest.fromInputStream(jarFile.getInputStream(je));
+ pkg.manifestHashCode = ThemeUtils.getPackageHashCode(pkg);
}
} finally {
jarFile.close();
@@ -1300,6 +1407,9 @@ public class PackageParser {
// Only search the tree when the tag is directly below <manifest>
int type;
final int searchDepth = parser.getDepth() + 1;
+ // Search for category and actions inside <intent-filter>
+ final int iconPackSearchDepth = parser.getDepth() + 4;
+ boolean isTheme = false;
final List<VerifierInfo> verifiers = new ArrayList<VerifierInfo>();
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
@@ -1326,11 +1436,53 @@ public class PackageParser {
}
}
}
+
+ if (parser.getDepth() == searchDepth && "meta-data".equals(parser.getName())) {
+ for (int i=0; i < parser.getAttributeCount(); i++) {
+ if ("name".equals(parser.getAttributeName(i)) &&
+ ThemeInfo.META_TAG_NAME.equals(parser.getAttributeValue(i))) {
+ isTheme = true;
+ installLocation = PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY;
+ break;
+ }
+ }
+ }
+
+ if (parser.getDepth() == searchDepth && "theme".equals(parser.getName())) {
+ isTheme = true;
+ installLocation = PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY;
+ }
+
+ if (parser.getDepth() == iconPackSearchDepth && isLegacyIconPack(parser)) {
+ isTheme = true;
+ installLocation = PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY;
+ }
}
return new ApkLite(codePath, packageSplit.first, packageSplit.second, versionCode,
revisionCode, installLocation, verifiers, signatures, coreApp, multiArch,
- extractNativeLibs);
+ extractNativeLibs, isTheme);
+ }
+
+ private static boolean isLegacyIconPack(XmlPullParser parser) {
+ boolean isAction = "action".equals(parser.getName());
+ boolean isCategory = "category".equals(parser.getName());
+ String[] items = isAction ? ThemeUtils.sSupportedActions
+ : (isCategory ? ThemeUtils.sSupportedCategories : null);
+
+ if (items != null) {
+ for (int i = 0; i < parser.getAttributeCount(); i++) {
+ if ("name".equals(parser.getAttributeName(i))) {
+ final String value = parser.getAttributeValue(i);
+ for (String item : items) {
+ if (item.equals(value)) {
+ return true;
+ }
+ }
+ }
+ }
+ }
+ return false;
}
/**
@@ -1382,6 +1534,8 @@ public class PackageParser {
}
final Package pkg = new Package(pkgName);
+ Bundle metaDataBundle = new Bundle();
+
boolean foundApp = false;
TypedArray sa = res.obtainAttributes(attrs,
@@ -1794,6 +1948,11 @@ public class PackageParser {
XmlUtils.skipCurrentTag(parser);
continue;
+ } else if (parser.getName().equals("meta-data")) {
+ if ((metaDataBundle=parseMetaData(res, parser, attrs, metaDataBundle,
+ outError)) == null) {
+ return null;
+ }
} else if (RIGID_PARSER) {
outError[0] = "Bad element under <manifest>: "
+ parser.getName();
@@ -1882,6 +2041,17 @@ public class PackageParser {
>= android.os.Build.VERSION_CODES.DONUT)) {
pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES;
}
+ if (pkg.mIsThemeApk || pkg.mIsLegacyIconPackApk) {
+ pkg.applicationInfo.isThemeable = false;
+ }
+
+ //Is this pkg a theme?
+ if (metaDataBundle.containsKey(ThemeInfo.META_TAG_NAME)) {
+ pkg.mIsThemeApk = true;
+ pkg.mTrustedOverlay = true;
+ pkg.mOverlayPriority = 1;
+ pkg.mThemeInfo = new ThemeInfo(metaDataBundle);
+ }
return pkg;
}
@@ -2257,6 +2427,10 @@ public class PackageParser {
perm.info.flags = sa.getInt(
com.android.internal.R.styleable.AndroidManifestPermission_permissionFlags, 0);
+ perm.info.allowViaWhitelist = sa.getBoolean(
+ com.android.internal.R.styleable.AndroidManifestPermission_allowViaWhitelist,
+ false);
+
sa.recycle();
if (perm.info.protectionLevel == -1) {
@@ -2409,6 +2583,10 @@ public class PackageParser {
final ApplicationInfo ai = owner.applicationInfo;
final String pkgName = owner.applicationInfo.packageName;
+ String[] nonThemeablePackages =
+ res.getStringArray(com.android.internal.R.array.non_themeable_packages);
+ ai.isThemeable = isPackageThemeable(pkgName, nonThemeablePackages);
+
TypedArray sa = res.obtainAttributes(attrs,
com.android.internal.R.styleable.AndroidManifestApplication);
@@ -3238,6 +3416,26 @@ public class PackageParser {
if (!parseIntent(res, parser, attrs, true, true, intent, outError)) {
return null;
}
+
+ // Check if package is a legacy icon pack
+ if (!owner.mIsLegacyIconPackApk) {
+ for(String action : ThemeUtils.sSupportedActions) {
+ if (intent.hasAction(action)) {
+ owner.mIsLegacyIconPackApk = true;
+ break;
+ }
+
+ }
+ }
+ if (!owner.mIsLegacyIconPackApk) {
+ for(String category : ThemeUtils.sSupportedCategories) {
+ if (intent.hasCategory(category)) {
+ owner.mIsLegacyIconPackApk = true;
+ break;
+ }
+ }
+ }
+
if (intent.countActions() == 0) {
Slog.w(TAG, "No actions in intent filter at "
+ mArchiveSourcePath + " "
@@ -4247,6 +4445,22 @@ public class PackageParser {
return true;
}
+ /**1
+ * Returns whether the specified package is themeable
+ * @param packageName Name of package to check
+ * @param nonThemeablePackages Array of packages that are declared as non-themeable
+ * @return True if the package is themeable, false otherwise
+ */
+ private static boolean isPackageThemeable(String packageName, String[] nonThemeablePackages) {
+ for (String pkg : nonThemeablePackages) {
+ if (packageName.startsWith(pkg)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
/**
* Representation of a full package parsed from APK files on disk. A package
* consists of a single base APK, and zero or more split APKs.
@@ -4345,6 +4559,17 @@ public class PackageParser {
// For use by package manager to keep track of when a package was last used.
public long mLastPackageUsageTimeInMills;
+ // Is Theme Apk
+ public boolean mIsThemeApk = false;
+ public final ArrayList<String> mOverlayTargets = new ArrayList<String>(0);
+ public Map<String, Map<String, String>> mPackageRedirections
+ = new HashMap<String, Map<String, String>>();
+
+ // Theme info
+ public ThemeInfo mThemeInfo = null;
+
+ // Legacy icon pack
+ public boolean mIsLegacyIconPackApk = false;
// // User set enabled state.
// public int mSetEnabled = PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
@@ -4387,6 +4612,9 @@ public class PackageParser {
public int mOverlayPriority;
public boolean mTrustedOverlay;
+ public boolean hasIconPack;
+ public int manifestHashCode;
+
/**
* Data used to feed the KeySetManagerService
*/
@@ -4739,6 +4967,12 @@ public class PackageParser {
&& p.usesLibraryFiles != null) {
return true;
}
+ if (state.protectedComponents != null) {
+ boolean protect = state.protectedComponents.size() > 0;
+ if (p.applicationInfo.protect != protect) {
+ return true;
+ }
+ }
return false;
}
@@ -4772,6 +5006,9 @@ public class PackageParser {
ai.enabled = false;
}
ai.enabledSetting = state.enabled;
+ if (state.protectedComponents != null) {
+ ai.protect = state.protectedComponents.size() > 0;
+ }
}
public static ApplicationInfo generateApplicationInfo(Package p, int flags,
diff --git a/core/java/android/content/pm/PackageUserState.java b/core/java/android/content/pm/PackageUserState.java
index 9b28401..7b6d188 100644
--- a/core/java/android/content/pm/PackageUserState.java
+++ b/core/java/android/content/pm/PackageUserState.java
@@ -36,6 +36,8 @@ public class PackageUserState {
public ArraySet<String> disabledComponents;
public ArraySet<String> enabledComponents;
+ public ArraySet<String> protectedComponents;
+ public ArraySet<String> visibleComponents;
public int domainVerificationStatus;
public int appLinkGeneration;
@@ -62,5 +64,9 @@ public class PackageUserState {
blockUninstall = o.blockUninstall;
domainVerificationStatus = o.domainVerificationStatus;
appLinkGeneration = o.appLinkGeneration;
+ protectedComponents = o.protectedComponents != null
+ ? new ArraySet<String>(o.protectedComponents) : null;
+ visibleComponents = o.visibleComponents != null
+ ? new ArraySet<String>(o.visibleComponents) : null;
}
}
diff --git a/core/java/android/content/pm/PermissionInfo.java b/core/java/android/content/pm/PermissionInfo.java
index 9da2ba9..0fed65f 100644
--- a/core/java/android/content/pm/PermissionInfo.java
+++ b/core/java/android/content/pm/PermissionInfo.java
@@ -178,6 +178,14 @@ public class PermissionInfo extends PackageItemInfo implements Parcelable {
*/
public CharSequence nonLocalizedDescription;
+ /**
+ * Whether this permission will be granted to apps signed with white-listed keys in
+ * /system/etc/permissions/someapp.xml
+ *
+ * @hide
+ */
+ public boolean allowViaWhitelist;
+
/** @hide */
public static int fixProtectionLevel(int level) {
if (level == PROTECTION_SIGNATURE_OR_SYSTEM) {
@@ -237,6 +245,7 @@ public class PermissionInfo extends PackageItemInfo implements Parcelable {
group = orig.group;
descriptionRes = orig.descriptionRes;
nonLocalizedDescription = orig.nonLocalizedDescription;
+ allowViaWhitelist = orig.allowViaWhitelist;
}
/**
@@ -279,6 +288,7 @@ public class PermissionInfo extends PackageItemInfo implements Parcelable {
dest.writeInt(flags);
dest.writeString(group);
dest.writeInt(descriptionRes);
+ dest.writeInt(allowViaWhitelist ? 1 : 0);
TextUtils.writeToParcel(nonLocalizedDescription, dest, parcelableFlags);
}
@@ -298,6 +308,7 @@ public class PermissionInfo extends PackageItemInfo implements Parcelable {
flags = source.readInt();
group = source.readString();
descriptionRes = source.readInt();
+ allowViaWhitelist = source.readInt() == 1;
nonLocalizedDescription = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source);
}
}
diff --git a/core/java/android/content/pm/ThemeInfo.aidl b/core/java/android/content/pm/ThemeInfo.aidl
new file mode 100644
index 0000000..acbc85e
--- /dev/null
+++ b/core/java/android/content/pm/ThemeInfo.aidl
@@ -0,0 +1,3 @@
+package android.content.pm;
+
+parcelable ThemeInfo;
diff --git a/core/java/android/content/pm/ThemeInfo.java b/core/java/android/content/pm/ThemeInfo.java
new file mode 100644
index 0000000..ab798db
--- /dev/null
+++ b/core/java/android/content/pm/ThemeInfo.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2010, T-Mobile USA, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.pm;
+
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlPullParser;
+
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.AttributeSet;
+import android.content.res.Resources;
+
+/**
+ * Overall information about "theme" package. This corresponds
+ * to the information collected from AndroidManifest.xml
+ *
+ * Below is an example of the manifest:
+ *
+ * <meta-data android:name="org.cyanogenmod.theme.name" android:value="Foobar's Theme"/>
+ * <meta-data android:name="org.cyanogenmod.theme.author" android:value="Mr.Foo" />
+ *
+ * @hide
+ */
+public final class ThemeInfo extends BaseThemeInfo {
+
+ public static final String META_TAG_NAME = "org.cyanogenmod.theme.name";
+ public static final String META_TAG_AUTHOR = "org.cyanogenmod.theme.author";
+
+ public ThemeInfo(Bundle bundle) {
+ super();
+ name = bundle.getString(META_TAG_NAME);
+ themeId = name;
+ author = bundle.getString(META_TAG_AUTHOR);
+ }
+
+ public static final Parcelable.Creator<ThemeInfo> CREATOR
+ = new Parcelable.Creator<ThemeInfo>() {
+ public ThemeInfo createFromParcel(Parcel source) {
+ return new ThemeInfo(source);
+ }
+
+ public ThemeInfo[] newArray(int size) {
+ return new ThemeInfo[size];
+ }
+ };
+
+ private ThemeInfo(Parcel source) {
+ super(source);
+ }
+}
diff --git a/core/java/android/content/pm/ThemeUtils.java b/core/java/android/content/pm/ThemeUtils.java
new file mode 100644
index 0000000..357b372
--- /dev/null
+++ b/core/java/android/content/pm/ThemeUtils.java
@@ -0,0 +1,735 @@
+/*
+ * Copyright (C) 2014 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.content.pm;
+
+import android.content.BroadcastReceiver;
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.content.IntentFilter;
+import android.content.res.AssetManager;
+import android.content.res.Configuration;
+import android.content.res.ThemeConfig;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+import android.media.RingtoneManager;
+import android.net.Uri;
+import android.os.FileUtils;
+import android.os.SystemProperties;
+import android.provider.MediaStore;
+import android.provider.Settings;
+import android.provider.ThemesContract;
+import android.provider.ThemesContract.ThemesColumns;
+import android.text.TextUtils;
+import android.util.DisplayMetrics;
+import android.util.Log;
+import android.view.WindowManager;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.InputStreamReader;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.zip.CRC32;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
+import java.util.zip.ZipOutputStream;
+
+import static android.content.res.ThemeConfig.SYSTEM_DEFAULT;
+
+/**
+ * @hide
+ */
+public class ThemeUtils {
+ private static final String TAG = "ThemeUtils";
+
+ /* Path inside a theme APK to the overlay folder */
+ public static final String OVERLAY_PATH = "assets/overlays/";
+ public static final String ICONS_PATH = "assets/icons/";
+ public static final String COMMON_RES_PATH = "assets/overlays/common/";
+ public static final String FONT_XML = "fonts.xml";
+ public static final String RESOURCE_CACHE_DIR = "/data/resource-cache/";
+ public static final String IDMAP_SUFFIX = "@idmap";
+ public static final String COMMON_RES_SUFFIX = ".common";
+ public static final String COMMON_RES_TARGET = "common";
+ public static final String ICON_HASH_FILENAME = "hash";
+
+ // path to external theme resources, i.e. bootanimation.zip
+ public static final String SYSTEM_THEME_PATH = "/data/system/theme";
+ public static final String SYSTEM_THEME_FONT_PATH = SYSTEM_THEME_PATH + File.separator + "fonts";
+ public static final String SYSTEM_THEME_RINGTONE_PATH = SYSTEM_THEME_PATH
+ + File.separator + "ringtones";
+ public static final String SYSTEM_THEME_NOTIFICATION_PATH = SYSTEM_THEME_PATH
+ + File.separator + "notifications";
+ public static final String SYSTEM_THEME_ALARM_PATH = SYSTEM_THEME_PATH
+ + File.separator + "alarms";
+ public static final String SYSTEM_THEME_ICON_CACHE_DIR = SYSTEM_THEME_PATH
+ + File.separator + "icons";
+ // internal path to bootanimation.zip inside theme apk
+ public static final String THEME_BOOTANIMATION_PATH = "assets/bootanimation/bootanimation.zip";
+
+ public static final String SYSTEM_MEDIA_PATH = "/system/media/audio";
+ public static final String SYSTEM_ALARMS_PATH = SYSTEM_MEDIA_PATH + File.separator
+ + "alarms";
+ public static final String SYSTEM_RINGTONES_PATH = SYSTEM_MEDIA_PATH + File.separator
+ + "ringtones";
+ public static final String SYSTEM_NOTIFICATIONS_PATH = SYSTEM_MEDIA_PATH + File.separator
+ + "notifications";
+
+ // path to asset lockscreen and wallpapers directory
+ public static final String LOCKSCREEN_WALLPAPER_PATH = "lockscreen";
+ public static final String WALLPAPER_PATH = "wallpapers";
+
+ private static final String MEDIA_CONTENT_URI = "content://media/internal/audio/media";
+
+ // Constants for theme change broadcast
+ public static final String ACTION_THEME_CHANGED = "org.cyanogenmod.intent.action.THEME_CHANGED";
+ public static final String CATEGORY_THEME_COMPONENT_PREFIX = "org.cyanogenmod.intent.category.";
+ public static final String EXTRA_COMPONENTS = "components";
+ public static final String EXTRA_REQUEST_TYPE = "request_type";
+ public static final String EXTRA_UPDATE_TIME = "update_time";
+
+ public static final int SYSTEM_TARGET_API = 0;
+
+ // Package name for any app which does not have a specific theme applied
+ private static final String DEFAULT_PKG = "default";
+
+ private static final String SETTINGS_DB =
+ "/data/data/com.android.providers.settings/databases/settings.db";
+ private static final String SETTINGS_SECURE_TABLE = "secure";
+
+ /**
+ * IDMAP hash version code used to alter the resulting hash and force recreating
+ * of the idmap. This value should be changed whenever there is a need to force
+ * an update to all idmaps.
+ */
+ private static final byte IDMAP_HASH_VERSION = 3;
+
+ // Actions in manifests which identify legacy icon packs
+ public static final String[] sSupportedActions = new String[] {
+ "org.adw.launcher.THEMES",
+ "com.gau.go.launcherex.theme",
+ "com.novalauncher.THEME"
+ };
+
+ // Categories in manifests which identify legacy icon packs
+ public static final String[] sSupportedCategories = new String[] {
+ "com.fede.launcher.THEME_ICONPACK",
+ "com.anddoes.launcher.THEME",
+ "com.teslacoilsw.launcher.THEME"
+ };
+
+
+ /**
+ * Get the root path of the resource cache for the given theme
+ * @param themePkgName
+ * @return Root resource cache path for the given theme
+ */
+ public static String getOverlayResourceCacheDir(String themePkgName) {
+ return RESOURCE_CACHE_DIR + themePkgName;
+ }
+
+ /**
+ * Get the path of the resource cache for the given target and theme
+ * @param targetPkgName
+ * @param themePkg
+ * @return Path to the resource cache for this target and theme
+ */
+ public static String getTargetCacheDir(String targetPkgName, PackageInfo themePkg) {
+ return getTargetCacheDir(targetPkgName, themePkg.packageName);
+ }
+
+ public static String getTargetCacheDir(String targetPkgName, PackageParser.Package themePkg) {
+ return getTargetCacheDir(targetPkgName, themePkg.packageName);
+ }
+
+ public static String getTargetCacheDir(String targetPkgName, String themePkgName) {
+ return getOverlayResourceCacheDir(themePkgName) + File.separator + targetPkgName;
+ }
+
+ /**
+ * Get the path to the icons for the given theme
+ * @param pkgName
+ * @return
+ */
+ public static String getIconPackDir(String pkgName) {
+ return getOverlayResourceCacheDir(pkgName) + File.separator + "icons";
+ }
+
+ public static String getIconHashFile(String pkgName) {
+ return getIconPackDir(pkgName) + File.separator + ICON_HASH_FILENAME;
+ }
+
+ public static String getIconPackApkPath(String pkgName) {
+ return getIconPackDir(pkgName) + "/resources.apk";
+ }
+
+ public static String getIconPackResPath(String pkgName) {
+ return getIconPackDir(pkgName) + "/resources.arsc";
+ }
+
+ public static String getIdmapPath(String targetPkgName, String overlayPkgName) {
+ return getTargetCacheDir(targetPkgName, overlayPkgName) + File.separator + "idmap";
+ }
+
+ public static String getOverlayPathToTarget(String targetPkgName) {
+ StringBuilder sb = new StringBuilder();
+ sb.append(OVERLAY_PATH);
+ sb.append(targetPkgName);
+ sb.append('/');
+ return sb.toString();
+ }
+
+ public static String getCommonPackageName(String themePackageName) {
+ if (TextUtils.isEmpty(themePackageName)) return null;
+
+ return COMMON_RES_TARGET;
+ }
+
+ public static void createCacheDirIfNotExists() throws IOException {
+ File file = new File(RESOURCE_CACHE_DIR);
+ if (!file.exists() && !file.mkdir()) {
+ throw new IOException("Could not create dir: " + file.toString());
+ }
+ FileUtils.setPermissions(file, FileUtils.S_IRWXU
+ | FileUtils.S_IRWXG | FileUtils.S_IROTH | FileUtils.S_IXOTH, -1, -1);
+ }
+
+ public static void createResourcesDirIfNotExists(String targetPkgName, String overlayPkgName)
+ throws IOException {
+ createDirIfNotExists(getOverlayResourceCacheDir(overlayPkgName));
+ File file = new File(getTargetCacheDir(targetPkgName, overlayPkgName));
+ if (!file.exists() && !file.mkdir()) {
+ throw new IOException("Could not create dir: " + file.toString());
+ }
+ FileUtils.setPermissions(file, FileUtils.S_IRWXU
+ | FileUtils.S_IRWXG | FileUtils.S_IROTH | FileUtils.S_IXOTH, -1, -1);
+ }
+
+ public static void createIconDirIfNotExists(String pkgName) throws IOException {
+ createDirIfNotExists(getOverlayResourceCacheDir(pkgName));
+ File file = new File(getIconPackDir(pkgName));
+ if (!file.exists() && !file.mkdir()) {
+ throw new IOException("Could not create dir: " + file.toString());
+ }
+ FileUtils.setPermissions(file, FileUtils.S_IRWXU
+ | FileUtils.S_IRWXG | FileUtils.S_IROTH | FileUtils.S_IXOTH, -1, -1);
+ }
+
+ private static boolean dirExists(String dirPath) {
+ final File dir = new File(dirPath);
+ return dir.exists() && dir.isDirectory();
+ }
+
+ private static void createDirIfNotExists(String dirPath) {
+ if (!dirExists(dirPath)) {
+ File dir = new File(dirPath);
+ if (dir.mkdir()) {
+ FileUtils.setPermissions(dir, FileUtils.S_IRWXU |
+ FileUtils.S_IRWXG| FileUtils.S_IROTH | FileUtils.S_IXOTH, -1, -1);
+ }
+ }
+ }
+
+ /**
+ * Create SYSTEM_THEME_PATH directory if it does not exist
+ */
+ public static void createThemeDirIfNotExists() {
+ createDirIfNotExists(SYSTEM_THEME_PATH);
+ }
+
+ /**
+ * Create SYSTEM_FONT_PATH directory if it does not exist
+ */
+ public static void createFontDirIfNotExists() {
+ createDirIfNotExists(SYSTEM_THEME_FONT_PATH);
+ }
+
+ /**
+ * Create SYSTEM_THEME_RINGTONE_PATH directory if it does not exist
+ */
+ public static void createRingtoneDirIfNotExists() {
+ createDirIfNotExists(SYSTEM_THEME_RINGTONE_PATH);
+ }
+
+ /**
+ * Create SYSTEM_THEME_NOTIFICATION_PATH directory if it does not exist
+ */
+ public static void createNotificationDirIfNotExists() {
+ createDirIfNotExists(SYSTEM_THEME_NOTIFICATION_PATH);
+ }
+
+ /**
+ * Create SYSTEM_THEME_ALARM_PATH directory if it does not exist
+ */
+ public static void createAlarmDirIfNotExists() {
+ createDirIfNotExists(SYSTEM_THEME_ALARM_PATH);
+ }
+
+ /**
+ * Create SYSTEM_THEME_ICON_CACHE_DIR directory if it does not exist
+ */
+ public static void createIconCacheDirIfNotExists() {
+ createDirIfNotExists(SYSTEM_THEME_ICON_CACHE_DIR);
+ }
+
+ public static void clearIconCache() {
+ FileUtils.deleteContents(new File(SYSTEM_THEME_ICON_CACHE_DIR));
+ }
+
+ public static InputStream getInputStreamFromAsset(Context ctx, String path) throws IOException {
+ if (ctx == null || path == null)
+ return null;
+ InputStream is = null;
+ String ASSET_BASE = "file:///android_asset/";
+ path = path.substring(ASSET_BASE.length());
+ AssetManager assets = ctx.getAssets();
+ is = assets.open(path);
+ return is;
+ }
+
+ public static void closeQuietly(InputStream stream) {
+ if (stream == null)
+ return;
+ try {
+ stream.close();
+ } catch (IOException e) {
+ }
+ }
+
+ public static void closeQuietly(OutputStream stream) {
+ if (stream == null)
+ return;
+ try {
+ stream.close();
+ } catch (IOException e) {
+ }
+ }
+
+ /**
+ * Scale the boot animation to better fit the device by editing the desc.txt found
+ * in the bootanimation.zip
+ * @param context Context to use for getting an instance of the WindowManager
+ * @param input InputStream of the original bootanimation.zip
+ * @param dst Path to store the newly created bootanimation.zip
+ * @throws IOException
+ */
+ public static void copyAndScaleBootAnimation(Context context, InputStream input, String dst)
+ throws IOException {
+ final OutputStream os = new FileOutputStream(dst);
+ final ZipOutputStream zos = new ZipOutputStream(new BufferedOutputStream(os));
+ final ZipInputStream bootAni = new ZipInputStream(new BufferedInputStream(input));
+ ZipEntry ze;
+
+ zos.setMethod(ZipOutputStream.STORED);
+ final byte[] bytes = new byte[4096];
+ int len;
+ while ((ze = bootAni.getNextEntry()) != null) {
+ ZipEntry entry = new ZipEntry(ze.getName());
+ entry.setMethod(ZipEntry.STORED);
+ entry.setCrc(ze.getCrc());
+ entry.setSize(ze.getSize());
+ entry.setCompressedSize(ze.getSize());
+ if (!ze.getName().equals("desc.txt")) {
+ // just copy this entry straight over into the output zip
+ zos.putNextEntry(entry);
+ while ((len = bootAni.read(bytes)) > 0) {
+ zos.write(bytes, 0, len);
+ }
+ } else {
+ String line;
+ BufferedReader reader = new BufferedReader(new InputStreamReader(bootAni));
+ final String[] info = reader.readLine().split(" ");
+
+ int scaledWidth;
+ int scaledHeight;
+ WindowManager wm = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
+ DisplayMetrics dm = new DisplayMetrics();
+ wm.getDefaultDisplay().getRealMetrics(dm);
+ // just in case the device is in landscape orientation we will
+ // swap the values since most (if not all) animations are portrait
+ if (dm.widthPixels > dm.heightPixels) {
+ scaledWidth = dm.heightPixels;
+ scaledHeight = dm.widthPixels;
+ } else {
+ scaledWidth = dm.widthPixels;
+ scaledHeight = dm.heightPixels;
+ }
+
+ int width = Integer.parseInt(info[0]);
+ int height = Integer.parseInt(info[1]);
+
+ if (width == height)
+ scaledHeight = scaledWidth;
+ else {
+ // adjust scaledHeight to retain original aspect ratio
+ float scale = (float)scaledWidth / (float)width;
+ int newHeight = (int)((float)height * scale);
+ if (newHeight < scaledHeight)
+ scaledHeight = newHeight;
+ }
+
+ CRC32 crc32 = new CRC32();
+ int size = 0;
+ ByteBuffer buffer = ByteBuffer.wrap(bytes);
+ line = String.format("%d %d %s\n", scaledWidth, scaledHeight, info[2]);
+ buffer.put(line.getBytes());
+ size += line.getBytes().length;
+ crc32.update(line.getBytes());
+ while ((line = reader.readLine()) != null) {
+ line = String.format("%s\n", line);
+ buffer.put(line.getBytes());
+ size += line.getBytes().length;
+ crc32.update(line.getBytes());
+ }
+ entry.setCrc(crc32.getValue());
+ entry.setSize(size);
+ entry.setCompressedSize(size);
+ zos.putNextEntry(entry);
+ zos.write(buffer.array(), 0, size);
+ }
+ zos.closeEntry();
+ }
+ zos.close();
+ }
+
+ public static boolean isValidAudible(String fileName) {
+ return (fileName != null &&
+ (fileName.endsWith(".mp3") || fileName.endsWith(".ogg")));
+ }
+
+ public static boolean setAudible(Context context, File ringtone, int type, String name) {
+ final String path = ringtone.getAbsolutePath();
+ final String mimeType = name.endsWith(".ogg") ? "audio/ogg" : "audio/mp3";
+ ContentValues values = new ContentValues();
+ values.put(MediaStore.MediaColumns.DATA, path);
+ values.put(MediaStore.MediaColumns.TITLE, name);
+ values.put(MediaStore.MediaColumns.MIME_TYPE, mimeType);
+ values.put(MediaStore.MediaColumns.SIZE, ringtone.length());
+ values.put(MediaStore.Audio.Media.IS_RINGTONE, type == RingtoneManager.TYPE_RINGTONE);
+ values.put(MediaStore.Audio.Media.IS_NOTIFICATION,
+ type == RingtoneManager.TYPE_NOTIFICATION);
+ values.put(MediaStore.Audio.Media.IS_ALARM, type == RingtoneManager.TYPE_ALARM);
+ values.put(MediaStore.Audio.Media.IS_MUSIC, false);
+
+ Uri uri = MediaStore.Audio.Media.getContentUriForPath(path);
+ Uri newUri = null;
+ Cursor c = context.getContentResolver().query(uri,
+ new String[] {MediaStore.MediaColumns._ID},
+ MediaStore.MediaColumns.DATA + "='" + path + "'",
+ null, null);
+ if (c != null && c.getCount() > 0) {
+ c.moveToFirst();
+ long id = c.getLong(0);
+ c.close();
+ newUri = Uri.withAppendedPath(Uri.parse(MEDIA_CONTENT_URI), "" + id);
+ context.getContentResolver().update(uri, values,
+ MediaStore.MediaColumns._ID + "=" + id, null);
+ }
+ if (newUri == null)
+ newUri = context.getContentResolver().insert(uri, values);
+ try {
+ RingtoneManager.setActualDefaultRingtoneUri(context, type, newUri);
+ } catch (Exception e) {
+ return false;
+ }
+ return true;
+ }
+
+ public static boolean setDefaultAudible(Context context, int type) {
+ final String audiblePath = getDefaultAudiblePath(type);
+ if (audiblePath != null) {
+ Uri uri = MediaStore.Audio.Media.getContentUriForPath(audiblePath);
+ Cursor c = context.getContentResolver().query(uri,
+ new String[] {MediaStore.MediaColumns._ID},
+ MediaStore.MediaColumns.DATA + "='" + audiblePath + "'",
+ null, null);
+ if (c != null && c.getCount() > 0) {
+ c.moveToFirst();
+ long id = c.getLong(0);
+ c.close();
+ uri = Uri.withAppendedPath(
+ Uri.parse(MEDIA_CONTENT_URI), "" + id);
+ }
+ if (uri != null)
+ RingtoneManager.setActualDefaultRingtoneUri(context, type, uri);
+ } else {
+ return false;
+ }
+ return true;
+ }
+
+ public static String getDefaultAudiblePath(int type) {
+ final String name;
+ final String path;
+ switch (type) {
+ case RingtoneManager.TYPE_ALARM:
+ name = SystemProperties.get("ro.config.alarm_alert", null);
+ path = name != null ? SYSTEM_ALARMS_PATH + File.separator + name : null;
+ break;
+ case RingtoneManager.TYPE_NOTIFICATION:
+ name = SystemProperties.get("ro.config.notification_sound", null);
+ path = name != null ? SYSTEM_NOTIFICATIONS_PATH + File.separator + name : null;
+ break;
+ case RingtoneManager.TYPE_RINGTONE:
+ name = SystemProperties.get("ro.config.ringtone", null);
+ path = name != null ? SYSTEM_RINGTONES_PATH + File.separator + name : null;
+ break;
+ default:
+ path = null;
+ break;
+ }
+ return path;
+ }
+
+ public static void clearAudibles(Context context, String audiblePath) {
+ final File audibleDir = new File(audiblePath);
+ if (audibleDir.exists()) {
+ String[] files = audibleDir.list();
+ final ContentResolver resolver = context.getContentResolver();
+ for (String s : files) {
+ final String filePath = audiblePath + File.separator + s;
+ Uri uri = MediaStore.Audio.Media.getContentUriForPath(filePath);
+ resolver.delete(uri, MediaStore.MediaColumns.DATA + "=\""
+ + filePath + "\"", null);
+ (new File(filePath)).delete();
+ }
+ }
+ }
+
+ public static Context createUiContext(final Context context) {
+ try {
+ Context uiContext = context.createPackageContext("com.android.systemui",
+ Context.CONTEXT_RESTRICTED);
+ return new ThemedUiContext(uiContext, context.getApplicationContext());
+ } catch (PackageManager.NameNotFoundException e) {
+ }
+
+ return null;
+ }
+
+ public static void registerThemeChangeReceiver(final Context context,
+ final BroadcastReceiver receiver) {
+ IntentFilter filter = new IntentFilter(ACTION_THEME_CHANGED);
+
+ context.registerReceiver(receiver, filter);
+ }
+
+ public static String getLockscreenWallpaperPath(AssetManager assetManager) throws IOException {
+ String[] assets = assetManager.list(LOCKSCREEN_WALLPAPER_PATH);
+ String asset = getFirstNonEmptyAsset(assets);
+ if (asset == null) return null;
+ return LOCKSCREEN_WALLPAPER_PATH + File.separator + asset;
+ }
+
+ public static String getWallpaperPath(AssetManager assetManager) throws IOException {
+ String[] assets = assetManager.list(WALLPAPER_PATH);
+ String asset = getFirstNonEmptyAsset(assets);
+ if (asset == null) return null;
+ return WALLPAPER_PATH + File.separator + asset;
+ }
+
+ public static List<String> getWallpaperPathList(AssetManager assetManager)
+ throws IOException {
+ List<String> wallpaperList = new ArrayList<String>();
+ String[] assets = assetManager.list(WALLPAPER_PATH);
+ for (String asset : assets) {
+ if (!TextUtils.isEmpty(asset)) {
+ wallpaperList.add(WALLPAPER_PATH + File.separator + asset);
+ }
+ }
+ return wallpaperList;
+ }
+
+ // Returns the first non-empty asset name. Empty assets can occur if the APK is built
+ // with folders included as zip entries in the APK. Searching for files inside "folderName" via
+ // assetManager.list("folderName") can cause these entries to be included as empty strings.
+ private static String getFirstNonEmptyAsset(String[] assets) {
+ if (assets == null) return null;
+ String filename = null;
+ for(String asset : assets) {
+ if (!TextUtils.isEmpty(asset)) {
+ filename = asset;
+ break;
+ }
+ }
+ return filename;
+ }
+
+ public static String getDefaultThemePackageName(Context context) {
+ final String defaultThemePkg = Settings.Secure.getString(context.getContentResolver(),
+ Settings.Secure.DEFAULT_THEME_PACKAGE);
+ if (!TextUtils.isEmpty(defaultThemePkg)) {
+ PackageManager pm = context.getPackageManager();
+ try {
+ if (pm.getPackageInfo(defaultThemePkg, 0) != null) {
+ return defaultThemePkg;
+ }
+ } catch (PackageManager.NameNotFoundException e) {
+ // doesn't exist so system will be default
+ Log.w(TAG, "Default theme " + defaultThemePkg + " not found", e);
+ }
+ }
+
+ return SYSTEM_DEFAULT;
+ }
+
+ private static class ThemedUiContext extends ContextWrapper {
+ private Context mAppContext;
+
+ public ThemedUiContext(Context context, Context appContext) {
+ super(context);
+ mAppContext = appContext;
+ }
+
+ @Override
+ public Context getApplicationContext() {
+ return mAppContext;
+ }
+
+ @Override
+ public String getPackageName() {
+ return mAppContext.getPackageName();
+ }
+ }
+
+ // Returns a mutable list of all theme components
+ public static List<String> getAllComponents() {
+ List<String> components = new ArrayList<String>(9);
+ components.add(ThemesColumns.MODIFIES_FONTS);
+ components.add(ThemesColumns.MODIFIES_LAUNCHER);
+ components.add(ThemesColumns.MODIFIES_ALARMS);
+ components.add(ThemesColumns.MODIFIES_BOOT_ANIM);
+ components.add(ThemesColumns.MODIFIES_ICONS);
+ components.add(ThemesColumns.MODIFIES_LOCKSCREEN);
+ components.add(ThemesColumns.MODIFIES_NOTIFICATIONS);
+ components.add(ThemesColumns.MODIFIES_OVERLAYS);
+ components.add(ThemesColumns.MODIFIES_RINGTONES);
+ components.add(ThemesColumns.MODIFIES_STATUS_BAR);
+ components.add(ThemesColumns.MODIFIES_NAVIGATION_BAR);
+ components.add(ThemesColumns.MODIFIES_LIVE_LOCK_SCREEN);
+ return components;
+ }
+
+ /**
+ * Returns a mutable list of all the theme components supported by a given package
+ * NOTE: This queries the themes content provider. If there isn't a provider installed
+ * or if it is too early in the boot process this method will not work.
+ */
+ public static List<String> getSupportedComponents(Context context, String pkgName) {
+ List<String> supportedComponents = new ArrayList<String>();
+
+ String selection = ThemesContract.ThemesColumns.PKG_NAME + "= ?";
+ String[] selectionArgs = new String[]{ pkgName };
+ Cursor c = context.getContentResolver().query(ThemesContract.ThemesColumns.CONTENT_URI,
+ null, selection, selectionArgs, null);
+
+ if (c != null) {
+ if (c.moveToFirst()) {
+ List<String> allComponents = getAllComponents();
+ for (String component : allComponents) {
+ int index = c.getColumnIndex(component);
+ if (c.getInt(index) == 1) {
+ supportedComponents.add(component);
+ }
+ }
+ }
+ c.close();
+ }
+ return supportedComponents;
+ }
+
+ /**
+ * Get the components from the default theme. If the default theme is not SYSTEM then any
+ * components that are not in the default theme will come from SYSTEM to create a complete
+ * component map.
+ * @param context
+ * @return
+ */
+ public static Map<String, String> getDefaultComponents(Context context) {
+ String defaultThemePkg = getDefaultThemePackageName(context);
+ List<String> defaultComponents = null;
+ List<String> systemComponents = getSupportedComponents(context, SYSTEM_DEFAULT);
+ if (!SYSTEM_DEFAULT.equals(defaultThemePkg)) {
+ defaultComponents = getSupportedComponents(context, defaultThemePkg);
+ }
+
+ Map<String, String> componentMap = new HashMap<String, String>(systemComponents.size());
+ if (defaultComponents != null) {
+ for (String component : defaultComponents) {
+ componentMap.put(component, defaultThemePkg);
+ }
+ }
+ for (String component : systemComponents) {
+ if (!componentMap.containsKey(component)) {
+ componentMap.put(component, SYSTEM_DEFAULT);
+ }
+ }
+
+ return componentMap;
+ }
+
+ /**
+ * Takes an existing component map and adds any missing components from the default
+ * map of components.
+ * @param context
+ * @param componentMap An existing component map
+ */
+ public static void completeComponentMap(Context context,
+ Map<String, String> componentMap) {
+ if (componentMap == null) return;
+
+ Map<String, String> defaultComponents = getDefaultComponents(context);
+ for (String component : defaultComponents.keySet()) {
+ if (!componentMap.containsKey(component)) {
+ componentMap.put(component, defaultComponents.get(component));
+ }
+ }
+ }
+
+ /**
+ * Convenience method to determine if a theme component is a per app theme and not a standard
+ * component.
+ * @param component
+ * @return
+ */
+ public static boolean isPerAppThemeComponent(String component) {
+ return !(DEFAULT_PKG.equals(component)
+ || ThemeConfig.SYSTEMUI_STATUS_BAR_PKG.equals(component)
+ || ThemeConfig.SYSTEMUI_NAVBAR_PKG.equals(component));
+ }
+
+ /**
+ * Get a 32 bit hashcode for the given package.
+ * @param pkg
+ * @return
+ */
+ public static int getPackageHashCode(PackageParser.Package pkg) {
+ int hash = pkg.manifestDigest != null ? pkg.manifestDigest.hashCode() : 0;
+ hash = 31 * hash + IDMAP_HASH_VERSION;
+ return hash;
+ }
+}
diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java
index 8d96f5c..abb1871 100644
--- a/core/java/android/content/res/AssetManager.java
+++ b/core/java/android/content/res/AssetManager.java
@@ -21,9 +21,11 @@ import android.util.Log;
import android.util.SparseArray;
import android.util.TypedValue;
+import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
+import java.util.ArrayList;
import java.util.HashMap;
/**
@@ -77,6 +79,16 @@ public final class AssetManager implements AutoCloseable {
private boolean mOpen = true;
private HashMap<Long, RuntimeException> mRefStacks;
+ private String mAppName;
+
+ private boolean mThemeSupport;
+ private String mThemePackageName;
+ private String mIconPackageName;
+ private String mCommonResPackageName;
+ private ArrayList<Integer> mThemeCookies = new ArrayList<Integer>(2);
+ private int mIconPackCookie;
+ private int mCommonResCookie;
+
/**
* Create a new AssetManager containing only the basic system assets.
* Applications will not generally use this method, instead retrieving the
@@ -252,6 +264,12 @@ public final class AssetManager implements AutoCloseable {
}
}
+ /*package*/ final void recreateStringBlocks() {
+ synchronized (this) {
+ makeStringBlocks(sSystem.mStringBlocks);
+ }
+ }
+
/*package*/ final void makeStringBlocks(StringBlock[] seed) {
final int seedNum = (seed != null) ? seed.length : 0;
final int num = getStringBlockCount();
@@ -612,7 +630,9 @@ public final class AssetManager implements AutoCloseable {
public final int addAssetPath(String path) {
synchronized (this) {
int res = addAssetPathNative(path);
- makeStringBlocks(mStringBlocks);
+ if (mStringBlocks != null) {
+ makeStringBlocks(mStringBlocks);
+ }
return res;
}
}
@@ -627,11 +647,14 @@ public final class AssetManager implements AutoCloseable {
*
* {@hide}
*/
-
- public final int addOverlayPath(String idmapPath) {
+ public final int addOverlayPath(String idmapPath, String themeApkPath,
+ String resApkPath, String targetPkgPath, String prefixPath) {
synchronized (this) {
- int res = addOverlayPathNative(idmapPath);
- makeStringBlocks(mStringBlocks);
+ int res = addOverlayPathNative(idmapPath, themeApkPath, resApkPath, targetPkgPath,
+ prefixPath);
+ if (mStringBlocks != null) {
+ makeStringBlocks(mStringBlocks);
+ }
return res;
}
}
@@ -641,7 +664,59 @@ public final class AssetManager implements AutoCloseable {
*
* {@hide}
*/
- public native final int addOverlayPathNative(String idmapPath);
+ private native final int addOverlayPathNative(String idmapPath, String themeApkPath,
+ String resApkPath, String targetPkgPath, String prefixPath);
+
+ /**
+ * Add a set of common assets.
+ *
+ * {@hide}
+ */
+ public final int addCommonOverlayPath(String themeApkPath,
+ String resApkPath, String prefixPath) {
+ synchronized (this) {
+ return addCommonOverlayPathNative(themeApkPath, resApkPath, prefixPath);
+ }
+ }
+
+ private native final int addCommonOverlayPathNative(String themeApkPath,
+ String resApkPath, String prefixPath);
+
+ /**
+ * Add a set of assets as an icon pack. A pkgIdOverride value will change the package's id from
+ * what is in the resource table to a new value. Manage this carefully, if icon pack has more
+ * than one package then that next package's id will use pkgIdOverride+1.
+ *
+ * Icon packs are different from overlays as they have a different pkg id and
+ * do not use idmap so no targetPkg is required
+ *
+ * {@hide}
+ */
+ public final int addIconPath(String idmapPath, String resApkPath,
+ String prefixPath, int pkgIdOverride) {
+ synchronized (this) {
+ return addIconPathNative(idmapPath, resApkPath, prefixPath, pkgIdOverride);
+ }
+ }
+
+ private native final int addIconPathNative(String idmapPath,
+ String resApkPath, String prefixPath, int pkgIdOverride);
+
+ /**
+ * Delete a set of overlay assets from the asset manager. Not for use by
+ * applications. Returns true if succeeded or false on failure.
+ *
+ * Also works for icon packs
+ *
+ * {@hide}
+ */
+ public final boolean removeOverlayPath(String packageName, int cookie) {
+ synchronized (this) {
+ return removeOverlayPathNative(packageName, cookie);
+ }
+ }
+
+ private native final boolean removeOverlayPathNative(String packageName, int cookie);
/**
* Add multiple sets of assets to the asset manager at once. See
@@ -664,6 +739,126 @@ public final class AssetManager implements AutoCloseable {
}
/**
+ * Sets a flag indicating that this AssetManager should have themes
+ * attached, according to the initial request to create it by the
+ * ApplicationContext.
+ *
+ * {@hide}
+ */
+ public final void setThemeSupport(boolean themeSupport) {
+ mThemeSupport = themeSupport;
+ }
+
+ /**
+ * Should this AssetManager have themes attached, according to the initial
+ * request to create it by the ApplicationContext?
+ *
+ * {@hide}
+ */
+ public final boolean hasThemeSupport() {
+ return mThemeSupport;
+ }
+
+ /**
+ * Get package name of current icon pack (may return null).
+ * {@hide}
+ */
+ public String getIconPackageName() {
+ return mIconPackageName;
+ }
+
+ /**
+ * Sets icon package name
+ * {@hide}
+ */
+ public void setIconPackageName(String packageName) {
+ mIconPackageName = packageName;
+ }
+
+ /**
+ * Get package name of current common resources (may return null).
+ * {@hide}
+ */
+ public String getCommonResPackageName() {
+ return mCommonResPackageName;
+ }
+
+ /**
+ * Sets common resources package name
+ * {@hide}
+ */
+ public void setCommonResPackageName(String packageName) {
+ mCommonResPackageName = packageName;
+ }
+
+ /**
+ * Get package name of current theme (may return null).
+ * {@hide}
+ */
+ public String getThemePackageName() {
+ return mThemePackageName;
+ }
+
+ /**
+ * Sets package name and highest level style id for current theme (null, 0 is allowed).
+ * {@hide}
+ */
+ public void setThemePackageName(String packageName) {
+ mThemePackageName = packageName;
+ }
+
+ /**
+ * Get asset cookie for current theme (may return 0).
+ * {@hide}
+ */
+ public ArrayList<Integer> getThemeCookies() {
+ return mThemeCookies;
+ }
+
+ /** {@hide} */
+ public void setIconPackCookie(int cookie) {
+ mIconPackCookie = cookie;
+ }
+
+ /** {@hide} */
+ public int getIconPackCookie() {
+ return mIconPackCookie;
+ }
+
+ /** {@hide} */
+ public void setCommonResCookie(int cookie) {
+ mCommonResCookie = cookie;
+ }
+
+ /** {@hide} */
+ public int getCommonResCookie() {
+ return mCommonResCookie;
+ }
+
+ /**
+ * Sets asset cookie for current theme (0 if not a themed asset manager).
+ * {@hide}
+ */
+ public void addThemeCookie(int cookie) {
+ mThemeCookies.add(cookie);
+ }
+
+ /** {@hide} */
+ public String getAppName() {
+ return mAppName;
+ }
+
+ /** {@hide} */
+ public void setAppName(String pkgName) {
+ mAppName = pkgName;
+ }
+
+ /** {@hide} */
+ public boolean hasThemedAssets() {
+ return mThemeCookies.size() > 0;
+ }
+
+ /**
* Determine whether the state in this asset manager is up-to-date with
* the files on the filesystem. If false is returned, you need to
* instantiate a new AssetManager class to see the new data.
@@ -800,6 +995,26 @@ public final class AssetManager implements AutoCloseable {
/*package*/ native final int[] getStyleAttributes(int themeRes);
private native final void init(boolean isSystem);
+ /**
+ * {@hide}
+ */
+ public native final int getBasePackageCount();
+
+ /**
+ * {@hide}
+ */
+ public native final String getBasePackageName(int index);
+
+ /**
+ * {@hide}
+ */
+ public native final String getBaseResourcePackageName(int index);
+
+ /**
+ * {@hide}
+ */
+ public native final int getBasePackageId(int index);
+
private native final void destroy();
private final void incRefsLocked(long id) {
diff --git a/core/java/android/content/res/CompatibilityInfo.java b/core/java/android/content/res/CompatibilityInfo.java
index da35ee9..2b8951e 100644
--- a/core/java/android/content/res/CompatibilityInfo.java
+++ b/core/java/android/content/res/CompatibilityInfo.java
@@ -241,8 +241,7 @@ public class CompatibilityInfo implements Parcelable {
mCompatibilityFlags = compatFlags;
}
- private CompatibilityInfo(int compFlags,
- int dens, float scale, float invertedScale) {
+ private CompatibilityInfo(int compFlags, int dens, float scale, float invertedScale) {
mCompatibilityFlags = compFlags;
applicationDensity = dens;
applicationScale = scale;
diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java
index fd60476..0bc1ec2 100644
--- a/core/java/android/content/res/Configuration.java
+++ b/core/java/android/content/res/Configuration.java
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2008 The Android Open Source Project
+ * This code has been modified. Portions copyright (C) 2010, T-Mobile USA, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -82,6 +83,11 @@ public final class Configuration implements Parcelable, Comparable<Configuration
public Locale locale;
/**
+ * @hide
+ */
+ public ThemeConfig themeConfig;
+
+ /**
* Locale should persist on setting. This is hidden because it is really
* questionable whether this is the right way to expose the functionality.
* @hide
@@ -441,7 +447,47 @@ public final class Configuration implements Parcelable, Comparable<Configuration
public static final int ORIENTATION_LANDSCAPE = 2;
/** @deprecated Not currently supported or used. */
@Deprecated public static final int ORIENTATION_SQUARE = 3;
-
+
+ /**
+ * @hide
+ * @deprecated
+ */
+ public static final String THEME_PACKAGE_NAME_PERSISTENCE_PROPERTY
+ = "persist.sys.themePackageName";
+
+ /**
+ * @hide
+ * @deprecated
+ */
+ public static final String THEME_ICONPACK_PACKAGE_NAME_PERSISTENCE_PROPERTY
+ = "themeIconPackPkgName";
+
+ /**
+ * @hide
+ * @deprecated
+ */
+ public static final String THEME_FONT_PACKAGE_NAME_PERSISTENCE_PROPERTY
+ = "themeFontPackPkgName";
+
+ /**
+ * @hide
+ * Serialized json structure mapping app pkgnames to their set theme.
+ *
+ * {
+ * "default":{
+ *" stylePkgName":"com.jasonevil.theme.miuiv5dark",
+ * "iconPkgName":"com.cyngn.hexo",
+ * "fontPkgName":"com.cyngn.hexo"
+ * }
+ * }
+
+ * If an app does not have a specific theme set then it will use the 'default' theme+
+ * example: 'default' -> overlayPkgName: 'org.blue.theme'
+ * 'com.android.phone' -> 'com.red.theme'
+ * 'com.google.vending' -> 'com.white.theme'
+ */
+ public static final String THEME_PKG_CONFIGURATION_PERSISTENCE_PROPERTY = "themeConfig";
+
/**
* Overall orientation of the screen. May be one of
* {@link #ORIENTATION_LANDSCAPE}, {@link #ORIENTATION_PORTRAIT}.
@@ -673,8 +719,11 @@ public final class Configuration implements Parcelable, Comparable<Configuration
compatScreenHeightDp = o.compatScreenHeightDp;
compatSmallestScreenWidthDp = o.compatSmallestScreenWidthDp;
seq = o.seq;
+ if (o.themeConfig != null) {
+ themeConfig = (ThemeConfig) o.themeConfig.clone();
+ }
}
-
+
public String toString() {
StringBuilder sb = new StringBuilder(128);
sb.append("{");
@@ -809,6 +858,8 @@ public final class Configuration implements Parcelable, Comparable<Configuration
sb.append(" s.");
sb.append(seq);
}
+ sb.append(" themeResource=");
+ sb.append(themeConfig);
sb.append('}');
return sb.toString();
}
@@ -835,6 +886,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration
smallestScreenWidthDp = compatSmallestScreenWidthDp = SMALLEST_SCREEN_WIDTH_DP_UNDEFINED;
densityDpi = DENSITY_DPI_UNDEFINED;
seq = 0;
+ themeConfig = null;
}
/** {@hide} */
@@ -977,7 +1029,18 @@ public final class Configuration implements Parcelable, Comparable<Configuration
if (delta.seq != 0) {
seq = delta.seq;
}
-
+
+ if (delta.themeConfig != null
+ && (themeConfig == null || !themeConfig.equals(delta.themeConfig))) {
+ changed |= ActivityInfo.CONFIG_THEME_RESOURCE;
+ final String fontPkgName = delta.themeConfig.getFontPkgName();
+ if (themeConfig == null ||
+ (fontPkgName != null && !fontPkgName.equals(themeConfig.getFontPkgName()))) {
+ changed |= ActivityInfo.CONFIG_THEME_FONT;
+ }
+ themeConfig = (ThemeConfig)delta.themeConfig.clone();
+ }
+
return changed;
}
@@ -1087,7 +1150,15 @@ public final class Configuration implements Parcelable, Comparable<Configuration
&& densityDpi != delta.densityDpi) {
changed |= ActivityInfo.CONFIG_DENSITY;
}
-
+ if (delta.themeConfig != null &&
+ (themeConfig == null || !themeConfig.equals(delta.themeConfig))) {
+ changed |= ActivityInfo.CONFIG_THEME_RESOURCE;
+ final String fontPkgName = delta.themeConfig.getFontPkgName();
+ if (themeConfig == null ||
+ (fontPkgName != null && !fontPkgName.equals(themeConfig.getFontPkgName()))) {
+ changed |= ActivityInfo.CONFIG_THEME_FONT;
+ }
+ }
return changed;
}
@@ -1103,7 +1174,9 @@ public final class Configuration implements Parcelable, Comparable<Configuration
* @return Return true if the resource needs to be loaded, else false.
*/
public static boolean needNewResources(int configChanges, int interestingChanges) {
- return (configChanges & (interestingChanges|ActivityInfo.CONFIG_FONT_SCALE)) != 0;
+ return (configChanges & (interestingChanges |
+ ActivityInfo.CONFIG_FONT_SCALE |
+ ActivityInfo.CONFIG_THEME_RESOURCE)) != 0;
}
/**
@@ -1176,6 +1249,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration
dest.writeInt(compatScreenHeightDp);
dest.writeInt(compatSmallestScreenWidthDp);
dest.writeInt(seq);
+ dest.writeParcelable(themeConfig, flags);
}
public void readFromParcel(Parcel source) {
@@ -1204,6 +1278,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration
compatScreenHeightDp = source.readInt();
compatSmallestScreenWidthDp = source.readInt();
seq = source.readInt();
+ themeConfig = source.readParcelable(ThemeConfig.class.getClassLoader());
}
public static final Parcelable.Creator<Configuration> CREATOR
@@ -1271,7 +1346,12 @@ public final class Configuration implements Parcelable, Comparable<Configuration
n = this.smallestScreenWidthDp - that.smallestScreenWidthDp;
if (n != 0) return n;
n = this.densityDpi - that.densityDpi;
- //if (n != 0) return n;
+ if (n != 0) return n;
+ if (this.themeConfig == null) {
+ if (that.themeConfig != null) return 1;
+ } else {
+ n = this.themeConfig.compareTo(that.themeConfig);
+ }
return n;
}
@@ -1308,6 +1388,8 @@ public final class Configuration implements Parcelable, Comparable<Configuration
result = 31 * result + screenHeightDp;
result = 31 * result + smallestScreenWidthDp;
result = 31 * result + densityDpi;
+ result = 31 * result + (this.themeConfig != null ?
+ this.themeConfig.hashCode() : 0);
return result;
}
diff --git a/core/java/android/content/res/IThemeChangeListener.aidl b/core/java/android/content/res/IThemeChangeListener.aidl
new file mode 100644
index 0000000..a2e2abd
--- /dev/null
+++ b/core/java/android/content/res/IThemeChangeListener.aidl
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2014 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.content.res;
+
+/** {@hide} */
+oneway interface IThemeChangeListener {
+ void onProgress(int progress);
+ void onFinish(boolean isSuccess);
+}
diff --git a/core/java/android/content/res/IThemeProcessingListener.aidl b/core/java/android/content/res/IThemeProcessingListener.aidl
new file mode 100644
index 0000000..2e1c16e
--- /dev/null
+++ b/core/java/android/content/res/IThemeProcessingListener.aidl
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2014 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.content.res;
+
+/** {@hide} */
+oneway interface IThemeProcessingListener {
+ void onFinishedProcessing(String pkgName);
+}
diff --git a/core/java/android/content/res/IThemeService.aidl b/core/java/android/content/res/IThemeService.aidl
new file mode 100644
index 0000000..90cb9fb
--- /dev/null
+++ b/core/java/android/content/res/IThemeService.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2014 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.content.res;
+
+import android.content.res.IThemeChangeListener;
+import android.content.res.IThemeProcessingListener;
+import android.content.res.ThemeChangeRequest;
+import android.graphics.Bitmap;
+
+import java.util.Map;
+
+/** {@hide} */
+interface IThemeService {
+ void requestThemeChangeUpdates(in IThemeChangeListener listener);
+ void removeUpdates(in IThemeChangeListener listener);
+
+ void requestThemeChange(in ThemeChangeRequest request, boolean removePerAppThemes);
+ void applyDefaultTheme();
+ boolean isThemeApplying();
+ int getProgress();
+
+ boolean cacheComposedIcon(in Bitmap icon, String path);
+
+ boolean processThemeResources(String themePkgName);
+ boolean isThemeBeingProcessed(String themePkgName);
+ void registerThemeProcessingListener(in IThemeProcessingListener listener);
+ void unregisterThemeProcessingListener(in IThemeProcessingListener listener);
+
+ void rebuildResourceCache();
+}
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index 731903c..85ecc0a 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -21,6 +21,9 @@ import android.annotation.ColorInt;
import android.annotation.StyleRes;
import android.annotation.StyleableRes;
import com.android.internal.util.GrowingArrayUtils;
+import android.app.ComposedIconInfo;
+import android.app.IconPackHelper;
+import android.app.IconPackHelper.IconCustomizer;
import com.android.internal.util.XmlUtils;
import org.xmlpull.v1.XmlPullParser;
@@ -45,6 +48,7 @@ import android.annotation.RawRes;
import android.annotation.StringRes;
import android.annotation.XmlRes;
import android.content.pm.ActivityInfo;
+import android.content.pm.PackageItemInfo;
import android.graphics.Movie;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
@@ -59,6 +63,7 @@ import android.util.Log;
import android.util.LongSparseArray;
import android.util.Pools.SynchronizedPool;
import android.util.Slog;
+import android.util.SparseArray;
import android.util.TypedValue;
import android.view.ViewDebug;
import android.view.ViewHierarchyEncoder;
@@ -108,6 +113,20 @@ public class Resources {
private static final int ID_OTHER = 0x01000004;
+ // Package IDs for themes. Aapt will compile the res table with this id.
+ /** @hide */
+ public static final int THEME_FRAMEWORK_PKG_ID = 0x60;
+ /** @hide */
+ public static final int THEME_APP_PKG_ID = 0x61;
+ /** @hide */
+ public static final int THEME_ICON_PKG_ID = 0x62;
+ /**
+ * The common resource pkg id needs to be less than the THEME_FRAMEWORK_PKG_ID
+ * otherwise aapt will complain and fail
+ * @hide
+ */
+ public static final int THEME_COMMON_PKG_ID = THEME_FRAMEWORK_PKG_ID - 1;
+
private static final Object sSync = new Object();
// Information about preloaded resources. Note that they are not
@@ -158,6 +177,9 @@ public class Resources {
private CompatibilityInfo mCompatibilityInfo = CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO;
+ private SparseArray<PackageItemInfo> mIcons;
+ private ComposedIconInfo mComposedIconInfo;
+
static {
sPreloadedDrawables = new LongSparseArray[2];
sPreloadedDrawables[0] = new LongSparseArray<>();
@@ -268,7 +290,7 @@ public class Resources {
mCompatibilityInfo = compatInfo;
}
updateConfiguration(config, metrics);
- assets.ensureStringBlocks();
+ assets.recreateStringBlocks();
}
/**
@@ -793,6 +815,19 @@ public class Resources {
*/
@Nullable
public Drawable getDrawable(@DrawableRes int id, @Nullable Theme theme) throws NotFoundException {
+ return getDrawable(id, theme, true);
+ }
+
+ /** @hide */
+ @Nullable
+ public Drawable getDrawable(@DrawableRes int id, @Nullable Theme theme, boolean supportComposedIcons)
+ throws NotFoundException {
+ //Check if an icon is themed
+ PackageItemInfo info = mIcons != null ? mIcons.get(id) : null;
+ if (info != null && info.themedIcon != 0) {
+ id = info.themedIcon;
+ }
+
TypedValue value;
synchronized (mAccessLock) {
value = mTmpValue;
@@ -801,9 +836,24 @@ public class Resources {
} else {
mTmpValue = null;
}
- getValue(id, value, true);
+ getValue(id, value, true, supportComposedIcons);
+ }
+ Drawable res = null;
+ try {
+ res = loadDrawable(value, id, theme);
+ } catch (NotFoundException e) {
+ // The below statement will be true if we were trying to load a composed icon.
+ // Since we received a NotFoundException, try to load the original if this
+ // condition is true, otherwise throw the original exception.
+ if (supportComposedIcons && mComposedIconInfo != null && info != null &&
+ info.themedIcon == 0) {
+ Log.e(TAG, "Failed to retrieve composed icon.", e);
+ getValue(id, value, true, false);
+ res = loadDrawable(value, id, theme);
+ } else {
+ throw e;
+ }
}
- final Drawable res = loadDrawable(value, id, theme);
synchronized (mAccessLock) {
if (mTmpValue == null) {
mTmpValue = value;
@@ -860,6 +910,19 @@ public class Resources {
*/
@Nullable
public Drawable getDrawableForDensity(@DrawableRes int id, int density, @Nullable Theme theme) {
+ return getDrawableForDensity(id, density, theme, true);
+ }
+
+ /** @hide */
+ @Nullable
+ public Drawable getDrawableForDensity(@DrawableRes int id, int density, @Nullable Theme theme,
+ boolean supportComposedIcons) {
+ //Check if an icon was themed
+ PackageItemInfo info = mIcons != null ? mIcons.get(id) : null;
+ if (info != null && info.themedIcon != 0) {
+ id = info.themedIcon;
+ }
+
TypedValue value;
synchronized (mAccessLock) {
value = mTmpValue;
@@ -868,7 +931,7 @@ public class Resources {
} else {
mTmpValue = null;
}
- getValueForDensity(id, density, value, true);
+ getValueForDensity(id, density, value, true, supportComposedIcons);
/*
* Pretend the requested density is actually the display density. If
@@ -1344,8 +1407,24 @@ public class Resources {
*/
public void getValue(@AnyRes int id, TypedValue outValue, boolean resolveRefs)
throws NotFoundException {
+ getValue(id, outValue, resolveRefs, true);
+ }
+
+ /** @hide */
+ public void getValue(@AnyRes int id, TypedValue outValue, boolean resolveRefs,
+ boolean supportComposedIcons) throws NotFoundException {
+ //Check if an icon was themed
+ PackageItemInfo info = mIcons != null ? mIcons.get(id) : null;
+ if (info != null && info.themedIcon != 0) {
+ id = info.themedIcon;
+ }
boolean found = mAssets.getResourceValue(id, 0, outValue, resolveRefs);
if (found) {
+ if (supportComposedIcons && IconPackHelper.shouldComposeIcon(mComposedIconInfo)
+ && info != null && info.themedIcon == 0) {
+ Drawable dr = loadDrawable(outValue, id, null);
+ IconCustomizer.getValue(this, id, outValue, dr);
+ }
return;
}
throw new NotFoundException("Resource ID #0x"
@@ -1367,8 +1446,45 @@ public class Resources {
*/
public void getValueForDensity(@AnyRes int id, int density, TypedValue outValue,
boolean resolveRefs) throws NotFoundException {
+ getValueForDensity(id, density, outValue, resolveRefs, true);
+ }
+
+ /** @hide */
+ public void getValueForDensity(@AnyRes int id, int density, TypedValue outValue,
+ boolean resolveRefs, boolean supportComposedIcons) throws NotFoundException {
+ //Check if an icon was themed
+ PackageItemInfo info = mIcons != null ? mIcons.get(id) : null;
+ if (info != null && info.themedIcon != 0) {
+ id = info.themedIcon;
+ }
+
boolean found = mAssets.getResourceValue(id, density, outValue, resolveRefs);
if (found) {
+ if (supportComposedIcons && IconPackHelper.shouldComposeIcon(mComposedIconInfo) &&
+ info != null && info.themedIcon == 0) {
+ int tmpDensity = outValue.density;
+ /*
+ * Pretend the requested density is actually the display density. If
+ * the drawable returned is not the requested density, then force it
+ * to be scaled later by dividing its density by the ratio of
+ * requested density to actual device density. Drawables that have
+ * undefined density or no density don't need to be handled here.
+ */
+ if (outValue.density > 0 && outValue.density != TypedValue.DENSITY_NONE) {
+ if (outValue.density == density) {
+ outValue.density = mMetrics.densityDpi;
+ } else {
+ outValue.density = (outValue.density * mMetrics.densityDpi) / density;
+ }
+ }
+ Drawable dr = loadDrawable(outValue, id, null);
+
+ // Return to original density. If we do not do this then
+ // the caller will get the wrong density for the given id and perform
+ // more of its own scaling in loadDrawable
+ outValue.density = tmpDensity;
+ IconCustomizer.getValue(this, id, outValue, dr);
+ }
return;
}
throw new NotFoundException("Resource ID #0x" + Integer.toHexString(id));
@@ -2005,8 +2121,13 @@ public class Resources {
mConfiguration.setLayoutDirection(mConfiguration.locale);
}
if (mConfiguration.densityDpi != Configuration.DENSITY_DPI_UNDEFINED) {
- mMetrics.densityDpi = mConfiguration.densityDpi;
- mMetrics.density = mConfiguration.densityDpi * DisplayMetrics.DENSITY_DEFAULT_SCALE;
+ if (DisplayMetrics.DENSITY_DEVICE_DEFAULT == mCompatibilityInfo.applicationDensity
+ && (config != null
+ && config.densityDpi == DisplayMetrics.DENSITY_DEVICE_DEFAULT)) {
+ mMetrics.setDensity(DisplayMetrics.DENSITY_PREFERRED);
+ } else {
+ mMetrics.setDensity(mConfiguration.densityDpi);
+ }
}
mMetrics.scaledDensity = mMetrics.density * mConfiguration.fontScale;
@@ -2083,7 +2204,15 @@ public class Resources {
mTmpConfig.setLayoutDirection(mTmpConfig.locale);
}
configChanges = mConfiguration.updateFrom(mTmpConfig);
- configChanges = ActivityInfo.activityInfoConfigToNative(configChanges);
+
+ /* This is ugly, but modifying the activityInfoConfigToNative
+ * adapter would be messier */
+ if ((configChanges & ActivityInfo.CONFIG_THEME_RESOURCE) != 0) {
+ configChanges = ActivityInfo.activityInfoConfigToNative(configChanges);
+ configChanges |= ActivityInfo.CONFIG_THEME_RESOURCE;
+ } else {
+ configChanges = ActivityInfo.activityInfoConfigToNative(configChanges);
+ }
}
return configChanges;
}
@@ -2428,7 +2557,7 @@ public class Resources {
}
sPreloaded = true;
mPreloading = true;
- sPreloadedDensity = DisplayMetrics.DENSITY_DEVICE;
+ sPreloadedDensity = DisplayMetrics.DENSITY_PREFERRED;
mConfiguration.densityDpi = sPreloadedDensity;
updateConfiguration(null, null);
}
@@ -2526,9 +2655,10 @@ public class Resources {
// attributes.
final ConstantState cs;
if (isColorDrawable) {
- cs = sPreloadedColorDrawables.get(key);
+ cs = mAssets.hasThemedAssets() ? null : sPreloadedColorDrawables.get(key);
} else {
- cs = sPreloadedDrawables[mConfiguration.getLayoutDirection()].get(key);
+ cs = mAssets.hasThemedAssets() ? null :
+ sPreloadedDrawables[mConfiguration.getLayoutDirection()].get(key);
}
Drawable dr;
@@ -2666,7 +2796,7 @@ public class Resources {
if (value.type >= TypedValue.TYPE_FIRST_COLOR_INT
&& value.type <= TypedValue.TYPE_LAST_COLOR_INT) {
final android.content.res.ConstantState<ColorStateList> factory =
- sPreloadedColorStateLists.get(key);
+ mAssets.hasThemedAssets() ? null : sPreloadedColorStateLists.get(key);
if (factory != null) {
return factory.newInstance();
}
@@ -2690,7 +2820,7 @@ public class Resources {
}
final android.content.res.ConstantState<ColorStateList> factory =
- sPreloadedColorStateLists.get(key);
+ mAssets.hasThemedAssets() ? null : sPreloadedColorStateLists.get(key);
if (factory != null) {
csl = factory.newInstance(this, theme);
}
@@ -2845,6 +2975,28 @@ public class Resources {
return theme.obtainStyledAttributes(set, attrs, 0, 0);
}
+ /** @hide */
+ public void setIconResources(SparseArray<PackageItemInfo> icons) {
+ mIcons = icons;
+ }
+
+ /** @hide */
+ public void setComposedIconInfo(ComposedIconInfo iconInfo) {
+ mComposedIconInfo = iconInfo;
+ }
+
+ /** @hide */
+ public ComposedIconInfo getComposedIconInfo() {
+ return mComposedIconInfo;
+ }
+
+ /** @hide */
+ public final void updateStringCache() {
+ synchronized (mAccessLock) {
+ mAssets.recreateStringBlocks();
+ }
+ }
+
private Resources() {
mAssets = AssetManager.getSystem();
// NOTE: Intentionally leaving this uninitialized (all values set
diff --git a/core/java/android/content/res/ResourcesKey.java b/core/java/android/content/res/ResourcesKey.java
index 2620571..6cbf1d7 100644
--- a/core/java/android/content/res/ResourcesKey.java
+++ b/core/java/android/content/res/ResourcesKey.java
@@ -24,25 +24,31 @@ import java.util.Objects;
public final class ResourcesKey {
private final String mResDir;
private final float mScale;
+ private final boolean mIsThemeable;
private final int mHash;
+ private final ThemeConfig mThemeConfig;
public final int mDisplayId;
@NonNull
public final Configuration mOverrideConfiguration;
public ResourcesKey(String resDir, int displayId, Configuration overrideConfiguration,
- float scale) {
+ float scale, boolean isThemeable, ThemeConfig themeConfig) {
mResDir = resDir;
mDisplayId = displayId;
mOverrideConfiguration = overrideConfiguration != null
? overrideConfiguration : Configuration.EMPTY;
mScale = scale;
+ mIsThemeable = isThemeable;
+ mThemeConfig = themeConfig;
int hash = 17;
hash = 31 * hash + (mResDir == null ? 0 : mResDir.hashCode());
hash = 31 * hash + mDisplayId;
hash = 31 * hash + mOverrideConfiguration.hashCode();
hash = 31 * hash + Float.floatToIntBits(mScale);
+ hash = 31 * hash + (mIsThemeable ? 1 : 0);
+ hash = 31 * hash + (themeConfig != null ? themeConfig.hashCode() : 0);
mHash = hash;
}
@@ -74,6 +80,17 @@ public final class ResourcesKey {
if (mScale != peer.mScale) {
return false;
}
+ if (mIsThemeable != peer.mIsThemeable) {
+ return false;
+ }
+ if (mThemeConfig != peer.mThemeConfig) {
+ if (mThemeConfig == null || peer.mThemeConfig == null) {
+ return false;
+ }
+ if (!mThemeConfig.equals(peer.mThemeConfig)) {
+ return false;
+ }
+ }
return true;
}
diff --git a/core/java/android/content/res/ThemeChangeRequest.aidl b/core/java/android/content/res/ThemeChangeRequest.aidl
new file mode 100644
index 0000000..e6cf115
--- /dev/null
+++ b/core/java/android/content/res/ThemeChangeRequest.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2015 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.content.res;
+
+/** @hide */
+parcelable ThemeChangeRequest;
diff --git a/core/java/android/content/res/ThemeChangeRequest.java b/core/java/android/content/res/ThemeChangeRequest.java
new file mode 100644
index 0000000..1d13bb0
--- /dev/null
+++ b/core/java/android/content/res/ThemeChangeRequest.java
@@ -0,0 +1,307 @@
+/*
+ * Copyright (C) 2015 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.content.res;
+
+import android.content.pm.ThemeUtils;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+
+import static android.provider.ThemesContract.ThemesColumns.*;
+
+/** @hide */
+public final class ThemeChangeRequest implements Parcelable {
+ public static final int DEFAULT_WALLPAPER_ID = -1;
+
+ private final Map<String, String> mThemeComponents = new HashMap<String, String>();
+ private final Map<String, String> mPerAppOverlays = new HashMap<String, String>();
+ private RequestType mRequestType;
+ private long mWallpaperId = -1;
+
+ public String getOverlayThemePackageName() {
+ return getThemePackageNameForComponent(MODIFIES_OVERLAYS);
+ }
+
+ public String getStatusBarThemePackageName() {
+ return getThemePackageNameForComponent(MODIFIES_STATUS_BAR);
+ }
+
+ public String getNavBarThemePackageName() {
+ return getThemePackageNameForComponent(MODIFIES_NAVIGATION_BAR);
+ }
+
+ public String getFontThemePackageName() {
+ return getThemePackageNameForComponent(MODIFIES_FONTS);
+ }
+
+ public String getIconsThemePackageName() {
+ return getThemePackageNameForComponent(MODIFIES_ICONS);
+ }
+
+ public String getBootanimationThemePackageName() {
+ return getThemePackageNameForComponent(MODIFIES_BOOT_ANIM);
+ }
+
+ public String getWallpaperThemePackageName() {
+ return getThemePackageNameForComponent(MODIFIES_LAUNCHER);
+ }
+
+ public String getLockWallpaperThemePackageName() {
+ return getThemePackageNameForComponent(MODIFIES_LOCKSCREEN);
+ }
+
+ public String getAlarmThemePackageName() {
+ return getThemePackageNameForComponent(MODIFIES_ALARMS);
+ }
+
+ public String getNotificationThemePackageName() {
+ return getThemePackageNameForComponent(MODIFIES_NOTIFICATIONS);
+ }
+
+ public String getRingtoneThemePackageName() {
+ return getThemePackageNameForComponent(MODIFIES_RINGTONES);
+ }
+
+ public String getLiveLockScreenThemePackageName() {
+ return getThemePackageNameForComponent(MODIFIES_LIVE_LOCK_SCREEN);
+ }
+
+ public final Map<String, String> getThemeComponentsMap() {
+ return Collections.unmodifiableMap(mThemeComponents);
+ }
+
+ public long getWallpaperId() {
+ return mWallpaperId;
+ }
+
+ /**
+ * Get the mapping for per app themes
+ * @return A mapping of apps and the theme to apply for each one. or null if none set.
+ */
+ public final Map<String, String> getPerAppOverlays() {
+ return Collections.unmodifiableMap(mPerAppOverlays);
+ }
+
+ public int getNumChangesRequested() {
+ return mThemeComponents.size() + mPerAppOverlays.size();
+ }
+
+ public RequestType getReqeustType() {
+ return mRequestType;
+ }
+
+ private String getThemePackageNameForComponent(String componentName) {
+ return mThemeComponents.get(componentName);
+ }
+
+ private ThemeChangeRequest(Map<String, String> components, Map<String, String> perAppThemes,
+ RequestType requestType, long wallpaperId) {
+ if (components != null) {
+ mThemeComponents.putAll(components);
+ }
+ if (perAppThemes != null) {
+ mPerAppOverlays.putAll(perAppThemes);
+ }
+ mRequestType = requestType;
+ mWallpaperId = wallpaperId;
+ }
+
+ private ThemeChangeRequest(Parcel source) {
+ int numComponents = source.readInt();
+ for (int i = 0; i < numComponents; i++) {
+ mThemeComponents.put(source.readString(), source.readString());
+ }
+
+ numComponents = source.readInt();
+ for (int i = 0 ; i < numComponents; i++) {
+ mPerAppOverlays.put(source.readString(), source.readString());
+ }
+ mRequestType = RequestType.values()[source.readInt()];
+ mWallpaperId = source.readLong();
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(mThemeComponents.size());
+ for (String component : mThemeComponents.keySet()) {
+ dest.writeString(component);
+ dest.writeString(mThemeComponents.get(component));
+ }
+ dest.writeInt((mPerAppOverlays.size()));
+ for (String appPkgName : mPerAppOverlays.keySet()) {
+ dest.writeString(appPkgName);
+ dest.writeString(mPerAppOverlays.get(appPkgName));
+ }
+ dest.writeInt(mRequestType.ordinal());
+ dest.writeLong(mWallpaperId);
+ }
+
+ public static final Parcelable.Creator<ThemeChangeRequest> CREATOR =
+ new Parcelable.Creator<ThemeChangeRequest>() {
+ @Override
+ public ThemeChangeRequest createFromParcel(Parcel source) {
+ return new ThemeChangeRequest(source);
+ }
+
+ @Override
+ public ThemeChangeRequest[] newArray(int size) {
+ return new ThemeChangeRequest[size];
+ }
+ };
+
+ public enum RequestType {
+ USER_REQUEST,
+ USER_REQUEST_MIXNMATCH,
+ THEME_UPDATED,
+ THEME_REMOVED,
+ THEME_RESET;
+ }
+
+ public static class Builder {
+ Map<String, String> mThemeComponents = new HashMap<String, String>();
+ Map<String, String> mPerAppOverlays = new HashMap<String, String>();
+ RequestType mRequestType = RequestType.USER_REQUEST;
+ long mWallpaperId;
+
+ public Builder() {}
+
+ public Builder(ThemeConfig themeConfig) {
+ if (themeConfig != null) {
+ buildChangeRequestFromThemeConfig(themeConfig);
+ }
+ }
+
+ public Builder setOverlay(String pkgName) {
+ return setComponent(MODIFIES_OVERLAYS, pkgName);
+ }
+
+ public Builder setStatusBar(String pkgName) {
+ return setComponent(MODIFIES_STATUS_BAR, pkgName);
+ }
+
+ public Builder setNavBar(String pkgName) {
+ return setComponent(MODIFIES_NAVIGATION_BAR, pkgName);
+ }
+
+ public Builder setFont(String pkgName) {
+ return setComponent(MODIFIES_FONTS, pkgName);
+ }
+
+ public Builder setIcons(String pkgName) {
+ return setComponent(MODIFIES_ICONS, pkgName);
+ }
+
+ public Builder setBootanimation(String pkgName) {
+ return setComponent(MODIFIES_BOOT_ANIM, pkgName);
+ }
+
+ public Builder setWallpaper(String pkgName) {
+ return setComponent(MODIFIES_LAUNCHER, pkgName);
+ }
+
+ // Used in the case that more than one wallpaper exists for a given pkg name
+ public Builder setWallpaperId(long id) {
+ mWallpaperId = id;
+ return this;
+ }
+
+ public Builder setLockWallpaper(String pkgName) {
+ return setComponent(MODIFIES_LOCKSCREEN, pkgName);
+ }
+
+ public Builder setAlarm(String pkgName) {
+ return setComponent(MODIFIES_ALARMS, pkgName);
+ }
+
+ public Builder setNotification(String pkgName) {
+ return setComponent(MODIFIES_NOTIFICATIONS, pkgName);
+ }
+
+ public Builder setRingtone(String pkgName) {
+ return setComponent(MODIFIES_RINGTONES, pkgName);
+ }
+
+ public Builder setLiveLockScreen(String pkgName) {
+ return setComponent(MODIFIES_LIVE_LOCK_SCREEN, pkgName);
+ }
+
+ public Builder setComponent(String component, String pkgName) {
+ if (pkgName != null) {
+ mThemeComponents.put(component, pkgName);
+ } else {
+ mThemeComponents.remove(component);
+ }
+ return this;
+ }
+
+ public Builder setAppOverlay(String appPkgName, String themePkgName) {
+ if (appPkgName != null) {
+ if (themePkgName != null) {
+ mPerAppOverlays.put(appPkgName, themePkgName);
+ } else {
+ mPerAppOverlays.remove(appPkgName);
+ }
+ }
+
+ return this;
+ }
+
+ public Builder setRequestType(RequestType requestType) {
+ mRequestType = requestType != null ? requestType : RequestType.USER_REQUEST;
+ return this;
+ }
+
+ public ThemeChangeRequest build() {
+ return new ThemeChangeRequest(mThemeComponents, mPerAppOverlays,
+ mRequestType, mWallpaperId);
+ }
+
+ private void buildChangeRequestFromThemeConfig(ThemeConfig themeConfig) {
+ if (themeConfig.getFontPkgName() != null) {
+ this.setFont(themeConfig.getFontPkgName());
+ }
+ if (themeConfig.getIconPackPkgName() != null) {
+ this.setIcons(themeConfig.getIconPackPkgName());
+ }
+ if (themeConfig.getOverlayPkgName() != null) {
+ this.setOverlay(themeConfig.getOverlayPkgName());
+ }
+ if (themeConfig.getOverlayForStatusBar() != null) {
+ this.setStatusBar(themeConfig.getOverlayForStatusBar());
+ }
+ if (themeConfig.getOverlayForNavBar() != null) {
+ this.setNavBar(themeConfig.getOverlayForNavBar());
+ }
+
+ // Check if there are any per-app overlays using this theme
+ final Map<String, ThemeConfig.AppTheme> themes = themeConfig.getAppThemes();
+ for (String appPkgName : themes.keySet()) {
+ if (ThemeUtils.isPerAppThemeComponent(appPkgName)) {
+ this.setAppOverlay(appPkgName, themes.get(appPkgName).getOverlayPkgName());
+ }
+ }
+ }
+ }
+}
diff --git a/core/java/android/content/res/ThemeConfig.java b/core/java/android/content/res/ThemeConfig.java
new file mode 100644
index 0000000..ac95d6b
--- /dev/null
+++ b/core/java/android/content/res/ThemeConfig.java
@@ -0,0 +1,599 @@
+/*
+ * Copyright (C) 2014 The CyanogenMod Project
+ * Portions copyright (C) 2014, T-Mobile USA, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.content.res;
+
+import android.content.ContentResolver;
+import android.content.res.ThemeChangeRequest.RequestType;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.text.TextUtils;
+import android.util.JsonReader;
+import android.util.JsonToken;
+import android.util.JsonWriter;
+import android.util.Log;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+
+/**
+ * The Theme Configuration allows lookup of a theme element (fonts, icon, overlay) for a given
+ * application. If there isn't a particular theme designated to an app, it will fallback on the
+ * default theme. If there isn't a default theme then it will simply fallback to holo.
+ *
+ * @hide
+ */
+public class ThemeConfig implements Cloneable, Parcelable, Comparable<ThemeConfig> {
+ public static final String TAG = ThemeConfig.class.getCanonicalName();
+ public static final String SYSTEM_DEFAULT = "system";
+
+ /**
+ * Special package name for theming the navbar separate from the rest of SystemUI
+ */
+ public static final String SYSTEMUI_NAVBAR_PKG = "com.android.systemui.navbar";
+ public static final String SYSTEMUI_STATUS_BAR_PKG = "com.android.systemui";
+
+ // Key for any app which does not have a specific theme applied
+ private static final String KEY_DEFAULT_PKG = "default";
+ private static final SystemConfig mSystemConfig = new SystemConfig();
+ private static final SystemAppTheme mSystemAppTheme = new SystemAppTheme();
+
+ // Maps pkgname to theme (ex com.angry.birds -> red theme)
+ protected final Map<String, AppTheme> mThemes = new HashMap<String, AppTheme>();
+
+ private RequestType mLastThemeChangeRequestType = RequestType.USER_REQUEST;
+
+ public ThemeConfig(Map<String, AppTheme> appThemes) {
+ mThemes.putAll(appThemes);
+ }
+
+ public String getOverlayPkgName() {
+ AppTheme theme = getDefaultTheme();
+ return theme.mOverlayPkgName;
+ }
+
+ public String getOverlayForStatusBar() {
+ return getOverlayPkgNameForApp(SYSTEMUI_STATUS_BAR_PKG);
+ }
+
+ public String getOverlayForNavBar() {
+ return getOverlayPkgNameForApp(SYSTEMUI_NAVBAR_PKG);
+ }
+
+ public String getOverlayPkgNameForApp(String appPkgName) {
+ AppTheme theme = getThemeFor(appPkgName);
+ return theme.mOverlayPkgName;
+ }
+
+ public String getIconPackPkgName() {
+ AppTheme theme = getDefaultTheme();
+ return theme.mIconPkgName;
+ }
+
+ public String getIconPackPkgNameForApp(String appPkgName) {
+ AppTheme theme = getThemeFor(appPkgName);
+ return theme.mIconPkgName;
+ }
+
+ public String getFontPkgName() {
+ AppTheme defaultTheme = getDefaultTheme();
+ return defaultTheme.mFontPkgName;
+ }
+
+ public String getFontPkgNameForApp(String appPkgName) {
+ AppTheme theme = getThemeFor(appPkgName);
+ return theme.mFontPkgName;
+ }
+
+ public Map<String, AppTheme> getAppThemes() {
+ return Collections.unmodifiableMap(mThemes);
+ }
+
+ public RequestType getLastThemeChangeRequestType() {
+ return mLastThemeChangeRequestType;
+ }
+
+ private AppTheme getThemeFor(String pkgName) {
+ AppTheme theme = mThemes.get(pkgName);
+ if (theme == null) theme = getDefaultTheme();
+ return theme;
+ }
+
+ private AppTheme getDefaultTheme() {
+ AppTheme theme = mThemes.get(KEY_DEFAULT_PKG);
+ if (theme == null) theme = mSystemAppTheme;
+ return theme;
+ }
+
+ @Override
+ public boolean equals(Object object) {
+ if (object == this) {
+ return true;
+ }
+ if (object instanceof ThemeConfig) {
+ ThemeConfig o = (ThemeConfig) object;
+
+ Map<String, AppTheme> currThemes = (mThemes == null) ?
+ new HashMap<String, AppTheme>() : mThemes;
+ Map<String, AppTheme> newThemes = (o.mThemes == null) ?
+ new HashMap<String, AppTheme>() : o.mThemes;
+
+ return (currThemes.equals(newThemes) &&
+ mLastThemeChangeRequestType == o.mLastThemeChangeRequestType);
+ }
+ return false;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder result = new StringBuilder();
+ if (mThemes != null) {
+ result.append("themes:");
+ result.append(mThemes);
+ }
+ return result.toString();
+ }
+
+ @Override
+ public int hashCode() {
+ int hash = 17;
+ hash = 31 * hash + mThemes.hashCode();
+ hash = 31 * hash + (mLastThemeChangeRequestType == null ? 0 :
+ mLastThemeChangeRequestType.ordinal());
+ return hash;
+ }
+
+ public String toJson() {
+ return JsonSerializer.toJson(this);
+ }
+
+ public static ThemeConfig fromJson(String json) {
+ return JsonSerializer.fromJson(json);
+ }
+
+ /**
+ * Represents the theme that the device booted into. This is used to
+ * simulate a "default" configuration based on the user's last known
+ * preference until the theme is switched at runtime.
+ */
+ public static ThemeConfig getBootTheme(ContentResolver resolver) {
+ return getBootThemeForUser(resolver, UserHandle.USER_OWNER);
+ }
+
+ public static ThemeConfig getBootThemeForUser(ContentResolver resolver, int userHandle) {
+ ThemeConfig bootTheme = mSystemConfig;
+ try {
+ String json = Settings.Secure.getStringForUser(resolver,
+ Configuration.THEME_PKG_CONFIGURATION_PERSISTENCE_PROPERTY, userHandle);
+ bootTheme = ThemeConfig.fromJson(json);
+
+ // Handle upgrade Case: Previously the theme configuration was in separate fields
+ if (bootTheme == null) {
+ String overlayPkgName = Settings.Secure.getStringForUser(resolver,
+ Configuration.THEME_PACKAGE_NAME_PERSISTENCE_PROPERTY, userHandle);
+ String iconPackPkgName = Settings.Secure.getStringForUser(resolver,
+ Configuration.THEME_ICONPACK_PACKAGE_NAME_PERSISTENCE_PROPERTY, userHandle);
+ String fontPkgName = Settings.Secure.getStringForUser(resolver,
+ Configuration.THEME_FONT_PACKAGE_NAME_PERSISTENCE_PROPERTY, userHandle);
+
+ Builder builder = new Builder();
+ builder.defaultOverlay(overlayPkgName);
+ builder.defaultIcon(iconPackPkgName);
+ builder.defaultFont(fontPkgName);
+ bootTheme = builder.build();
+ }
+ } catch (SecurityException e) {
+ Log.w(TAG, "Could not get boot theme");
+ }
+ return bootTheme;
+ }
+
+ /**
+ * Represents the system framework theme, perceived by the system as there
+ * being no theme applied.
+ */
+ public static ThemeConfig getSystemTheme() {
+ return mSystemConfig;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ String json = JsonSerializer.toJson(this);
+ dest.writeString(json);
+ dest.writeInt(mLastThemeChangeRequestType.ordinal());
+ }
+
+ public static final Parcelable.Creator<ThemeConfig> CREATOR =
+ new Parcelable.Creator<ThemeConfig>() {
+ public ThemeConfig createFromParcel(Parcel source) {
+ String json = source.readString();
+ ThemeConfig themeConfig = JsonSerializer.fromJson(json);
+ themeConfig.mLastThemeChangeRequestType = RequestType.values()[source.readInt()];
+ return themeConfig;
+ }
+
+ public ThemeConfig[] newArray(int size) {
+ return new ThemeConfig[size];
+ }
+ };
+
+ @Override
+ public int compareTo(ThemeConfig o) {
+ if (o == null) return -1;
+ int n = 0;
+ n = mThemes.equals(o.mThemes) ? 0 : 1;
+ return n;
+ }
+
+ public Object clone() {
+ try {
+ return super.clone();
+ } catch (CloneNotSupportedException e) {
+ Log.d(TAG, "clone not supported", e);
+ return null;
+ }
+ }
+
+ public static class AppTheme implements Cloneable, Comparable<AppTheme> {
+ // If any field is modified or added here be sure to change the serializer accordingly
+ String mOverlayPkgName;
+ String mIconPkgName;
+ String mFontPkgName;
+
+ public AppTheme(String overlayPkgName, String iconPkgName, String fontPkgName) {
+ mOverlayPkgName = overlayPkgName;
+ mIconPkgName = iconPkgName;
+ mFontPkgName = fontPkgName;
+ }
+
+ public String getIconPackPkgName() {
+ return mIconPkgName;
+ }
+
+ public String getOverlayPkgName() {
+ return mOverlayPkgName;
+ }
+
+ public String getFontPackPkgName() {
+ return mFontPkgName;
+ }
+
+ @Override
+ public synchronized int hashCode() {
+ int hash = 17;
+ hash = 31 * hash + (mOverlayPkgName == null ? 0 : mOverlayPkgName.hashCode());
+ hash = 31 * hash + (mIconPkgName == null ? 0 : mIconPkgName.hashCode());
+ hash = 31 * hash + (mFontPkgName == null ? 0 : mFontPkgName.hashCode());
+ return hash;
+ }
+
+ @Override
+ public int compareTo(AppTheme o) {
+ if (o == null) return -1;
+ int n = 0;
+ n = mIconPkgName.compareTo(o.mIconPkgName);
+ if (n != 0) return n;
+ n = mFontPkgName.compareTo(o.mFontPkgName);
+ if (n != 0) return n;
+ n = mOverlayPkgName.equals(o.mOverlayPkgName) ? 0 : 1;
+ return n;
+ }
+
+ @Override
+ public boolean equals(Object object) {
+ if (object == this) {
+ return true;
+ }
+ if (object instanceof AppTheme) {
+ AppTheme o = (AppTheme) object;
+ String currentOverlayPkgName = (mOverlayPkgName == null)? "" : mOverlayPkgName;
+ String newOverlayPkgName = (o.mOverlayPkgName == null)? "" : o.mOverlayPkgName;
+ String currentIconPkgName = (mIconPkgName == null)? "" : mIconPkgName;
+ String newIconPkgName = (o.mIconPkgName == null)? "" : o.mIconPkgName;
+ String currentFontPkgName = (mFontPkgName == null)? "" : mFontPkgName;
+ String newFontPkgName = (o.mFontPkgName == null)? "" : o.mFontPkgName;
+
+
+ return (currentIconPkgName.equals(newIconPkgName) &&
+ currentFontPkgName.equals(newFontPkgName) &&
+ currentOverlayPkgName.equals(newOverlayPkgName));
+ }
+ return false;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder result = new StringBuilder();
+ if (mOverlayPkgName != null) {
+ result.append("overlay:");
+ result.append(mOverlayPkgName);
+ }
+
+ if (!TextUtils.isEmpty(mIconPkgName)) {
+ result.append(", iconPack:");
+ result.append(mIconPkgName);
+ }
+
+ if (!TextUtils.isEmpty(mFontPkgName)) {
+ result.append(", fontPkg:");
+ result.append(mFontPkgName);
+ }
+ return result.toString();
+ }
+ }
+
+
+ public static class Builder {
+ private HashMap<String, String> mOverlays = new HashMap<String, String>();
+ private HashMap<String, String> mIcons = new HashMap<String, String>();
+ private HashMap<String, String> mFonts = new HashMap<String, String>();
+ private RequestType mLastThemeChangeRequestType = RequestType.USER_REQUEST;
+
+ public Builder() {}
+
+ public Builder(ThemeConfig theme) {
+ for(Map.Entry<String, AppTheme> entry : theme.mThemes.entrySet()) {
+ String key = entry.getKey();
+ AppTheme appTheme = entry.getValue();
+ mFonts.put(key, appTheme.getFontPackPkgName());
+ mIcons.put(key, appTheme.getIconPackPkgName());
+ mOverlays.put(key, appTheme.getOverlayPkgName());
+ }
+ mLastThemeChangeRequestType = theme.mLastThemeChangeRequestType;
+ }
+
+ /**
+ * For uniquely theming a specific app. ex. "Dialer gets red theme,
+ * Calculator gets blue theme"
+ */
+ public Builder defaultOverlay(String themePkgName) {
+ if (themePkgName != null) {
+ mOverlays.put(KEY_DEFAULT_PKG, themePkgName);
+ } else {
+ mOverlays.remove(KEY_DEFAULT_PKG);
+ }
+ return this;
+ }
+
+ public Builder defaultFont(String themePkgName) {
+ if (themePkgName != null) {
+ mFonts.put(KEY_DEFAULT_PKG, themePkgName);
+ } else {
+ mFonts.remove(KEY_DEFAULT_PKG);
+ }
+ return this;
+ }
+
+ public Builder defaultIcon(String themePkgName) {
+ if (themePkgName != null) {
+ mIcons.put(KEY_DEFAULT_PKG, themePkgName);
+ } else {
+ mIcons.remove(KEY_DEFAULT_PKG);
+ }
+ return this;
+ }
+
+ public Builder icon(String appPkgName, String themePkgName) {
+ if (themePkgName != null) {
+ mIcons.put(appPkgName, themePkgName);
+ } else {
+ mIcons.remove(appPkgName);
+ }
+ return this;
+ }
+
+ public Builder overlay(String appPkgName, String themePkgName) {
+ if (themePkgName != null) {
+ mOverlays.put(appPkgName, themePkgName);
+ } else {
+ mOverlays.remove(appPkgName);
+ }
+ return this;
+ }
+
+ public Builder font(String appPkgName, String themePkgName) {
+ if (themePkgName != null) {
+ mFonts.put(appPkgName, themePkgName);
+ } else {
+ mFonts.remove(appPkgName);
+ }
+ return this;
+ }
+
+ public Builder setLastThemeChangeRequestType(RequestType requestType) {
+ mLastThemeChangeRequestType = requestType;
+ return this;
+ }
+
+ public ThemeConfig build() {
+ HashSet<String> appPkgSet = new HashSet<String>();
+ appPkgSet.addAll(mOverlays.keySet());
+ appPkgSet.addAll(mIcons.keySet());
+ appPkgSet.addAll(mFonts.keySet());
+
+ HashMap<String, AppTheme> appThemes = new HashMap<String, AppTheme>();
+ for(String appPkgName : appPkgSet) {
+ String icon = mIcons.get(appPkgName);
+ String overlay = mOverlays.get(appPkgName);
+ String font = mFonts.get(appPkgName);
+
+ // Remove app theme if all items are null
+ if (overlay == null && icon == null && font == null) {
+ if (appThemes.containsKey(appPkgName)) {
+ appThemes.remove(appPkgName);
+ }
+ } else {
+ AppTheme appTheme = new AppTheme(overlay, icon, font);
+ appThemes.put(appPkgName, appTheme);
+ }
+ }
+ ThemeConfig themeConfig = new ThemeConfig(appThemes);
+ themeConfig.mLastThemeChangeRequestType = mLastThemeChangeRequestType;
+ return themeConfig;
+ }
+ }
+
+
+ public static class JsonSerializer {
+ private static final String NAME_OVERLAY_PKG = "mOverlayPkgName";
+ private static final String NAME_ICON_PKG = "mIconPkgName";
+ private static final String NAME_FONT_PKG = "mFontPkgName";
+
+ public static String toJson(ThemeConfig theme) {
+ String json = null;
+ Writer writer = null;
+ JsonWriter jsonWriter = null;
+ try {
+ writer = new StringWriter();
+ jsonWriter = new JsonWriter(writer);
+ writeTheme(jsonWriter, theme);
+ json = writer.toString();
+ } catch(IOException e) {
+ Log.e(TAG, "Could not write theme mapping", e);
+ } finally {
+ closeQuietly(writer);
+ closeQuietly(jsonWriter);
+ }
+ return json;
+ }
+
+ private static void writeTheme(JsonWriter writer, ThemeConfig theme)
+ throws IOException {
+ writer.beginObject();
+ for(Map.Entry<String, AppTheme> entry : theme.mThemes.entrySet()) {
+ String appPkgName = entry.getKey();
+ AppTheme appTheme = entry.getValue();
+ writer.name(appPkgName);
+ writeAppTheme(writer, appTheme);
+ }
+ writer.endObject();
+ }
+
+ private static void writeAppTheme(JsonWriter writer, AppTheme appTheme) throws IOException {
+ writer.beginObject();
+ writer.name(NAME_OVERLAY_PKG).value(appTheme.mOverlayPkgName);
+ writer.name(NAME_ICON_PKG).value(appTheme.mIconPkgName);
+ writer.name(NAME_FONT_PKG).value(appTheme.mFontPkgName);
+ writer.endObject();
+ }
+
+ public static ThemeConfig fromJson(String json) {
+ if (json == null) return null;
+ HashMap<String, AppTheme> map = new HashMap<String, AppTheme>();
+ StringReader reader = null;
+ JsonReader jsonReader = null;
+ try {
+ reader = new StringReader(json);
+ jsonReader = new JsonReader(reader);
+ jsonReader.beginObject();
+ while (jsonReader.hasNext()) {
+ String appPkgName = jsonReader.nextName();
+ AppTheme appTheme = readAppTheme(jsonReader);
+ map.put(appPkgName, appTheme);
+ }
+ jsonReader.endObject();
+ } catch(Exception e) {
+ Log.e(TAG, "Could not parse ThemeConfig from: " + json, e);
+ } finally {
+ closeQuietly(reader);
+ closeQuietly(jsonReader);
+ }
+ return new ThemeConfig(map);
+ }
+
+ private static AppTheme readAppTheme(JsonReader reader) throws IOException {
+ String overlay = null;
+ String icon = null;
+ String font = null;
+
+ reader.beginObject();
+ while(reader.hasNext()) {
+ String name = reader.nextName();
+ if (NAME_OVERLAY_PKG.equals(name) && reader.peek() != JsonToken.NULL) {
+ overlay = reader.nextString();
+ } else if (NAME_ICON_PKG.equals(name) && reader.peek() != JsonToken.NULL) {
+ icon = reader.nextString();
+ } else if (NAME_FONT_PKG.equals(name) && reader.peek() != JsonToken.NULL) {
+ font = reader.nextString();
+ } else {
+ reader.skipValue();
+ }
+ }
+ reader.endObject();
+
+ return new AppTheme(overlay, icon, font);
+ }
+
+ private static void closeQuietly(Reader reader) {
+ try {
+ if (reader != null) reader.close();
+ } catch(IOException e) {
+ }
+ }
+
+ private static void closeQuietly(JsonReader reader) {
+ try {
+ if (reader != null) reader.close();
+ } catch(IOException e) {
+ }
+ }
+
+ private static void closeQuietly(Writer writer) {
+ try {
+ if (writer != null) writer.close();
+ } catch(IOException e) {
+ }
+ }
+
+ private static void closeQuietly(JsonWriter writer) {
+ try {
+ if (writer != null) writer.close();
+ } catch(IOException e) {
+ }
+ }
+ }
+
+ public static class SystemConfig extends ThemeConfig {
+ public SystemConfig() {
+ super(new HashMap<String, AppTheme>());
+ }
+ }
+
+ public static class SystemAppTheme extends AppTheme {
+ public SystemAppTheme() {
+ super(SYSTEM_DEFAULT, SYSTEM_DEFAULT, SYSTEM_DEFAULT);
+ }
+
+ @Override
+ public String toString() {
+ return "No Theme Applied (Holo)";
+ }
+ }
+}
diff --git a/core/java/android/content/res/ThemeManager.java b/core/java/android/content/res/ThemeManager.java
new file mode 100644
index 0000000..fd05f1e
--- /dev/null
+++ b/core/java/android/content/res/ThemeManager.java
@@ -0,0 +1,316 @@
+/*
+ * Copyright (C) 2014 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.content.res;
+
+import android.content.Context;
+import android.content.pm.ThemeUtils;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.RemoteException;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * {@hide}
+ */
+public class ThemeManager {
+ private static final String TAG = ThemeManager.class.getName();
+ private Context mContext;
+ private IThemeService mService;
+ private Handler mHandler;
+
+ private Set<ThemeChangeListener> mChangeListeners =
+ new HashSet<ThemeChangeListener>();
+
+ private Set<ThemeProcessingListener> mProcessingListeners =
+ new HashSet<ThemeProcessingListener>();
+
+ public ThemeManager(Context context, IThemeService service) {
+ mContext = context;
+ mService = service;
+ mHandler = new Handler(Looper.getMainLooper());
+ }
+
+ private final IThemeChangeListener mThemeChangeListener = new IThemeChangeListener.Stub() {
+ @Override
+ public void onProgress(final int progress) throws RemoteException {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ synchronized (mChangeListeners) {
+ List<ThemeChangeListener> listenersToRemove = new ArrayList
+ <ThemeChangeListener>();
+ for (ThemeChangeListener listener : mChangeListeners) {
+ try {
+ listener.onProgress(progress);
+ } catch (Throwable e) {
+ Log.w(TAG, "Unable to update theme change progress", e);
+ listenersToRemove.add(listener);
+ }
+ }
+ if (listenersToRemove.size() > 0) {
+ for (ThemeChangeListener listener : listenersToRemove) {
+ mChangeListeners.remove(listener);
+ }
+ }
+ }
+ }
+ });
+ }
+
+ @Override
+ public void onFinish(final boolean isSuccess) throws RemoteException {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ synchronized (mChangeListeners) {
+ List<ThemeChangeListener> listenersToRemove = new ArrayList
+ <ThemeChangeListener>();
+ for (ThemeChangeListener listener : mChangeListeners) {
+ try {
+ listener.onFinish(isSuccess);
+ } catch (Throwable e) {
+ Log.w(TAG, "Unable to update theme change listener", e);
+ listenersToRemove.add(listener);
+ }
+ }
+ if (listenersToRemove.size() > 0) {
+ for (ThemeChangeListener listener : listenersToRemove) {
+ mChangeListeners.remove(listener);
+ }
+ }
+ }
+ }
+ });
+ }
+ };
+
+ private final IThemeProcessingListener mThemeProcessingListener =
+ new IThemeProcessingListener.Stub() {
+ @Override
+ public void onFinishedProcessing(final String pkgName) throws RemoteException {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ synchronized (mProcessingListeners) {
+ List<ThemeProcessingListener> listenersToRemove = new ArrayList
+ <ThemeProcessingListener>();
+ for (ThemeProcessingListener listener : mProcessingListeners) {
+ try {
+ listener.onFinishedProcessing(pkgName);
+ } catch (Throwable e) {
+ Log.w(TAG, "Unable to update theme change progress", e);
+ listenersToRemove.add(listener);
+ }
+ }
+ if (listenersToRemove.size() > 0) {
+ for (ThemeProcessingListener listener : listenersToRemove) {
+ mProcessingListeners.remove(listener);
+ }
+ }
+ }
+ }
+ });
+ }
+ };
+
+
+ public void addClient(ThemeChangeListener listener) {
+ synchronized (mChangeListeners) {
+ if (mChangeListeners.contains(listener)) {
+ throw new IllegalArgumentException("Client was already added ");
+ }
+ if (mChangeListeners.size() == 0) {
+ try {
+ mService.requestThemeChangeUpdates(mThemeChangeListener);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Unable to register listener", e);
+ }
+ }
+ mChangeListeners.add(listener);
+ }
+ }
+
+ public void removeClient(ThemeChangeListener listener) {
+ synchronized (mChangeListeners) {
+ mChangeListeners.remove(listener);
+ if (mChangeListeners.size() == 0) {
+ try {
+ mService.removeUpdates(mThemeChangeListener);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Unable to remove listener", e);
+ }
+ }
+ }
+ }
+
+ public void onClientPaused(ThemeChangeListener listener) {
+ removeClient(listener);
+ }
+
+ public void onClientResumed(ThemeChangeListener listener) {
+ addClient(listener);
+ }
+
+ public void onClientDestroyed(ThemeChangeListener listener) {
+ removeClient(listener);
+ }
+
+ /**
+ * Register a ThemeProcessingListener to be notified when a theme is done being processed.
+ * @param listener ThemeChangeListener to register
+ */
+ public void registerProcessingListener(ThemeProcessingListener listener) {
+ synchronized (mProcessingListeners) {
+ if (mProcessingListeners.contains(listener)) {
+ throw new IllegalArgumentException("Listener was already added ");
+ }
+ if (mProcessingListeners.size() == 0) {
+ try {
+ mService.registerThemeProcessingListener(mThemeProcessingListener);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Unable to register listener", e);
+ }
+ }
+ mProcessingListeners.add(listener);
+ }
+ }
+
+ /**
+ * Unregister a ThemeChangeListener.
+ * @param listener ThemeChangeListener to unregister
+ */
+ public void unregisterProcessingListener(ThemeChangeListener listener) {
+ synchronized (mProcessingListeners) {
+ mProcessingListeners.remove(listener);
+ if (mProcessingListeners.size() == 0) {
+ try {
+ mService.unregisterThemeProcessingListener(mThemeProcessingListener);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Unable to remove listener", e);
+ }
+ }
+ }
+ }
+
+ /**
+ * Convenience method. Applies the entire theme.
+ */
+ public void requestThemeChange(String pkgName) {
+ //List<String> components = ThemeUtils.getSupportedComponents(mContext, pkgName);
+ //requestThemeChange(pkgName, components);
+ }
+
+ public void requestThemeChange(String pkgName, List<String> components) {
+ requestThemeChange(pkgName, components, true);
+ }
+
+ public void requestThemeChange(String pkgName, List<String> components,
+ boolean removePerAppThemes) {
+ Map<String, String> componentMap = new HashMap<String, String>(components.size());
+ for (String component : components) {
+ componentMap.put(component, pkgName);
+ }
+ requestThemeChange(componentMap, removePerAppThemes);
+ }
+
+ public void requestThemeChange(Map<String, String> componentMap) {
+ requestThemeChange(componentMap, true);
+ }
+
+ public void requestThemeChange(Map<String, String> componentMap, boolean removePerAppThemes) {
+ ThemeChangeRequest.Builder builder = new ThemeChangeRequest.Builder();
+ for (String component : componentMap.keySet()) {
+ builder.setComponent(component, componentMap.get(component));
+ }
+
+ requestThemeChange(builder.build(), removePerAppThemes);
+ }
+
+ public void requestThemeChange(ThemeChangeRequest request, boolean removePerAppThemes) {
+ try {
+ mService.requestThemeChange(request, removePerAppThemes);
+ } catch (RemoteException e) {
+ logThemeServiceException(e);
+ }
+ }
+
+ public void applyDefaultTheme() {
+ try {
+ mService.applyDefaultTheme();
+ } catch (RemoteException e) {
+ logThemeServiceException(e);
+ }
+ }
+
+ public boolean isThemeApplying() {
+ try {
+ return mService.isThemeApplying();
+ } catch (RemoteException e) {
+ logThemeServiceException(e);
+ }
+
+ return false;
+ }
+
+ public boolean isThemeBeingProcessed(String themePkgName) {
+ try {
+ return mService.isThemeBeingProcessed(themePkgName);
+ } catch (RemoteException e) {
+ logThemeServiceException(e);
+ }
+ return false;
+ }
+
+ public int getProgress() {
+ try {
+ return mService.getProgress();
+ } catch (RemoteException e) {
+ logThemeServiceException(e);
+ }
+ return -1;
+ }
+
+ public boolean processThemeResources(String themePkgName) {
+ try {
+ return mService.processThemeResources(themePkgName);
+ } catch (RemoteException e) {
+ logThemeServiceException(e);
+ }
+ return false;
+ }
+
+ private void logThemeServiceException(Exception e) {
+ Log.w(TAG, "Unable to access ThemeService", e);
+ }
+
+ public interface ThemeChangeListener {
+ void onProgress(int progress);
+ void onFinish(boolean isSuccess);
+ }
+
+ public interface ThemeProcessingListener {
+ void onFinishedProcessing(String pkgName);
+ }
+}
+
diff --git a/core/java/android/database/sqlite/SQLiteConnection.java b/core/java/android/database/sqlite/SQLiteConnection.java
index 3cda39a..6ab9637 100644
--- a/core/java/android/database/sqlite/SQLiteConnection.java
+++ b/core/java/android/database/sqlite/SQLiteConnection.java
@@ -387,6 +387,8 @@ public final class SQLiteConnection implements CancellationSignal.OnCancelListen
} finally {
execute(success ? "COMMIT" : "ROLLBACK", null, null);
}
+ } catch (SQLiteDatabaseCorruptException ex) {
+ throw ex;
} catch (RuntimeException ex) {
throw new SQLiteException("Failed to change locale for db '" + mConfiguration.label
+ "' to '" + newLocale + "'.", ex);
diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java
index 1fc69c0..dc576a5 100644
--- a/core/java/android/hardware/Camera.java
+++ b/core/java/android/hardware/Camera.java
@@ -153,6 +153,10 @@ public class Camera {
private static final int CAMERA_MSG_RAW_IMAGE_NOTIFY = 0x200;
private static final int CAMERA_MSG_PREVIEW_METADATA = 0x400;
private static final int CAMERA_MSG_FOCUS_MOVE = 0x800;
+ /* ### QC ADD-ONS: START */
+ private static final int CAMERA_MSG_STATS_DATA = 0x1000;
+ private static final int CAMERA_MSG_META_DATA = 0x2000;
+ /* ### QC ADD-ONS: END */
private long mNativeContext; // accessed by native methods
private EventHandler mEventHandler;
@@ -180,6 +184,10 @@ public class Camera {
private static final int ENOSYS = -38;
private static final int EUSERS = -87;
private static final int EOPNOTSUPP = -95;
+ /* ### QC ADD-ONS: START */
+ private CameraDataCallback mCameraDataCallback;
+ private CameraMetaDataCallback mCameraMetaDataCallback;
+ /* ### QC ADD-ONS: END */
/**
* Broadcast Action: A new picture is taken by the camera, and the entry of
@@ -266,6 +274,17 @@ public class Camera {
*/
public static final int CAMERA_FACING_FRONT = 1;
+ /* ### QC ADD-ONS: START TBD*/
+ /** @hide
+ * camera is in ZSL mode.
+ */
+ public static final int CAMERA_SUPPORT_MODE_ZSL = 2;
+
+ /** @hide
+ * camera is in non-ZSL mode.
+ */
+ public static final int CAMERA_SUPPORT_MODE_NONZSL = 3;
+ /* ### QC ADD-ONS: END */
/**
* The direction that the camera faces. It should be
* CAMERA_FACING_BACK or CAMERA_FACING_FRONT.
@@ -450,6 +469,10 @@ public class Camera {
mPostviewCallback = null;
mUsingPreviewAllocation = false;
mZoomListener = null;
+ /* ### QC ADD-ONS: START */
+ mCameraDataCallback = null;
+ mCameraMetaDataCallback = null;
+ /* ### QC ADD-ONS: END */
Looper looper;
if ((looper = Looper.myLooper()) != null) {
@@ -766,6 +789,7 @@ public class Camera {
* @see android.media.MediaActionSound
*/
public final void setPreviewCallback(PreviewCallback cb) {
+ android.util.SeempLog.record(66);
mPreviewCallback = cb;
mOneShot = false;
mWithBuffer = false;
@@ -792,6 +816,7 @@ public class Camera {
* @see android.media.MediaActionSound
*/
public final void setOneShotPreviewCallback(PreviewCallback cb) {
+ android.util.SeempLog.record(68);
mPreviewCallback = cb;
mOneShot = true;
mWithBuffer = false;
@@ -830,6 +855,7 @@ public class Camera {
* @see android.media.MediaActionSound
*/
public final void setPreviewCallbackWithBuffer(PreviewCallback cb) {
+ android.util.SeempLog.record(67);
mPreviewCallback = cb;
mOneShot = false;
mWithBuffer = true;
@@ -1152,7 +1178,23 @@ public class Camera {
mAutoFocusMoveCallback.onAutoFocusMoving(msg.arg1 == 0 ? false : true, mCamera);
}
return;
+ /* ### QC ADD-ONS: START */
+ case CAMERA_MSG_STATS_DATA:
+ int statsdata[] = new int[257];
+ for(int i =0; i<257; i++ ) {
+ statsdata[i] = byteToInt( (byte[])msg.obj, i*4);
+ }
+ if (mCameraDataCallback != null) {
+ mCameraDataCallback.onCameraData(statsdata, mCamera);
+ }
+ return;
+ case CAMERA_MSG_META_DATA:
+ if (mCameraMetaDataCallback != null) {
+ mCameraMetaDataCallback.onCameraMetaData((byte[])msg.obj, mCamera);
+ }
+ return;
+ /* ### QC ADD-ONS: END */
default:
Log.e(TAG, "Unknown message type " + msg.what);
return;
@@ -1376,6 +1418,7 @@ public class Camera {
*/
public final void takePicture(ShutterCallback shutter, PictureCallback raw,
PictureCallback jpeg) {
+ android.util.SeempLog.record(65);
takePicture(shutter, raw, null, jpeg);
}
private native final void native_takePicture(int msgType);
@@ -1411,6 +1454,7 @@ public class Camera {
*/
public final void takePicture(ShutterCallback shutter, PictureCallback raw,
PictureCallback postview, PictureCallback jpeg) {
+ android.util.SeempLog.record(65);
mShutterCallback = shutter;
mRawImageCallback = raw;
mPostviewCallback = postview;
@@ -1579,6 +1623,20 @@ public class Camera {
private native final boolean _enableShutterSound(boolean enabled);
/**
+ * Send a vendor-specific camera command
+ *
+ * @hide
+ */
+ public final void sendVendorCommand(int cmd, int arg1, int arg2) {
+ if (cmd < 1000) {
+ throw new IllegalArgumentException("Command numbers must be at least 1000");
+ }
+ _sendVendorCommand(cmd, arg1, arg2);
+ }
+
+ private native final void _sendVendorCommand(int cmd, int arg1, int arg2);
+
+ /**
* Callback interface for zoom changes during a smooth zoom operation.
*
* @see #setZoomChangeListener(OnZoomChangeListener)
@@ -1800,6 +1858,23 @@ public class Camera {
* as a set. Either they are all valid, or none of them are.
*/
public Point mouth = null;
+
+ /**
+ * {@hide}
+ */
+ public int smileDegree = 0;
+ /**
+ * {@hide}
+ */
+ public int smileScore = 0;
+ /**
+ * {@hide}
+ */
+ public int blinkDetected = 0;
+ /**
+ * {@hide}
+ */
+ public int faceRecognised = 0;
}
/**
@@ -1892,6 +1967,27 @@ public class Camera {
return p;
}
+ /** @hide
+ * Returns the current cct value of white balance.
+ *
+ * If it's in AWB mode, cct is determined by stats/awb module.
+ *
+ * If it's in Manual WB mode, it actually returns cct value
+ * set by user via {@link #setParameters(Camera.Parameters)}.
+ */
+ public int getWBCurrentCCT() {
+ Parameters p = new Parameters();
+ String s = native_getParameters();
+ p.unflatten(s);
+
+ int cct = 0;
+ if (p.getWBCurrentCCT() != null) {
+ cct = Integer.parseInt(p.getWBCurrentCCT());
+ }
+
+ return cct;
+ }
+
/**
* Returns an empty {@link Parameters} for testing purpose.
*
@@ -1904,6 +2000,166 @@ public class Camera {
return camera.new Parameters();
}
+ /* ### QC ADD-ONS: START */
+ private static int byteToInt(byte[] b, int offset) {
+ int value = 0;
+ for (int i = 0; i < 4; i++) {
+ int shift = (4 - 1 - i) * 8;
+ value += (b[(3-i) + offset] & 0x000000FF) << shift;
+ }
+ return value;
+ }
+ /** @hide
+ * Handles the callback for when Camera Data is available.
+ * data is read from the camera.
+ */
+ public interface CameraDataCallback {
+ /**
+ * Callback for when camera data is available.
+ *
+ * @param data a int array of the camera data
+ * @param camera the Camera service object
+ */
+ void onCameraData(int[] data, Camera camera);
+ };
+
+ /** @hide
+ * Set camera histogram mode and registers a callback function to run.
+ * Only valid after startPreview() has been called.
+ *
+ * @param cb the callback to run
+ */
+ public final void setHistogramMode(CameraDataCallback cb)
+ {
+ mCameraDataCallback = cb;
+ native_setHistogramMode(cb!=null);
+ }
+ private native final void native_setHistogramMode(boolean mode);
+
+ /** @hide
+ * Set camera histogram command to send data.
+ *
+ */
+ public final void sendHistogramData()
+ {
+ native_sendHistogramData();
+ }
+ private native final void native_sendHistogramData();
+
+ /** @hide
+ * Handles the callback for when Camera Meta Data is available.
+ * Meta data is read from the camera.
+ */
+ public interface CameraMetaDataCallback {
+ /**
+ * Callback for when camera meta data is available.
+ *
+ * @param data a byte array of the camera meta data
+ * @param camera the Camera service object
+ */
+ void onCameraMetaData(byte[] data, Camera camera);
+ };
+
+ /** @hide
+ * Set camera meta data and registers a callback function to run.
+ * Only valid after startPreview() has been called.
+ *
+ * @param cb the callback to run
+ */
+ public final void setMetadataCb(CameraMetaDataCallback cb)
+ {
+ mCameraMetaDataCallback = cb;
+ native_setMetadataCb(cb!=null);
+ }
+ private native final void native_setMetadataCb(boolean mode);
+
+ /** @hide
+ * Set camera face detection command to send meta data.
+ */
+ public final void sendMetaData()
+ {
+ native_sendMetaData();
+ }
+ private native final void native_sendMetaData();
+
+ /** @hide
+ * Configure longshot mode. Available only in ZSL.
+ *
+ * @param enable enable/disable this mode
+ */
+ public final void setLongshot(boolean enable)
+ {
+ native_setLongshot(enable);
+ }
+ private native final void native_setLongshot(boolean enable);
+
+ /** @hide
+ * Stop longshot. Available only in ZSL.
+ */
+ public final void stopLongshot()
+ {
+ native_stopLongshot();
+ }
+ private native final void native_stopLongshot();
+
+ /** @hide
+ * Handles the Touch Co-ordinate.
+ */
+ public class Coordinate {
+ /**
+ * Sets the x,y co-ordinates for a touch event
+ *
+ * @param x the x co-ordinate (pixels)
+ * @param y the y co-ordinate (pixels)
+ */
+ public Coordinate(int x, int y) {
+ xCoordinate = x;
+ yCoordinate = y;
+ }
+ /**
+ * Compares {@code obj} to this co-ordinate.
+ *
+ * @param obj the object to compare this co-ordinate with.
+ * @return {@code true} if the xCoordinate and yCoordinate of {@code obj} is the
+ * same as those of this coordinate. {@code false} otherwise.
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof Coordinate)) {
+ return false;
+ }
+ Coordinate c = (Coordinate) obj;
+ return xCoordinate == c.xCoordinate && yCoordinate == c.yCoordinate;
+ }
+
+ /** x co-ordinate for the touch event*/
+ public int xCoordinate;
+
+ /** y co-ordinate for the touch event */
+ public int yCoordinate;
+ };
+
+ /** @hide
+ * Returns the current focus position.
+ *
+ * If it's in AF mode, it's the lens position after af is done.
+ *
+ * If it's in Manual Focus mode, it actually returns the value
+ * set by user via {@link #setParameters(Camera.Parameters)}.
+ */
+ public int getCurrentFocusPosition() {
+ Parameters p = new Parameters();
+ String s = native_getParameters();
+ p.unflatten(s);
+
+ int focus_pos = -1;
+ if (p.getCurrentFocusPosition() != null) {
+ focus_pos = Integer.parseInt(p.getCurrentFocusPosition());
+ }
+ return focus_pos;
+ }
+
+ /* ### QC ADD-ONS: END */
/**
* Returns a copied {@link Parameters}; for shim use only.
*
@@ -2151,6 +2407,10 @@ public class Camera {
public static final String WHITE_BALANCE_CLOUDY_DAYLIGHT = "cloudy-daylight";
public static final String WHITE_BALANCE_TWILIGHT = "twilight";
public static final String WHITE_BALANCE_SHADE = "shade";
+ /** @hide
+ * wb manual cct mode.
+ */
+ public static final String WHITE_BALANCE_MANUAL_CCT = "manual-cct";
// Values for color effect settings.
public static final String EFFECT_NONE = "none";
@@ -2198,6 +2458,11 @@ public class Camera {
*/
public static final String FLASH_MODE_TORCH = "torch";
+ /** @hide
+ * Scene mode is off.
+ */
+ public static final String SCENE_MODE_ASD = "asd";
+
/**
* Scene mode is off.
*/
@@ -2274,6 +2539,14 @@ public class Camera {
* Capture the naturally warm color of scenes lit by candles.
*/
public static final String SCENE_MODE_CANDLELIGHT = "candlelight";
+ /** @hide
+ * SCENE_MODE_BACKLIGHT
+ **/
+ public static final String SCENE_MODE_BACKLIGHT = "backlight";
+ /** @hide
+ * SCENE_MODE_FLOWERS
+ **/
+ public static final String SCENE_MODE_FLOWERS = "flowers";
/**
* Applications are looking for a barcode. Camera driver will be
@@ -2316,6 +2589,13 @@ public class Camera {
*/
public static final String FOCUS_MODE_FIXED = "fixed";
+ /** @hide
+ * Normal focus mode. Applications should call
+ * {@link #autoFocus(AutoFocusCallback)} to start the focus in this
+ * mode.
+ */
+ public static final String FOCUS_MODE_NORMAL = "normal";
+
/**
* Extended depth of field (EDOF). Focusing is done digitally and
* continuously. Applications should not call {@link
@@ -2368,6 +2648,11 @@ public class Camera {
*/
public static final String FOCUS_MODE_CONTINUOUS_PICTURE = "continuous-picture";
+ /** @hide
+ * manual focus mode
+ */
+ public static final String FOCUS_MODE_MANUAL_POSITION = "manual";
+
// Indices for focus distance array.
/**
* The array index of near focus distance for use with
@@ -2404,11 +2689,15 @@ public class Camera {
// Formats for setPreviewFormat and setPictureFormat.
private static final String PIXEL_FORMAT_YUV422SP = "yuv422sp";
private static final String PIXEL_FORMAT_YUV420SP = "yuv420sp";
+ private static final String PIXEL_FORMAT_YUV420SP_ADRENO = "yuv420sp-adreno";
private static final String PIXEL_FORMAT_YUV422I = "yuv422i-yuyv";
private static final String PIXEL_FORMAT_YUV420P = "yuv420p";
private static final String PIXEL_FORMAT_RGB565 = "rgb565";
private static final String PIXEL_FORMAT_JPEG = "jpeg";
private static final String PIXEL_FORMAT_BAYER_RGGB = "bayer-rggb";
+ private static final String PIXEL_FORMAT_RAW = "raw";
+ private static final String PIXEL_FORMAT_YV12 = "yv12";
+ private static final String PIXEL_FORMAT_NV12 = "nv12";
/**
* Order matters: Keys that are {@link #set(String, String) set} later
@@ -3196,8 +3485,11 @@ public class Camera {
* parameters.
*/
public void removeGpsData() {
+ remove(KEY_QC_GPS_LATITUDE_REF);
remove(KEY_GPS_LATITUDE);
+ remove(KEY_QC_GPS_LONGITUDE_REF);
remove(KEY_GPS_LONGITUDE);
+ remove(KEY_QC_GPS_ALTITUDE_REF);
remove(KEY_GPS_ALTITUDE);
remove(KEY_GPS_TIMESTAMP);
remove(KEY_GPS_PROCESSING_METHOD);
@@ -4088,6 +4380,7 @@ public class Camera {
splitter.setString(str);
int index = 0;
for (String s : splitter) {
+ s = s.replaceAll("\\s","");
output[index++] = Integer.parseInt(s);
}
}
@@ -4158,7 +4451,7 @@ public class Camera {
// Example string: "(10000,26623),(10000,30000)". Return null if the
// passing string is null or the size is 0.
private ArrayList<int[]> splitRange(String str) {
- if (str == null || str.charAt(0) != '('
+ if (str == null || str.isEmpty() || str.charAt(0) != '('
|| str.charAt(str.length() - 1) != ')') {
Log.e(TAG, "Invalid range list string=" + str);
return null;
@@ -4183,7 +4476,7 @@ public class Camera {
// Example string: "(-10,-10,0,0,300),(0,0,10,10,700)". Return null if
// the passing string is null or the size is 0 or (0,0,0,0,0).
private ArrayList<Area> splitArea(String str) {
- if (str == null || str.charAt(0) != '('
+ if (str == null || str.isEmpty() || str.charAt(0) != '('
|| str.charAt(str.length() - 1) != ')') {
Log.e(TAG, "Invalid area string=" + str);
return null;
@@ -4220,5 +4513,1231 @@ public class Camera {
if (s1 != null && s1.equals(s2)) return true;
return false;
}
+ /* ### QC ADD-ONS: START */
+
+ /* ### QC ADDED PARAMETER KEYS*/
+ private static final String KEY_QC_HFR_SIZE = "hfr-size";
+ private static final String KEY_QC_PREVIEW_FRAME_RATE_MODE = "preview-frame-rate-mode";
+ private static final String KEY_QC_PREVIEW_FRAME_RATE_AUTO_MODE = "frame-rate-auto";
+ private static final String KEY_QC_PREVIEW_FRAME_RATE_FIXED_MODE = "frame-rate-fixed";
+ private static final String KEY_QC_GPS_LATITUDE_REF = "gps-latitude-ref";
+ private static final String KEY_QC_GPS_LONGITUDE_REF = "gps-longitude-ref";
+ private static final String KEY_QC_GPS_ALTITUDE_REF = "gps-altitude-ref";
+ private static final String KEY_QC_GPS_STATUS = "gps-status";
+ private static final String KEY_QC_EXIF_DATETIME = "exif-datetime";
+ private static final String KEY_QC_TOUCH_AF_AEC = "touch-af-aec";
+ private static final String KEY_QC_TOUCH_INDEX_AEC = "touch-index-aec";
+ private static final String KEY_QC_TOUCH_INDEX_AF = "touch-index-af";
+ private static final String KEY_QC_MANUAL_FOCUS_POSITION = "manual-focus-position";
+ private static final String KEY_QC_MANUAL_FOCUS_POS_TYPE = "manual-focus-pos-type";
+ private static final String KEY_QC_SCENE_DETECT = "scene-detect";
+ private static final String KEY_QC_ISO_MODE = "iso";
+ private static final String KEY_QC_EXPOSURE_TIME = "exposure-time";
+ private static final String KEY_QC_MIN_EXPOSURE_TIME = "min-exposure-time";
+ private static final String KEY_QC_MAX_EXPOSURE_TIME = "max-exposure-time";
+ private static final String KEY_QC_LENSSHADE = "lensshade";
+ private static final String KEY_QC_HISTOGRAM = "histogram";
+ private static final String KEY_QC_SKIN_TONE_ENHANCEMENT = "skinToneEnhancement";
+ private static final String KEY_QC_AUTO_EXPOSURE = "auto-exposure";
+ private static final String KEY_QC_SHARPNESS = "sharpness";
+ private static final String KEY_QC_MAX_SHARPNESS = "max-sharpness";
+ private static final String KEY_QC_CONTRAST = "contrast";
+ private static final String KEY_QC_MAX_CONTRAST = "max-contrast";
+ private static final String KEY_QC_SATURATION = "saturation";
+ private static final String KEY_QC_MAX_SATURATION = "max-saturation";
+ private static final String KEY_QC_DENOISE = "denoise";
+ private static final String KEY_QC_CONTINUOUS_AF = "continuous-af";
+ private static final String KEY_QC_SELECTABLE_ZONE_AF = "selectable-zone-af";
+ private static final String KEY_QC_FACE_DETECTION = "face-detection";
+ private static final String KEY_QC_MEMORY_COLOR_ENHANCEMENT = "mce";
+ private static final String KEY_QC_REDEYE_REDUCTION = "redeye-reduction";
+ private static final String KEY_QC_ZSL = "zsl";
+ private static final String KEY_QC_CAMERA_MODE = "camera-mode";
+ private static final String KEY_QC_VIDEO_HIGH_FRAME_RATE = "video-hfr";
+ private static final String KEY_QC_VIDEO_HDR = "video-hdr";
+ private static final String KEY_QC_POWER_MODE = "power-mode";
+ private static final String KEY_QC_POWER_MODE_SUPPORTED = "power-mode-supported";
+ private static final String KEY_QC_WB_MANUAL_CCT = "wb-manual-cct";
+ private static final String KEY_QC_MIN_WB_CCT = "min-wb-cct";
+ private static final String KEY_QC_MAX_WB_CCT = "max-wb-cct";
+ private static final String KEY_QC_AUTO_HDR_ENABLE = "auto-hdr-enable";
+ private static final String KEY_QC_VIDEO_ROTATION = "video-rotation";
+
+ /** @hide
+ * KEY_QC_AE_BRACKET_HDR
+ **/
+ public static final String KEY_QC_AE_BRACKET_HDR = "ae-bracket-hdr";
+
+ /* ### QC ADDED PARAMETER VALUES*/
+
+ // Values for touch af/aec settings.
+ /** @hide
+ * TOUCH_AF_AEC_OFF
+ **/
+ public static final String TOUCH_AF_AEC_OFF = "touch-off";
+ /** @hide
+ * TOUCH_AF_AEC_ON
+ **/
+ public static final String TOUCH_AF_AEC_ON = "touch-on";
+
+ // Values for auto exposure settings.
+ /** @hide
+ * Auto exposure frame-avg
+ **/
+ public static final String AUTO_EXPOSURE_FRAME_AVG = "frame-average";
+ /** @hide
+ * Auto exposure center weighted
+ **/
+ public static final String AUTO_EXPOSURE_CENTER_WEIGHTED = "center-weighted";
+ /** @hide
+ * Auto exposure spot metering
+ **/
+ public static final String AUTO_EXPOSURE_SPOT_METERING = "spot-metering";
+
+ //Values for ISO settings
+ /** @hide
+ * ISO_AUTO
+ **/
+ public static final String ISO_AUTO = "auto";
+ /** @hide
+ * ISO_HJR
+ **/
+ public static final String ISO_HJR = "ISO_HJR";
+ /** @hide
+ * ISO_100
+ **/
+ public static final String ISO_100 = "ISO100";
+ /** @hide
+ * ISO_200
+ **/
+ public static final String ISO_200 = "ISO200";
+ /** @hide
+ * ISO_400
+ **/
+ public static final String ISO_400 = "ISO400";
+ /** @hide
+ * ISO_800
+ **/
+ public static final String ISO_800 = "ISO800";
+ /** @hide
+ * ISO_1600
+ **/
+ public static final String ISO_1600 = "ISO1600";
+
+ /** @hide
+ * ISO_3200
+ **/
+ public static final String ISO_3200 = "ISO3200";
+
+ //Values for Lens Shading
+ /** @hide
+ * LENSSHADE_ENABLE
+ **/
+ public static final String LENSSHADE_ENABLE = "enable";
+ /** @hide
+ * LENSSHADE_DISABLE
+ **/
+ public static final String LENSSHADE_DISABLE= "disable";
+
+ //Values for Histogram
+ /** @hide
+ * Histogram enable
+ **/
+ public static final String HISTOGRAM_ENABLE = "enable";
+ /** @hide
+ * Histogram disable
+ **/
+ public static final String HISTOGRAM_DISABLE= "disable";
+
+ //Values for Skin Tone Enhancement
+ /** @hide
+ * SKIN_TONE_ENHANCEMENT_ENABLE
+ **/
+ public static final String SKIN_TONE_ENHANCEMENT_ENABLE = "enable";
+ /** @hide
+ * SKIN_TONE_ENHANCEMENT_DISABLE
+ **/
+ public static final String SKIN_TONE_ENHANCEMENT_DISABLE= "disable";
+
+ // Values for MCE settings.
+ /** @hide
+ * MCE_ENaBLE
+ **/
+ public static final String MCE_ENABLE = "enable";
+ /** @hide
+ * MCE_DISABLE
+ **/
+ public static final String MCE_DISABLE = "disable";
+
+ // Values for ZSL settings.
+ /** @hide
+ * ZSL_ON
+ **/
+ public static final String ZSL_ON = "on";
+ /** @hide
+ * ZSL_OFF
+ **/
+ public static final String ZSL_OFF = "off";
+
+ // Values for HDR Bracketing settings.
+
+ /** @hide
+ * AEC bracketing off
+ **/
+ public static final String AE_BRACKET_HDR_OFF = "Off";
+ /** @hide
+ * AEC bracketing hdr
+ **/
+ public static final String AE_BRACKET_HDR = "HDR";
+ /** @hide
+ * AEC bracketing aec-bracket
+ **/
+ public static final String AE_BRACKET = "AE-Bracket";
+
+ // Values for Power mode.
+ /** @hide
+ * LOW_POWER
+ **/
+ public static final String LOW_POWER = "Low_Power";
+ /** @hide
+ * NORMAL_POWER
+ **/
+ public static final String NORMAL_POWER = "Normal_Power";
+
+ // Values for HFR settings.
+ /** @hide
+ * VIDEO_HFR_OFF
+ **/
+ public static final String VIDEO_HFR_OFF = "off";
+ /** @hide
+ * VIDEO_HFR_2X
+ **/
+ public static final String VIDEO_HFR_2X = "60";
+ /** @hide
+ * VIDEO_HFR_3X
+ **/
+ public static final String VIDEO_HFR_3X = "90";
+ /** @hide
+ * VIDEO_HFR_4X
+ **/
+ public static final String VIDEO_HFR_4X = "120";
+
+ // Values for auto scene detection settings.
+ /** @hide
+ * SCENE_DETECT_OFF
+ **/
+ public static final String SCENE_DETECT_OFF = "off";
+ /** @hide
+ * SCENE_DETECT_ON
+ **/
+ public static final String SCENE_DETECT_ON = "on";
+
+ //Values for Continuous AF
+
+ /** @hide
+ * CAF off
+ **/
+ public static final String CONTINUOUS_AF_OFF = "caf-off";
+ /** @hide
+ * CAF on
+ **/
+ public static final String CONTINUOUS_AF_ON = "caf-on";
+ /** @hide
+ * Denoise off
+ **/
+ public static final String DENOISE_OFF = "denoise-off";
+ /** @hide
+ * Denoise on
+ **/
+ public static final String DENOISE_ON = "denoise-on";
+
+ // Values for Redeye Reduction settings.
+ /** @hide
+ * REDEYE_REDUCTION_ENABLE
+ **/
+ public static final String REDEYE_REDUCTION_ENABLE = "enable";
+ /** @hide
+ * REDEYE_REDUCTION_DISABLE
+ **/
+ public static final String REDEYE_REDUCTION_DISABLE = "disable";
+
+ // Values for selectable zone af settings.
+ /** @hide
+ * SELECTABLE_ZONE_AF_AUTO
+ **/
+ public static final String SELECTABLE_ZONE_AF_AUTO = "auto";
+ /** @hide
+ * SELECTABLE_ZONE_AF_SPOTMETERING
+ **/
+ public static final String SELECTABLE_ZONE_AF_SPOTMETERING = "spot-metering";
+ /** @hide
+ * SELECTABLE_ZONE_AF_CENTER_WEIGHTED
+ **/
+ public static final String SELECTABLE_ZONE_AF_CENTER_WEIGHTED = "center-weighted";
+ /** @hide
+ * SELECTABLE_ZONE_AF_FRAME_AVERAGE
+ **/
+ public static final String SELECTABLE_ZONE_AF_FRAME_AVERAGE = "frame-average";
+
+ // Values for Face Detection settings.
+ /** @hide
+ * Face Detection off
+ **/
+ public static final String FACE_DETECTION_OFF = "off";
+ /** @hide
+ * Face Detction on
+ **/
+ public static final String FACE_DETECTION_ON = "on";
+
+ // Values for video rotation settings.
+
+ /** @hide
+ * VIDEO_ROTATION_0
+ **/
+ public static final String VIDEO_ROTATION_0 = "0";
+ /** @hide
+ * VIDEO_ROTATION_90
+ **/
+ public static final String VIDEO_ROTATION_90 = "90";
+ /** @hide
+ * VIDEO_ROTATION_180
+ **/
+ public static final String VIDEO_ROTATION_180 = "180";
+ /** @hide
+ * VIDEO_ROTATION_270
+ **/
+ public static final String VIDEO_ROTATION_270 = "270";
+
+ /* ### QC ADDED PARAMETER APIS*/
+ /** @hide
+ * Gets the supported preview sizes in high frame rate recording mode.
+ *
+ * @return a list of Size object. This method will always return a list
+ * with at least one element.
+ */
+ public List<Size> getSupportedHfrSizes() {
+ String str = get(KEY_QC_HFR_SIZE + SUPPORTED_VALUES_SUFFIX);
+ return splitSize(str);
+ }
+
+ /** @hide
+ * Gets the supported Touch AF/AEC setting.
+ *
+ * @return a List of TOUCH_AF_AEC_XXX string constants. null if TOUCH AF/AEC
+ * setting is not supported.
+ *
+ */
+ public List<String> getSupportedTouchAfAec() {
+ String str = get(KEY_QC_TOUCH_AF_AEC + SUPPORTED_VALUES_SUFFIX);
+ return split(str);
+ }
+
+ /**
+ * Gets the supported Touch AF/AEC setting.
+ *
+ * @return a List of TOUCH_AF_AEC_XXX string constants. null if TOUCH AF/AEC
+ * setting is not supported.
+ *
+ */
+
+ /** @hide
+ * Gets the supported frame rate modes.
+ *
+ * @return a List of FRAME_RATE_XXX_MODE string constant. null if this
+ * setting is not supported.
+ */
+ public List<String> getSupportedPreviewFrameRateModes() {
+ String str = get(KEY_QC_PREVIEW_FRAME_RATE_MODE + SUPPORTED_VALUES_SUFFIX);
+ return split(str);
+ }
+
+ /** @hide
+ * Gets the supported auto scene detection modes.
+ *
+ * @return a List of SCENE_DETECT_XXX string constant. null if scene detection
+ * setting is not supported.
+ *
+ */
+ public List<String> getSupportedSceneDetectModes() {
+ String str = get(KEY_QC_SCENE_DETECT + SUPPORTED_VALUES_SUFFIX);
+ return split(str);
+ }
+
+ /** @hide
+ * Gets the supported ISO values.
+ *
+ * @return a List of FLASH_MODE_XXX string constants. null if flash mode
+ * setting is not supported.
+ */
+ public List<String> getSupportedIsoValues() {
+ String str = get(KEY_QC_ISO_MODE + SUPPORTED_VALUES_SUFFIX);
+ return split(str);
+ }
+
+ /** @hide
+ * Gets the supported Lensshade modes.
+ *
+ * @return a List of LENS_MODE_XXX string constants. null if lens mode
+ * setting is not supported.
+ */
+ public List<String> getSupportedLensShadeModes() {
+ String str = get(KEY_QC_LENSSHADE + SUPPORTED_VALUES_SUFFIX);
+ return split(str);
+ }
+
+ /** @hide
+ * Gets the supported Histogram modes.
+ *
+ * @return a List of HISTOGRAM_XXX string constants. null if histogram mode
+ * setting is not supported.
+ */
+ public List<String> getSupportedHistogramModes() {
+ String str = get(KEY_QC_HISTOGRAM + SUPPORTED_VALUES_SUFFIX);
+ return split(str);
+ }
+
+ /** @hide
+ * Gets the supported Skin Tone Enhancement modes.
+ *
+ * @return a List of SKIN_TONE_ENHANCEMENT_XXX string constants. null if skin tone enhancement
+ * setting is not supported.
+ */
+ public List<String> getSupportedSkinToneEnhancementModes() {
+ String str = get(KEY_QC_SKIN_TONE_ENHANCEMENT + SUPPORTED_VALUES_SUFFIX);
+ return split(str);
+ }
+
+ /** @hide
+ * Gets the supported auto exposure setting.
+ *
+ * @return a List of AUTO_EXPOSURE_XXX string constants. null if auto exposure
+ * setting is not supported.
+ */
+ public List<String> getSupportedAutoexposure() {
+ String str = get(KEY_QC_AUTO_EXPOSURE + SUPPORTED_VALUES_SUFFIX);
+ return split(str);
+ }
+
+ /** @hide
+ * Gets the supported MCE modes.
+ *
+ * @return a List of MCE_ENABLE/DISABLE string constants. null if MCE mode
+ * setting is not supported.
+ */
+ public List<String> getSupportedMemColorEnhanceModes() {
+ String str = get(KEY_QC_MEMORY_COLOR_ENHANCEMENT + SUPPORTED_VALUES_SUFFIX);
+ return split(str);
+ }
+
+ /** @hide
+ * Gets the supported ZSL modes.
+ *
+ * @return a List of ZSL_OFF/OFF string constants. null if ZSL mode
+ * setting is not supported.
+ */
+ public List<String> getSupportedZSLModes() {
+ String str = get(KEY_QC_ZSL + SUPPORTED_VALUES_SUFFIX);
+ return split(str);
+ }
+
+ /** @hide
+ * Gets the supported Video HDR modes.
+ *
+ * @return a List of Video HDR_OFF/OFF string constants. null if
+ * Video HDR mode setting is not supported.
+ */
+ public List<String> getSupportedVideoHDRModes() {
+ String str = get(KEY_QC_VIDEO_HDR + SUPPORTED_VALUES_SUFFIX);
+ return split(str);
+ }
+
+ /** @hide
+ * Gets the supported HFR modes.
+ *
+ * @return a List of VIDEO_HFR_XXX string constants. null if hfr mode
+ * setting is not supported.
+ */
+ public List<String> getSupportedVideoHighFrameRateModes() {
+ String str = get(KEY_QC_VIDEO_HIGH_FRAME_RATE + SUPPORTED_VALUES_SUFFIX);
+ return split(str);
+ }
+
+ /** @hide
+ * Gets the supported Continuous AF modes.
+ *
+ * @return a List of CONTINUOUS_AF_XXX string constant. null if continuous AF
+ * setting is not supported.
+ *
+ */
+ public List<String> getSupportedContinuousAfModes() {
+ String str = get(KEY_QC_CONTINUOUS_AF + SUPPORTED_VALUES_SUFFIX);
+ return split(str);
+ }
+
+ /** @hide
+ * Gets the supported DENOISE modes.
+ *
+ * @return a List of DENOISE_XXX string constant. null if DENOISE
+ * setting is not supported.
+ *
+ */
+ public List<String> getSupportedDenoiseModes() {
+ String str = get(KEY_QC_DENOISE + SUPPORTED_VALUES_SUFFIX);
+ return split(str);
+ }
+
+ /** @hide
+ * Gets the supported selectable zone af setting.
+ *
+ * @return a List of SELECTABLE_ZONE_AF_XXX string constants. null if selectable zone af
+ * setting is not supported.
+ */
+ public List<String> getSupportedSelectableZoneAf() {
+ String str = get(KEY_QC_SELECTABLE_ZONE_AF + SUPPORTED_VALUES_SUFFIX);
+ return split(str);
+ }
+
+ /** @hide
+ * Gets the supported face detection modes.
+ *
+ * @return a List of FACE_DETECTION_XXX string constant. null if face detection
+ * setting is not supported.
+ *
+ */
+ public List<String> getSupportedFaceDetectionModes() {
+ String str = get(KEY_QC_FACE_DETECTION + SUPPORTED_VALUES_SUFFIX);
+ return split(str);
+ }
+
+ /** @hide
+ * Gets the supported redeye reduction modes.
+ *
+ * @return a List of REDEYE_REDUCTION_XXX string constant. null if redeye reduction
+ * setting is not supported.
+ *
+ */
+ public List<String> getSupportedRedeyeReductionModes() {
+ String str = get(KEY_QC_REDEYE_REDUCTION + SUPPORTED_VALUES_SUFFIX);
+ return split(str);
+ }
+
+ /** @hide
+ * Sets GPS altitude reference. This will be stored in JPEG EXIF header.
+ * @param altRef reference GPS altitude in meters.
+ */
+ public void setGpsAltitudeRef(double altRef) {
+ set(KEY_QC_GPS_ALTITUDE_REF, Double.toString(altRef));
+ }
+
+ /** @hide
+ * Sets GPS Status. This will be stored in JPEG EXIF header.
+ *
+ * @param status GPS status (UTC in seconds since January 1,
+ * 1970).
+ */
+ public void setGpsStatus(double status) {
+ set(KEY_QC_GPS_STATUS, Double.toString(status));
+ }
+
+ /** @hide
+ * Sets the touch co-ordinate for Touch AEC.
+ *
+ * @param x the x co-ordinate of the touch event
+ * @param y the y co-ordinate of the touch event
+ *
+ */
+ public void setTouchIndexAec(int x, int y) {
+ String v = Integer.toString(x) + "x" + Integer.toString(y);
+ set(KEY_QC_TOUCH_INDEX_AEC, v);
+ }
+
+ /** @hide
+ * Returns the touch co-ordinates of the touch event.
+ *
+ * @return a Index object with the x and y co-ordinated
+ * for the touch event
+ *
+ */
+ public Coordinate getTouchIndexAec() {
+ String pair = get(KEY_QC_TOUCH_INDEX_AEC);
+ return strToCoordinate(pair);
+ }
+
+ /** @hide
+ * Sets the touch co-ordinate for Touch AF.
+ *
+ * @param x the x co-ordinate of the touch event
+ * @param y the y co-ordinate of the touch event
+ *
+ */
+ public void setTouchIndexAf(int x, int y) {
+ String v = Integer.toString(x) + "x" + Integer.toString(y);
+ set(KEY_QC_TOUCH_INDEX_AF, v);
+ }
+
+ /** @hide
+ * Returns the touch co-ordinates of the touch event.
+ *
+ * @return a Index object with the x and y co-ordinated
+ * for the touch event
+ *
+ */
+ public Coordinate getTouchIndexAf() {
+ String pair = get(KEY_QC_TOUCH_INDEX_AF);
+ return strToCoordinate(pair);
+ }
+ /** @hide
+ * Set Sharpness Level
+ *
+ * @param sharpness level
+ */
+ public void setSharpness(int sharpness){
+ if((sharpness < 0) || (sharpness > getMaxSharpness()) )
+ throw new IllegalArgumentException(
+ "Invalid Sharpness " + sharpness);
+
+ set(KEY_QC_SHARPNESS, String.valueOf(sharpness));
+ }
+
+ /** @hide
+ * Set Contrast Level
+ *
+ * @param contrast level
+ */
+ public void setContrast(int contrast){
+ if((contrast < 0 ) || (contrast > getMaxContrast()))
+ throw new IllegalArgumentException(
+ "Invalid Contrast " + contrast);
+
+ set(KEY_QC_CONTRAST, String.valueOf(contrast));
+ }
+
+ /** @hide
+ * Set Saturation Level
+ *
+ * @param saturation level
+ */
+ public void setSaturation(int saturation){
+ if((saturation < 0 ) || (saturation > getMaxSaturation()))
+ throw new IllegalArgumentException(
+ "Invalid Saturation " + saturation);
+
+ set(KEY_QC_SATURATION, String.valueOf(saturation));
+ }
+
+ /** @hide
+ * @return true if full size video snapshot is supported.
+ */
+ public boolean isPowerModeSupported() {
+ String str = get(KEY_QC_POWER_MODE_SUPPORTED);
+ return TRUE.equals(str);
+ }
+
+ /** @hide
+ * Get Sharpness level
+ *
+ * @return sharpness level
+ */
+ public int getSharpness(){
+ return getInt(KEY_QC_SHARPNESS);
+ }
+
+ /** @hide
+ * Get Max Sharpness Level
+ *
+ * @return max sharpness level
+ */
+ public int getMaxSharpness(){
+ return getInt(KEY_QC_MAX_SHARPNESS);
+ }
+
+ /** @hide
+ * Get Contrast level
+ *
+ * @return contrast level
+ */
+ public int getContrast(){
+ return getInt(KEY_QC_CONTRAST);
+ }
+
+ /** @hide
+ * Get Max Contrast Level
+ *
+ * @return max contrast level
+ */
+ public int getMaxContrast(){
+ return getInt(KEY_QC_MAX_CONTRAST);
+ }
+
+ /** @hide
+ * Get Saturation level
+ *
+ * @return saturation level
+ */
+ public int getSaturation(){
+ return getInt(KEY_QC_SATURATION);
+ }
+
+ /** @hide
+ * Get Max Saturation Level
+ *
+ * @return max contrast level
+ */
+ public int getMaxSaturation(){
+ return getInt(KEY_QC_MAX_SATURATION);
+ }
+
+ /** @hide
+ * Sets GPS latitude reference coordinate. This will be stored in JPEG EXIF
+ * header.
+ * @param latRef GPS latitude reference coordinate.
+ */
+ public void setGpsLatitudeRef(String latRef) {
+ set(KEY_QC_GPS_LATITUDE_REF, latRef);
+ }
+
+ /** @hide
+ * Sets GPS longitude reference coordinate. This will be stored in JPEG EXIF
+ * header.
+ * @param lonRef GPS longitude reference coordinate.
+ */
+ public void setGpsLongitudeRef(String lonRef) {
+ set(KEY_QC_GPS_LONGITUDE_REF, lonRef);
+ }
+
+ /** @hide
+ * Sets system timestamp. This will be stored in JPEG EXIF header.
+ *
+ * @param dateTime current timestamp (UTC in seconds since January 1,
+ * 1970).
+ */
+ public void setExifDateTime(String dateTime) {
+ set(KEY_QC_EXIF_DATETIME, dateTime);
+ }
+
+ /** @hide
+ * Gets the current Touch AF/AEC setting.
+ *
+ * @return one of TOUCH_AF_AEC_XXX string constant. null if Touch AF/AEC
+ * setting is not supported.
+ *
+ */
+ public String getTouchAfAec() {
+ return get(KEY_QC_TOUCH_AF_AEC);
+ }
+
+ /** @hide
+ * Sets the current TOUCH AF/AEC setting.
+ *
+ * @param value TOUCH_AF_AEC_XXX string constants.
+ *
+ */
+ public void setTouchAfAec(String value) {
+ set(KEY_QC_TOUCH_AF_AEC, value);
+ }
+
+ /** @hide
+ * Gets the current redeye reduction setting.
+ *
+ * @return one of REDEYE_REDUCTION_XXX string constant. null if redeye reduction
+ * setting is not supported.
+ *
+ */
+ public String getRedeyeReductionMode() {
+ return get(KEY_QC_REDEYE_REDUCTION);
+ }
+
+ /** @hide
+ * Sets the redeye reduction. Other parameters may be changed after changing
+ * redeye reduction. After setting redeye reduction,
+ * applications should call getParameters to know if some parameters are
+ * changed.
+ *
+ * @param value REDEYE_REDUCTION_XXX string constants.
+ *
+ */
+ public void setRedeyeReductionMode(String value) {
+ set(KEY_QC_REDEYE_REDUCTION, value);
+ }
+
+ /** @hide
+ * Gets the frame rate mode setting.
+ *
+ * @return one of FRAME_RATE_XXX_MODE string constant. null if this
+ * setting is not supported.
+ */
+ public String getPreviewFrameRateMode() {
+ return get(KEY_QC_PREVIEW_FRAME_RATE_MODE);
+ }
+
+ /** @hide
+ * Sets the frame rate mode.
+ *
+ * @param value FRAME_RATE_XXX_MODE string constants.
+ */
+ public void setPreviewFrameRateMode(String value) {
+ set(KEY_QC_PREVIEW_FRAME_RATE_MODE, value);
+ }
+
+ /** @hide
+ * Gets the current auto scene detection setting.
+ *
+ * @return one of SCENE_DETECT_XXX string constant. null if auto scene detection
+ * setting is not supported.
+ *
+ */
+ public String getSceneDetectMode() {
+ return get(KEY_QC_SCENE_DETECT);
+ }
+
+ /** @hide
+ * Sets the auto scene detect. Other parameters may be changed after changing
+ * scene detect. After setting auto scene detection,
+ * applications should call getParameters to know if some parameters are
+ * changed.
+ *
+ * @param value SCENE_DETECT_XXX string constants.
+ *
+ */
+ public void setSceneDetectMode(String value) {
+ set(KEY_QC_SCENE_DETECT, value);
+ }
+
+ /** @hide
+ * Gets the current hdr bracketing mode setting.
+ *
+ * @return current hdr bracketing mode.
+ * @see #KEY_AE_BRACKET_OFF
+ * @see #KEY_AE_BRACKET_HDR
+ * @see #KEY_AE_BRACKET_BRACKATING
+ */
+ public String getAEBracket() {
+ return get(KEY_QC_AE_BRACKET_HDR);
+ }
+
+ /** @hide
+ * Sets the Power mode.
+ *
+ * @param value Power mode.
+ * @see #getPowerMode()
+ */
+ public void setPowerMode(String value) {
+ set(KEY_QC_POWER_MODE, value);
+ }
+
+ /** @hide
+ * Gets the current power mode setting.
+ *
+ * @return current power mode. null if power mode setting is not
+ * supported.
+ * @see #POWER_MODE_LOW
+ * @see #POWER_MODE_NORMAL
+ */
+ public String getPowerMode() {
+ return get(KEY_QC_POWER_MODE);
+ }
+
+ /** @hide
+ * Set HDR-Bracketing Level
+ *
+ * @param value HDR-Bracketing
+ */
+ public void setAEBracket(String value){
+ set(KEY_QC_AE_BRACKET_HDR, value);
+ }
+
+ /** @hide
+ * Gets the current ISO setting.
+ *
+ * @return one of ISO_XXX string constant. null if ISO
+ * setting is not supported.
+ */
+ public String getISOValue() {
+ return get(KEY_QC_ISO_MODE);
+ }
+
+ /** @hide
+ * Sets the ISO.
+ *
+ * @param iso ISO_XXX string constant.
+ */
+ public void setISOValue(String iso) {
+ set(KEY_QC_ISO_MODE, iso);
+ }
+
+ /** @hide
+ * Sets the exposure time.
+ *
+ * @param value exposure time.
+ */
+ public void setExposureTime(int value) {
+ set(KEY_QC_EXPOSURE_TIME, Integer.toString(value));
+ }
+
+ /** @hide
+ * Gets the current exposure time.
+ *
+ * @return exposure time.
+ */
+ public String getExposureTime() {
+ return get(KEY_QC_EXPOSURE_TIME);
+ }
+
+ /** @hide
+ * Gets the min supported exposure time.
+ *
+ * @return min supported exposure time.
+ */
+ public String getMinExposureTime() {
+ return get(KEY_QC_MIN_EXPOSURE_TIME);
+ }
+
+ /** @hide
+ * Gets the max supported exposure time.
+ *
+ * @return max supported exposure time.
+ */
+ public String getMaxExposureTime() {
+ return get(KEY_QC_MAX_EXPOSURE_TIME);
+ }
+
+ /** @hide
+ * Gets the current LensShade Mode.
+ *
+ * @return LensShade Mode
+ */
+ public String getLensShade() {
+ return get(KEY_QC_LENSSHADE);
+ }
+
+ /** @hide
+ * Sets the current LensShade Mode.
+ *
+ * @return LensShade Mode
+ */
+ public void setLensShade(String lensshade) {
+ set(KEY_QC_LENSSHADE, lensshade);
+ }
+
+ /** @hide
+ * Gets the current auto exposure setting.
+ *
+ * @return one of AUTO_EXPOSURE_XXX string constant. null if auto exposure
+ * setting is not supported.
+ */
+ public String getAutoExposure() {
+ return get(KEY_QC_AUTO_EXPOSURE);
+ }
+
+ /** @hide
+ * Sets the current auto exposure setting.
+ *
+ * @param value AUTO_EXPOSURE_XXX string constants.
+ */
+ public void setAutoExposure(String value) {
+ set(KEY_QC_AUTO_EXPOSURE, value);
+ }
+
+ /** @hide
+ * Gets the current MCE Mode.
+ *
+ * @return MCE value
+ */
+ public String getMemColorEnhance() {
+ return get(KEY_QC_MEMORY_COLOR_ENHANCEMENT);
+ }
+
+ /** @hide
+ * Sets the current MCE Mode.
+ *
+ * @return MCE Mode
+ */
+ public void setMemColorEnhance(String mce) {
+ set(KEY_QC_MEMORY_COLOR_ENHANCEMENT, mce);
+ }
+
+ /** @hide
+ * Set white balance manual cct value.
+ *
+ * @param cct user CCT setting.
+ */
+ public void setWBManualCCT(int cct) {
+ set(KEY_QC_WB_MANUAL_CCT, Integer.toString(cct));
+ }
+
+ /** @hide
+ * Gets the WB min supported CCT.
+ *
+ * @return min cct value.
+ */
+ public String getWBMinCCT() {
+ return get(KEY_QC_MIN_WB_CCT);
+ }
+
+ /** @hide
+ * Gets the WB max supported CCT.
+ *
+ * @return max cct value.
+ */
+ public String getMaxWBCCT() {
+ return get(KEY_QC_MAX_WB_CCT);
+ }
+
+ /** @hide
+ * Gets the current WB CCT.
+ *
+ * @return CCT value
+ */
+ public String getWBCurrentCCT() {
+ return get(KEY_QC_WB_MANUAL_CCT);
+ }
+
+ /** @hide
+ * Gets the current ZSL Mode.
+ *
+ * @return ZSL mode value
+ */
+ public String getZSLMode() {
+ return get(KEY_QC_ZSL);
+ }
+
+ /** @hide
+ * Sets the current ZSL Mode. ZSL mode is set as a 0th bit in KEY_CAMERA_MODE.
+ *
+ * @return null
+ */
+ public void setZSLMode(String zsl) {
+ set(KEY_QC_ZSL, zsl);
+ }
+
+ /** @hide
+ * Sets the current Auto HDR Mode.
+ * @ auto_hdr auto hdr string for enable/disable
+ * @return null
+ */
+ public void setAutoHDRMode(String auto_hdr){
+ set(KEY_QC_AUTO_HDR_ENABLE,auto_hdr);
+ }
+
+ /** @hide
+ * Gets the current Camera Mode Flag. Camera mode includes a
+ * flag(byte) which indicates different camera modes.
+ * For now support for ZSL added at bit0
+ *
+ * @return Camera Mode.
+ */
+ public String getCameraMode() {
+ return get(KEY_QC_CAMERA_MODE);
+ }
+
+ /** @hide
+ * Sets the current Camera Mode.
+ *
+ * @return null
+ */
+ public void setCameraMode(int cameraMode) {
+ set(KEY_QC_CAMERA_MODE, cameraMode);
+ }
+
+ private static final int MANUAL_FOCUS_POS_TYPE_INDEX = 0;
+ private static final int MANUAL_FOCUS_POS_TYPE_DAC = 1;
+ /** @hide
+ * Set focus position.
+ *
+ * @param pos user setting of focus position.
+ */
+ public void setFocusPosition(int type, int pos) {
+ set(KEY_QC_MANUAL_FOCUS_POS_TYPE, Integer.toString(type));
+ set(KEY_QC_MANUAL_FOCUS_POSITION, Integer.toString(pos));
+ }
+
+ /** @hide
+ * Gets the current focus position.
+ *
+ * @return current focus position
+ */
+ public String getCurrentFocusPosition() {
+ return get(KEY_QC_MANUAL_FOCUS_POSITION);
+ }
+
+
+ /** @hide
+ * Gets the current HFR Mode.
+ *
+ * @return VIDEO_HFR_XXX string constants
+ */
+ public String getVideoHighFrameRate() {
+ return get(KEY_QC_VIDEO_HIGH_FRAME_RATE);
+ }
+
+ /** @hide
+ * Sets the current HFR Mode.
+ *
+ * @param hfr VIDEO_HFR_XXX string constants
+ */
+ public void setVideoHighFrameRate(String hfr) {
+ set(KEY_QC_VIDEO_HIGH_FRAME_RATE, hfr);
+ }
+
+ /** @hide
+ * Gets the current Video HDR Mode.
+ *
+ * @return Video HDR mode value
+ */
+ public String getVideoHDRMode() {
+ return get(KEY_QC_VIDEO_HDR);
+ }
+
+ /** @hide
+ * Sets the current Video HDR Mode.
+ *
+ * @return null
+ */
+ public void setVideoHDRMode(String videohdr) {
+ set(KEY_QC_VIDEO_HDR, videohdr);
+ }
+
+ /** @hide
+ * Gets the current DENOISE setting.
+ *
+ * @return one of DENOISE_XXX string constant. null if Denoise
+ * setting is not supported.
+ *
+ */
+ public String getDenoise() {
+ return get(KEY_QC_DENOISE);
+ }
+
+ /** @hide
+ * Gets the current Continuous AF setting.
+ *
+ * @return one of CONTINUOUS_AF_XXX string constant. null if continuous AF
+ * setting is not supported.
+ *
+ */
+ public String getContinuousAf() {
+ return get(KEY_QC_CONTINUOUS_AF);
+ }
+
+ /** @hide
+ * Sets the current Denoise mode.
+ * @param value DENOISE_XXX string constants.
+ *
+ */
+
+ public void setDenoise(String value) {
+ set(KEY_QC_DENOISE, value);
+ }
+
+ /** @hide
+ * Sets the current Continuous AF mode.
+ * @param value CONTINUOUS_AF_XXX string constants.
+ *
+ */
+ public void setContinuousAf(String value) {
+ set(KEY_QC_CONTINUOUS_AF, value);
+ }
+
+ /** @hide
+ * Gets the current selectable zone af setting.
+ *
+ * @return one of SELECTABLE_ZONE_AF_XXX string constant. null if selectable zone af
+ * setting is not supported.
+ */
+ public String getSelectableZoneAf() {
+ return get(KEY_QC_SELECTABLE_ZONE_AF);
+ }
+
+ /** @hide
+ * Sets the current selectable zone af setting.
+ *
+ * @param value SELECTABLE_ZONE_AF_XXX string constants.
+ */
+ public void setSelectableZoneAf(String value) {
+ set(KEY_QC_SELECTABLE_ZONE_AF, value);
+ }
+
+ /** @hide
+ * Gets the current face detection setting.
+ *
+ * @return one of FACE_DETECTION_XXX string constant. null if face detection
+ * setting is not supported.
+ *
+ */
+ public String getFaceDetectionMode() {
+ return get(KEY_QC_FACE_DETECTION);
+ }
+
+ /** @hide
+ * Sets the auto scene detect. Other settings like Touch AF/AEC might be
+ * changed after setting face detection.
+ *
+ * @param value FACE_DETECTION_XXX string constants.
+ *
+ */
+ public void setFaceDetectionMode(String value) {
+ set(KEY_QC_FACE_DETECTION, value);
+ }
+
+ /** @hide
+ * Gets the current video rotation setting.
+ *
+ * @return one of VIDEO_QC_ROTATION_XXX string constant. null if video rotation
+ * setting is not supported.
+ */
+ public String getVideoRotation() {
+ return get(KEY_QC_VIDEO_ROTATION);
+ }
+
+ /** @hide
+ * Sets the current video rotation setting.
+ *
+ * @param value VIDEO_QC_ROTATION_XXX string constants.
+ */
+ public void setVideoRotation(String value) {
+ set(KEY_QC_VIDEO_ROTATION, value);
+ }
+ /** @hide
+ * Gets the supported video rotation modes.
+ *
+ * @return a List of VIDEO_QC_ROTATION_XXX string constant. null if this
+ * setting is not supported.
+ */
+ public List<String> getSupportedVideoRotationValues() {
+ String str = get(KEY_QC_VIDEO_ROTATION + SUPPORTED_VALUES_SUFFIX);
+ return split(str);
+ }
+
+ // Splits a comma delimited string to an ArrayList of Coordinate.
+ // Return null if the passing string is null or the Coordinate is 0.
+ private ArrayList<Coordinate> splitCoordinate(String str) {
+ if (str == null) return null;
+ TextUtils.StringSplitter splitter = new TextUtils.SimpleStringSplitter(',');
+ splitter.setString(str);
+ ArrayList<Coordinate> coordinateList = new ArrayList<Coordinate>();
+ for (String s : splitter) {
+ Coordinate coordinate = strToCoordinate(s);
+ if (coordinate != null) coordinateList.add(coordinate);
+ }
+ if (coordinateList.size() == 0) return null;
+ return coordinateList;
+ }
+
+ // Parses a string (ex: "500x500") to Coordinate object.
+ // Return null if the passing string is null.
+ private Coordinate strToCoordinate(String str) {
+ if (str == null) return null;
+
+ int pos = str.indexOf('x');
+ if (pos != -1) {
+ String x = str.substring(0, pos);
+ String y = str.substring(pos + 1);
+ return new Coordinate(Integer.parseInt(x),
+ Integer.parseInt(y));
+ }
+ Log.e(TAG, "Invalid Coordinate parameter string=" + str);
+ return null;
+ }
+ /* ### QC ADD-ONS: END */
};
}
diff --git a/core/java/android/hardware/SystemSensorManager.java b/core/java/android/hardware/SystemSensorManager.java
index 2fe8fb6..ba0d5be 100644
--- a/core/java/android/hardware/SystemSensorManager.java
+++ b/core/java/android/hardware/SystemSensorManager.java
@@ -101,6 +101,7 @@ public class SystemSensorManager extends SensorManager {
@Override
protected boolean registerListenerImpl(SensorEventListener listener, Sensor sensor,
int delayUs, Handler handler, int maxBatchReportLatencyUs, int reservedFlags) {
+ android.util.SeempLog.record_sensor_rate(381, sensor, delayUs);
if (listener == null || sensor == null) {
Log.e(TAG, "sensor or listener is null");
return false;
@@ -142,6 +143,7 @@ public class SystemSensorManager extends SensorManager {
/** @hide */
@Override
protected void unregisterListenerImpl(SensorEventListener listener, Sensor sensor) {
+ android.util.SeempLog.record_sensor(382, sensor);
// Trigger Sensors should use the cancelTriggerSensor call.
if (sensor != null && sensor.getReportingMode() == Sensor.REPORTING_MODE_ONE_SHOT) {
return;
diff --git a/core/java/android/hardware/camera2/legacy/RequestThreadManager.java b/core/java/android/hardware/camera2/legacy/RequestThreadManager.java
index 4866598..a0a03b1 100644
--- a/core/java/android/hardware/camera2/legacy/RequestThreadManager.java
+++ b/core/java/android/hardware/camera2/legacy/RequestThreadManager.java
@@ -920,6 +920,9 @@ public class RequestThreadManager {
mDeviceState.setError(
CameraDeviceImpl.CameraDeviceCallbacks.ERROR_CAMERA_DEVICE);
}
+ if (mPreviewTexture != null) {
+ mPreviewTexture.setOnFrameAvailableListener(null);
+ }
if (mGLThreadManager != null) {
mGLThreadManager.quit();
mGLThreadManager = null;
diff --git a/core/java/android/hardware/camera2/legacy/SurfaceTextureRenderer.java b/core/java/android/hardware/camera2/legacy/SurfaceTextureRenderer.java
index bc80fc1..86eb01d 100644
--- a/core/java/android/hardware/camera2/legacy/SurfaceTextureRenderer.java
+++ b/core/java/android/hardware/camera2/legacy/SurfaceTextureRenderer.java
@@ -433,6 +433,20 @@ public class SurfaceTextureRenderer {
EGL14.eglChooseConfig(mEGLDisplay, attribList, /*offset*/ 0, configs, /*offset*/ 0,
configs.length, numConfigs, /*offset*/ 0);
checkEglError("eglCreateContext RGB888+recordable ES2");
+ if (numConfigs[0] == 0) {
+ Log.w(TAG, "eglChooseConfig returned no configs, retrying without EGL_RECORDABLE_ANDROID");
+ int[] attribList2 = {
+ EGL14.EGL_RED_SIZE, EGL_COLOR_BITLENGTH,
+ EGL14.EGL_GREEN_SIZE, EGL_COLOR_BITLENGTH,
+ EGL14.EGL_BLUE_SIZE, EGL_COLOR_BITLENGTH,
+ EGL14.EGL_RENDERABLE_TYPE, EGL14.EGL_OPENGL_ES2_BIT,
+ EGL14.EGL_SURFACE_TYPE, EGL14.EGL_PBUFFER_BIT | EGL14.EGL_WINDOW_BIT,
+ EGL14.EGL_NONE
+ };
+ EGL14.eglChooseConfig(mEGLDisplay, attribList2, /*offset*/ 0, configs, /*offset*/ 0,
+ configs.length, numConfigs, /*offset*/ 0);
+ checkEglError("eglCreateContext RGB888 ES2");
+ }
mConfigs = configs[0];
int[] attrib_list = {
EGL14.EGL_CONTEXT_CLIENT_VERSION, GLES_VERSION,
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index ff7a300..5e9cd97 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -317,6 +317,11 @@ public class InputMethodService extends AbstractInputMethodService {
final Insets mTmpInsets = new Insets();
final int[] mTmpLocation = new int[2];
+ int mVolumeKeyCursorControl;
+ private static final int VOLUME_CURSOR_OFF = 0;
+ private static final int VOLUME_CURSOR_ON = 1;
+ private static final int VOLUME_CURSOR_ON_REVERSE = 2;
+
final ViewTreeObserver.OnComputeInternalInsetsListener mInsetsComputer =
new ViewTreeObserver.OnComputeInternalInsetsListener() {
public void onComputeInternalInsets(ViewTreeObserver.InternalInsetsInfo info) {
@@ -1856,6 +1861,26 @@ public class InputMethodService extends AbstractInputMethodService {
}
return false;
}
+ if (event.getKeyCode() == KeyEvent.KEYCODE_VOLUME_UP) {
+ mVolumeKeyCursorControl = Settings.System.getInt(getContentResolver(),
+ Settings.System.VOLUME_KEY_CURSOR_CONTROL, 0);
+ if (isInputViewShown() && (mVolumeKeyCursorControl != VOLUME_CURSOR_OFF)) {
+ sendDownUpKeyEvents((mVolumeKeyCursorControl == VOLUME_CURSOR_ON_REVERSE)
+ ? KeyEvent.KEYCODE_DPAD_RIGHT : KeyEvent.KEYCODE_DPAD_LEFT);
+ return true;
+ }
+ return false;
+ }
+ if (event.getKeyCode() == KeyEvent.KEYCODE_VOLUME_DOWN) {
+ mVolumeKeyCursorControl = Settings.System.getInt(getContentResolver(),
+ Settings.System.VOLUME_KEY_CURSOR_CONTROL, 0);
+ if (isInputViewShown() && (mVolumeKeyCursorControl != VOLUME_CURSOR_OFF)) {
+ sendDownUpKeyEvents((mVolumeKeyCursorControl == VOLUME_CURSOR_ON_REVERSE)
+ ? KeyEvent.KEYCODE_DPAD_LEFT : KeyEvent.KEYCODE_DPAD_RIGHT);
+ return true;
+ }
+ return false;
+ }
return doMovementKey(keyCode, event, MOVEMENT_DOWN);
}
@@ -1906,6 +1931,15 @@ public class InputMethodService extends AbstractInputMethodService {
return handleBack(true);
}
}
+ if (event.getKeyCode() == KeyEvent.KEYCODE_VOLUME_UP
+ || keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) {
+ mVolumeKeyCursorControl = Settings.System.getInt(getContentResolver(),
+ Settings.System.VOLUME_KEY_CURSOR_CONTROL, 0);
+ if (isInputViewShown() && (mVolumeKeyCursorControl != VOLUME_CURSOR_OFF)) {
+ return true;
+ }
+ return false;
+ }
return doMovementKey(keyCode, event, MOVEMENT_UP);
}
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 4d9b759..6bbd9c8 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -24,6 +24,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.NetworkUtils;
+import android.net.wifi.WifiDevice;
import android.os.Binder;
import android.os.Build.VERSION_CODES;
import android.os.Handler;
@@ -49,6 +50,7 @@ import com.android.internal.util.Protocol;
import java.net.InetAddress;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.HashMap;
+import java.util.List;
import libcore.net.event.NetworkEventDispatcher;
@@ -283,6 +285,15 @@ public class ConnectivityManager {
"android.net.conn.TETHER_STATE_CHANGED";
/**
+ * Broadcast intent action indicating that a Station is connected
+ * or disconnected.
+ *
+ * @hide
+ */
+ public static final String TETHER_CONNECT_STATE_CHANGED =
+ "codeaurora.net.conn.TETHER_CONNECT_STATE_CHANGED";
+
+ /**
* @hide
* gives a String[] listing all the interfaces configured for
* tethering and currently available for tethering.
@@ -1838,6 +1849,20 @@ public class ConnectivityManager {
}
}
+ /**
+ * Get the list of Stations connected to Hotspot.
+ *
+ * @return a list of {@link WifiDevice} objects.
+ * {@hide}
+ */
+ public List<WifiDevice> getTetherConnectedSta() {
+ try {
+ return mService.getTetherConnectedSta();
+ } catch (RemoteException e) {
+ return null;
+ }
+ }
+
/** {@hide} */
public static final int TETHER_ERROR_NO_ERROR = 0;
/** {@hide} */
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index d4dd669..c6de7a5 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -26,6 +26,7 @@ import android.net.NetworkQuotaInfo;
import android.net.NetworkRequest;
import android.net.NetworkState;
import android.net.ProxyInfo;
+import android.net.wifi.WifiDevice;
import android.os.IBinder;
import android.os.Messenger;
import android.os.ParcelFileDescriptor;
@@ -36,6 +37,8 @@ import com.android.internal.net.VpnConfig;
import com.android.internal.net.VpnInfo;
import com.android.internal.net.VpnProfile;
+import java.util.List;
+
/**
* Interface that answers queries about, and allows changing, the
* state of network connectivity.
@@ -92,6 +95,8 @@ interface IConnectivityManager
int setUsbTethering(boolean enable);
+ List<WifiDevice> getTetherConnectedSta();
+
void reportInetCondition(int networkType, int percentage);
void reportNetworkConnectivity(in Network network, boolean hasConnectivity);
diff --git a/core/java/android/net/INetworkManagementEventObserver.aidl b/core/java/android/net/INetworkManagementEventObserver.aidl
index b7af374..5a70ff1 100644
--- a/core/java/android/net/INetworkManagementEventObserver.aidl
+++ b/core/java/android/net/INetworkManagementEventObserver.aidl
@@ -92,6 +92,13 @@ interface INetworkManagementEventObserver {
void interfaceClassDataActivityChanged(String label, boolean active, long tsNanos);
/**
+ * Message is received from network interface.
+ *
+ * @param message The message
+ */
+ void interfaceMessageRecevied(String message);
+
+ /**
* Information about available DNS servers has been received.
*
* @param iface The interface on which the information was received.
diff --git a/core/java/android/net/wimax/WimaxHelper.java b/core/java/android/net/wimax/WimaxHelper.java
new file mode 100644
index 0000000..9a6727e
--- /dev/null
+++ b/core/java/android/net/wimax/WimaxHelper.java
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) 2011-2015 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;
+ }
+} \ No newline at end of file
diff --git a/core/java/android/nfc/cardemulation/ApduServiceInfo.java b/core/java/android/nfc/cardemulation/ApduServiceInfo.java
index 7678678..09487d7 100644
--- a/core/java/android/nfc/cardemulation/ApduServiceInfo.java
+++ b/core/java/android/nfc/cardemulation/ApduServiceInfo.java
@@ -48,53 +48,53 @@ import java.util.Map;
/**
* @hide
*/
-public final class ApduServiceInfo implements Parcelable {
+public class ApduServiceInfo implements Parcelable {
static final String TAG = "ApduServiceInfo";
/**
* The service that implements this
*/
- final ResolveInfo mService;
+ protected ResolveInfo mService;
/**
* Description of the service
*/
- final String mDescription;
+ protected String mDescription;
/**
* Whether this service represents AIDs running on the host CPU
*/
- final boolean mOnHost;
+ protected boolean mOnHost;
/**
* Mapping from category to static AID group
*/
- final HashMap<String, AidGroup> mStaticAidGroups;
+ protected HashMap<String, AidGroup> mStaticAidGroups;
/**
* Mapping from category to dynamic AID group
*/
- final HashMap<String, AidGroup> mDynamicAidGroups;
+ protected HashMap<String, AidGroup> mDynamicAidGroups;
/**
* Whether this service should only be started when the device is unlocked.
*/
- final boolean mRequiresDeviceUnlock;
+ protected boolean mRequiresDeviceUnlock;
/**
* The id of the service banner specified in XML.
*/
- final int mBannerResourceId;
+ protected int mBannerResourceId;
/**
* The uid of the package the service belongs to
*/
- final int mUid;
+ protected int mUid;
/**
* Settings Activity for this service
*/
- final String mSettingsActivityName;
+ protected String mSettingsActivityName;
/**
* @hide
diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java
index f346fe7..2567a41 100644
--- a/core/java/android/os/Environment.java
+++ b/core/java/android/os/Environment.java
@@ -37,6 +37,7 @@ public class Environment {
private static final String ENV_ANDROID_STORAGE = "ANDROID_STORAGE";
private static final String ENV_OEM_ROOT = "OEM_ROOT";
private static final String ENV_VENDOR_ROOT = "VENDOR_ROOT";
+ private static final String ENV_PREBUNDLED_ROOT = "PREBUNDLED_ROOT";
/** {@hide} */
public static final String DIR_ANDROID = "Android";
@@ -55,6 +56,7 @@ public class Environment {
private static final File DIR_ANDROID_STORAGE = getDirectory(ENV_ANDROID_STORAGE, "/storage");
private static final File DIR_OEM_ROOT = getDirectory(ENV_OEM_ROOT, "/oem");
private static final File DIR_VENDOR_ROOT = getDirectory(ENV_VENDOR_ROOT, "/vendor");
+ private static final File DIR_PREBUNDLED_ROOT = getDirectory(ENV_PREBUNDLED_ROOT, "/vendor/bundled-app");
private static final String SYSTEM_PROPERTY_EFS_ENABLED = "persist.security.efs.enabled";
@@ -165,6 +167,15 @@ public class Environment {
}
/**
+ * Return the root directory for "prebundled" apps. These apps will be installed directly
+ * from this partition but will not be marked as system apps and will hence be uninstallable.
+ * @hide
+ */
+ public static File getPrebundledDirectory() {
+ return DIR_PREBUNDLED_ROOT;
+ }
+
+ /**
* Gets the system directory available for secure storage.
* If Encrypted File system is enabled, it returns an encrypted directory (/data/secure/system).
* Otherwise, it returns the unencrypted /data/system directory.
diff --git a/core/java/android/os/IDeviceIdleController.aidl b/core/java/android/os/IDeviceIdleController.aidl
index f55883a..6c7cd6d 100644
--- a/core/java/android/os/IDeviceIdleController.aidl
+++ b/core/java/android/os/IDeviceIdleController.aidl
@@ -35,4 +35,5 @@ interface IDeviceIdleController {
long addPowerSaveTempWhitelistAppForMms(String name, int userId, String reason);
long addPowerSaveTempWhitelistAppForSms(String name, int userId, String reason);
void exitIdle(String reason);
+ int getIdleStateDetailed();
}
diff --git a/core/java/android/os/IPowerManager.aidl b/core/java/android/os/IPowerManager.aidl
index 0f37ac7..4e0f329 100644
--- a/core/java/android/os/IPowerManager.aidl
+++ b/core/java/android/os/IPowerManager.aidl
@@ -60,4 +60,14 @@ interface IPowerManager
// sets the attention light (used by phone app only)
void setAttentionLight(boolean on, int color);
+ // update the uids being synchronized by network socket request manager
+ void updateBlockedUids(int uid, boolean isBlocked);
+
+ void setKeyboardVisibility(boolean visible);
+
+ void setKeyboardLight(boolean on, int key);
+
+ oneway void cpuBoost(int duration);
+
+ void wakeUpWithProximityCheck(long time, String reason, String opPackageName);
}
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index 9a1a03e..bbee5a3 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -18,7 +18,10 @@ package android.os;
import android.annotation.SdkConstant;
import android.annotation.SystemApi;
+import android.content.ComponentName;
import android.content.Context;
+import android.content.Intent;
+import android.text.TextUtils;
import android.util.Log;
/**
@@ -387,7 +390,7 @@ public final class PowerManager {
* @hide
*/
public static final String REBOOT_RECOVERY = "recovery";
-
+
final Context mContext;
final IPowerManager mService;
final Handler mHandler;
@@ -674,6 +677,19 @@ public final class PowerManager {
}
/**
+ * Forces the device to wake up from sleep only if
+ * nothing is blocking the proximity sensor
+ * @see #wakeUp
+ * @hide
+ */
+ public void wakeUpWithProximityCheck(long time, String reason) {
+ try {
+ mService.wakeUpWithProximityCheck(time, reason, mContext.getOpPackageName());
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
* Forces the device to start napping.
* <p>
* If the device is currently awake, starts dreaming, otherwise does nothing.
@@ -1235,4 +1251,68 @@ public final class PowerManager {
}
}
}
+
+ /**
+ * @hide
+ */
+ public void setKeyboardVisibility(boolean visible)
+ {
+ try {
+ if (mService != null) {
+ mService.setKeyboardVisibility(visible);
+ }
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * sets the keyboard LED state
+ *
+ * @param on boolean state
+ * @param key 1 for caps, 2 for fn
+ *
+ * {@hide}
+ */
+ public void setKeyboardLight(boolean on, int key)
+ {
+ try {
+ mService.setKeyboardLight(on, key);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Gets the default button brightness value.
+ * @hide
+ */
+ public int getDefaultButtonBrightness() {
+ return mContext.getResources().getInteger(
+ com.android.internal.R.integer.config_buttonBrightnessSettingDefault);
+ }
+
+ /**
+ * Gets the default keyboard brightness value.
+ * @hide
+ */
+ public int getDefaultKeyboardBrightness() {
+ return mContext.getResources().getInteger(
+ com.android.internal.R.integer.config_keyboardBrightnessSettingDefault);
+ }
+
+ /**
+ * Boost the CPU. Boosts the cpu for the given duration in microseconds.
+ *
+ * @param duration in microseconds to boost the CPU
+ *
+ * @hide
+ */
+ public void cpuBoost(int duration)
+ {
+ try {
+ if (mService != null) {
+ mService.cpuBoost(duration);
+ }
+ } catch (RemoteException e) {
+ }
+ }
}
diff --git a/core/java/android/os/PowerManagerInternal.java b/core/java/android/os/PowerManagerInternal.java
index 17bce30..38037a6 100644
--- a/core/java/android/os/PowerManagerInternal.java
+++ b/core/java/android/os/PowerManagerInternal.java
@@ -153,4 +153,11 @@ public abstract class PowerManagerInternal {
public abstract void uidGone(int uid);
public abstract void powerHint(int hintId, int data);
+
+ public abstract boolean setPowerSaveMode(boolean mode);
+
+ public abstract void setFeature(int featureId, int data);
+
+ public abstract int getFeature(int featureId);
+
}
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index 7234e98..65b09eb 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -487,11 +487,12 @@ public class Process {
String abi,
String instructionSet,
String appDataDir,
+ boolean refreshTheme,
String[] zygoteArgs) {
try {
return startViaZygote(processClass, niceName, uid, gid, gids,
debugFlags, mountExternal, targetSdkVersion, seInfo,
- abi, instructionSet, appDataDir, zygoteArgs);
+ abi, instructionSet, appDataDir, refreshTheme, zygoteArgs);
} catch (ZygoteStartFailedEx ex) {
Log.e(LOG_TAG,
"Starting VM process through Zygote failed");
@@ -610,6 +611,7 @@ public class Process {
String abi,
String instructionSet,
String appDataDir,
+ boolean refreshTheme,
String[] extraArgs)
throws ZygoteStartFailedEx {
synchronized(Process.class) {
@@ -648,6 +650,9 @@ public class Process {
} else if (mountExternal == Zygote.MOUNT_EXTERNAL_WRITE) {
argsForZygote.add("--mount-external-write");
}
+ if (refreshTheme) {
+ argsForZygote.add("--refresh_theme");
+ }
argsForZygote.add("--target-sdk-version=" + targetSdkVersion);
//TODO optionally enable debuger
diff --git a/core/java/android/os/RecoverySystem.java b/core/java/android/os/RecoverySystem.java
index 0c79094..4b6e6c1 100644
--- a/core/java/android/os/RecoverySystem.java
+++ b/core/java/android/os/RecoverySystem.java
@@ -341,6 +341,10 @@ public class RecoverySystem {
} finally {
uncryptFile.close();
}
+ // UNCRYPT_FILE needs to be readable by system server on bootup.
+ if (!UNCRYPT_FILE.setReadable(true, false)) {
+ Log.e(TAG, "Error setting readable for " + UNCRYPT_FILE.getCanonicalPath());
+ }
Log.w(TAG, "!!! REBOOTING TO INSTALL " + filename + " !!!");
// If the package is on the /data partition, write the block map file
@@ -368,21 +372,21 @@ public class RecoverySystem {
* @throws SecurityException if the current user is not allowed to wipe data.
*/
public static void rebootWipeUserData(Context context) throws IOException {
- rebootWipeUserData(context, false, context.getPackageName());
+ rebootWipeUserData(context, false, context.getPackageName(), false);
}
/** {@hide} */
public static void rebootWipeUserData(Context context, String reason) throws IOException {
- rebootWipeUserData(context, false, reason);
+ rebootWipeUserData(context, false, reason, false);
}
/** {@hide} */
public static void rebootWipeUserData(Context context, boolean shutdown)
throws IOException {
- rebootWipeUserData(context, shutdown, context.getPackageName());
+ rebootWipeUserData(context, shutdown, context.getPackageName(), false);
}
- /**
+ /**
* Reboots the device and wipes the user data and cache
* partitions. This is sometimes called a "factory reset", which
* is something of a misnomer because the system partition is not
@@ -400,8 +404,8 @@ public class RecoverySystem {
*
* @hide
*/
- public static void rebootWipeUserData(Context context, boolean shutdown, String reason)
- throws IOException {
+ public static void rebootWipeUserData(Context context, boolean shutdown, String reason,
+ boolean wipeMedia) throws IOException {
UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE);
if (um.hasUserRestriction(UserManager.DISALLOW_FACTORY_RESET)) {
throw new SecurityException("Wiping data is not allowed for this user.");
@@ -433,7 +437,13 @@ public class RecoverySystem {
}
final String localeArg = "--locale=" + Locale.getDefault().toString();
- bootCommand(context, shutdownArg, "--wipe_data", reasonArg, localeArg);
+
+ String cmd = "--wipe_data\n";
+ if (wipeMedia) {
+ cmd += "--wipe_media\n";
+ }
+
+ bootCommand(context, shutdownArg, cmd, reasonArg, localeArg);
}
/**
@@ -501,6 +511,25 @@ public class RecoverySystem {
Log.e(TAG, "Error reading recovery log", e);
}
+ if (UNCRYPT_FILE.exists()) {
+ String filename = null;
+ try {
+ filename = FileUtils.readTextFile(UNCRYPT_FILE, 0, null);
+ } catch (IOException e) {
+ Log.e(TAG, "Error reading uncrypt file", e);
+ }
+
+ // Remove the OTA package on /data that has been (possibly
+ // partially) processed. (Bug: 24973532)
+ if (filename != null && filename.startsWith("/data")) {
+ if (UNCRYPT_FILE.delete()) {
+ Log.i(TAG, "Deleted: " + filename);
+ } else {
+ Log.e(TAG, "Can't delete: " + filename);
+ }
+ }
+ }
+
// Delete everything in RECOVERY_DIR except those beginning
// with LAST_PREFIX
String[] names = RECOVERY_DIR.list();
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 045c1e8..5b532a3 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -489,6 +489,18 @@ public class UserManager {
*/
public static final String KEY_RESTRICTIONS_PENDING = "restrictions_pending";
+ /**
+ * Specifies if the user is not allowed to use SU commands.
+ * The default value is <code>false</code>.
+ *
+ * <p/>Key for user restrictions.
+ * <p/>Type: Boolean
+ * @see #setUserRestrictions(Bundle)
+ * @see #getUserRestrictions()
+ * @hide
+ */
+ public static final String DISALLOW_SU = "no_su";
+
/** @hide */
public static final int PIN_VERIFICATION_FAILED_INCORRECT = -3;
/** @hide */
@@ -853,6 +865,7 @@ public class UserManager {
Bundle guestRestrictions = mService.getDefaultGuestRestrictions();
guestRestrictions.putBoolean(DISALLOW_SMS, true);
guestRestrictions.putBoolean(DISALLOW_INSTALL_UNKNOWN_SOURCES, true);
+ guestRestrictions.putBoolean(DISALLOW_SU, true);
mService.setUserRestrictions(guestRestrictions, guest.id);
} catch (RemoteException re) {
Log.w(TAG, "Could not update guest restrictions");
@@ -892,6 +905,7 @@ public class UserManager {
private static void addDefaultUserRestrictions(Bundle restrictions) {
restrictions.putBoolean(DISALLOW_OUTGOING_CALLS, true);
restrictions.putBoolean(DISALLOW_SMS, true);
+ restrictions.putBoolean(DISALLOW_SU, true);
}
/**
diff --git a/core/java/android/os/storage/DiskInfo.java b/core/java/android/os/storage/DiskInfo.java
index 9114107..db0b0fd 100644
--- a/core/java/android/os/storage/DiskInfo.java
+++ b/core/java/android/os/storage/DiskInfo.java
@@ -47,6 +47,8 @@ public class DiskInfo implements Parcelable {
public static final int FLAG_DEFAULT_PRIMARY = 1 << 1;
public static final int FLAG_SD = 1 << 2;
public static final int FLAG_USB = 1 << 3;
+ public static final int FLAG_EMMC = 1 << 4;
+ public static final int FLAG_NON_REMOVABLE = 1 << 5;
public final String id;
public final int flags;
@@ -128,6 +130,10 @@ public class DiskInfo implements Parcelable {
return (flags & FLAG_USB) != 0;
}
+ public boolean isNonRemovable() {
+ return (flags & FLAG_NON_REMOVABLE) != 0;
+ }
+
@Override
public String toString() {
final CharArrayWriter writer = new CharArrayWriter();
diff --git a/core/java/android/os/storage/IMountService.java b/core/java/android/os/storage/IMountService.java
index 9f71ce1..5f84351 100644
--- a/core/java/android/os/storage/IMountService.java
+++ b/core/java/android/os/storage/IMountService.java
@@ -645,6 +645,24 @@ public interface IMountService extends IInterface {
return _result;
}
+ public int encryptWipeStorage(int type, String password) throws RemoteException {
+ Parcel _data = Parcel.obtain();
+ Parcel _reply = Parcel.obtain();
+ int _result;
+ try {
+ _data.writeInterfaceToken(DESCRIPTOR);
+ _data.writeInt(type);
+ _data.writeString(password);
+ mRemote.transact(Stub.TRANSACTION_encryptWipeStorage, _data, _reply, 0);
+ _reply.readException();
+ _result = _reply.readInt();
+ } finally {
+ _reply.recycle();
+ _data.recycle();
+ }
+ return _result;
+ }
+
public int changeEncryptionPassword(int type, String password) throws RemoteException {
Parcel _data = Parcel.obtain();
Parcel _reply = Parcel.obtain();
@@ -1326,6 +1344,8 @@ public interface IMountService extends IInterface {
static final int TRANSACTION_benchmark = IBinder.FIRST_CALL_TRANSACTION + 59;
static final int TRANSACTION_setDebugFlags = IBinder.FIRST_CALL_TRANSACTION + 60;
+ static final int TRANSACTION_encryptWipeStorage = IBinder.FIRST_CALL_TRANSACTION + 61;
+
static final int TRANSACTION_createNewUserDir = IBinder.FIRST_CALL_TRANSACTION + 62;
static final int TRANSACTION_deleteUserKey = IBinder.FIRST_CALL_TRANSACTION + 63;
@@ -1631,6 +1651,15 @@ public interface IMountService extends IInterface {
reply.writeInt(result);
return true;
}
+ case TRANSACTION_encryptWipeStorage: {
+ data.enforceInterface(DESCRIPTOR);
+ int type = data.readInt();
+ String password = data.readString();
+ int result = encryptWipeStorage(type, password);
+ reply.writeNoException();
+ reply.writeInt(result);
+ return true;
+ }
case TRANSACTION_changeEncryptionPassword: {
data.enforceInterface(DESCRIPTOR);
int type = data.readInt();
@@ -2065,7 +2094,8 @@ public interface IMountService extends IInterface {
* Returns whether or not the external storage is emulated.
*/
public boolean isExternalStorageEmulated() throws RemoteException;
-
+ /** The volume has been encrypted succesfully and MDTP state is 'activated'. */
+ static final int ENCRYPTION_STATE_OK_MDTP_ACTIVATED = 2;
/** The volume is not encrypted. */
static final int ENCRYPTION_STATE_NONE = 1;
/** The volume has been encrypted succesfully. */
@@ -2078,6 +2108,8 @@ public interface IMountService extends IInterface {
static final int ENCRYPTION_STATE_ERROR_INCONSISTENT = -3;
/** Underlying data is corrupt */
static final int ENCRYPTION_STATE_ERROR_CORRUPT = -4;
+ /** The volume is in a bad state and MDTP state is 'activated'.*/
+ static final int ENCRYPTION_STATE_ERROR_MDTP_ACTIVATED = -5;
/**
* Determines the encryption state of the volume.
@@ -2096,6 +2128,11 @@ public interface IMountService extends IInterface {
public int encryptStorage(int type, String password) throws RemoteException;
/**
+ * Encrypts and wipes storage.
+ */
+ public int encryptWipeStorage(int type, String password) throws RemoteException;
+
+ /**
* Changes the encryption password.
*/
public int changeEncryptionPassword(int type, String password)
diff --git a/core/java/android/os/storage/StorageVolume.java b/core/java/android/os/storage/StorageVolume.java
index 1408202..4dbd0a6 100644
--- a/core/java/android/os/storage/StorageVolume.java
+++ b/core/java/android/os/storage/StorageVolume.java
@@ -196,15 +196,20 @@ public class StorageVolume implements Parcelable {
}
/**
- * Parse and return volume UUID as FAT volume ID, or return -1 if unable to
+ * Parse and return volume UUID as volume ID, or return -1 if unable to
* parse or UUID is unknown.
*/
- public int getFatVolumeId() {
- if (mFsUuid == null || mFsUuid.length() != 9) {
+ public int getVolumeId() {
+ String id = mFsUuid;
+ if (id == null) {
return -1;
}
+ id = id.replace("-", "");
+ if (id.length() > 8) {
+ id = id.substring(0, 8);
+ }
try {
- return (int) Long.parseLong(mFsUuid.replace("-", ""), 16);
+ return (int) Long.parseLong(id, 16);
} catch (NumberFormatException e) {
return -1;
}
diff --git a/core/java/android/preference/DialogPreference.java b/core/java/android/preference/DialogPreference.java
index 3d57b4d..1aec3ec 100644
--- a/core/java/android/preference/DialogPreference.java
+++ b/core/java/android/preference/DialogPreference.java
@@ -285,6 +285,22 @@ public abstract class DialogPreference extends Preference implements
* @param state Optional instance state to restore on the dialog
*/
protected void showDialog(Bundle state) {
+ // Create the dialog
+ final Dialog dialog = mDialog = createDialog();
+ if (state != null) {
+ dialog.onRestoreInstanceState(state);
+ }
+ if (needInputMethod()) {
+ requestInputMethod(dialog);
+ }
+ dialog.setOnDismissListener(this);
+ dialog.show();
+ }
+
+ /**
+ * @hide
+ */
+ protected Dialog createDialog() {
Context context = getContext();
mWhichButtonClicked = DialogInterface.BUTTON_NEGATIVE;
@@ -306,17 +322,8 @@ public abstract class DialogPreference extends Preference implements
onPrepareDialogBuilder(mBuilder);
getPreferenceManager().registerOnActivityDestroyListener(this);
-
- // Create the dialog
- final Dialog dialog = mDialog = mBuilder.create();
- if (state != null) {
- dialog.onRestoreInstanceState(state);
- }
- if (needInputMethod()) {
- requestInputMethod(dialog);
- }
- dialog.setOnDismissListener(this);
- dialog.show();
+
+ return mBuilder.create();
}
/**
diff --git a/core/java/android/preference/MultiSelectListPreference.java b/core/java/android/preference/MultiSelectListPreference.java
index 138bd87..6acfd8d 100644..100755
--- a/core/java/android/preference/MultiSelectListPreference.java
+++ b/core/java/android/preference/MultiSelectListPreference.java
@@ -220,7 +220,7 @@ public class MultiSelectListPreference extends DialogPreference {
@Override
protected Object onGetDefaultValue(TypedArray a, int index) {
final CharSequence[] defaultValues = a.getTextArray(index);
- final int valueCount = defaultValues.length;
+ final int valueCount = defaultValues != null ? defaultValues.length : 0;
final Set<String> result = new HashSet<String>();
for (int i = 0; i < valueCount; i++) {
@@ -247,7 +247,20 @@ public class MultiSelectListPreference extends DialogPreference {
myState.values = getValues();
return myState;
}
-
+
+ @Override
+ protected void onRestoreInstanceState(Parcelable state) {
+ if (!state.getClass().equals(SavedState.class)) {
+ // Didn't save state for us in onSaveInstanceState
+ super.onRestoreInstanceState(state);
+ return;
+ }
+
+ SavedState myState = (SavedState) state;
+ super.onRestoreInstanceState(myState.getSuperState());
+ setValues(myState.values);
+ }
+
private static class SavedState extends BaseSavedState {
Set<String> values;
diff --git a/core/java/android/preference/Preference.java b/core/java/android/preference/Preference.java
index 3b482eb..b15a7e5 100644
--- a/core/java/android/preference/Preference.java
+++ b/core/java/android/preference/Preference.java
@@ -1377,10 +1377,18 @@ public class Preference implements Comparable<Preference> {
mDefaultValue = defaultValue;
}
+ /**
+ * Returns whether the preference can be found in persistent storage
+ * @hide
+ */
+ protected boolean isPersisted() {
+ return getSharedPreferences().contains(mKey);
+ }
+
private void dispatchSetInitialValue() {
// By now, we know if we are persistent.
final boolean shouldPersist = shouldPersist();
- if (!shouldPersist || !getSharedPreferences().contains(mKey)) {
+ if (!shouldPersist || !isPersisted()) {
if (mDefaultValue != null) {
onSetInitialValue(false, mDefaultValue);
}
diff --git a/core/java/android/preference/PreferenceFragment.java b/core/java/android/preference/PreferenceFragment.java
index 66642de..db04c71 100644
--- a/core/java/android/preference/PreferenceFragment.java
+++ b/core/java/android/preference/PreferenceFragment.java
@@ -214,6 +214,9 @@ public abstract class PreferenceFragment extends Fragment implements
@Override
public void onDestroyView() {
+ if (mList != null) {
+ mList.setOnKeyListener(null);
+ }
mList = null;
mHandler.removeCallbacks(mRequestFocus);
mHandler.removeMessages(MSG_BIND_PREFERENCES);
diff --git a/core/java/android/preference/PreferenceGroup.java b/core/java/android/preference/PreferenceGroup.java
index 5e84086..f17506b 100644
--- a/core/java/android/preference/PreferenceGroup.java
+++ b/core/java/android/preference/PreferenceGroup.java
@@ -148,16 +148,15 @@ public abstract class PreferenceGroup extends Preference implements GenericInfla
}
}
- int insertionIndex = Collections.binarySearch(mPreferenceList, preference);
- if (insertionIndex < 0) {
- insertionIndex = insertionIndex * -1 - 1;
- }
-
if (!onPrepareAddPreference(preference)) {
return false;
}
synchronized(this) {
+ int insertionIndex = Collections.binarySearch(mPreferenceList, preference);
+ if (insertionIndex < 0) {
+ insertionIndex = insertionIndex * -1 - 1;
+ }
mPreferenceList.add(insertionIndex, preference);
}
diff --git a/core/java/android/preference/RingtonePreference.java b/core/java/android/preference/RingtonePreference.java
index a76bb09..81c0595 100644
--- a/core/java/android/preference/RingtonePreference.java
+++ b/core/java/android/preference/RingtonePreference.java
@@ -48,6 +48,7 @@ public class RingtonePreference extends Preference implements
private int mRingtoneType;
private boolean mShowDefault;
private boolean mShowSilent;
+ private int mDialogStyle;
private int mRequestCode;
@@ -62,6 +63,8 @@ public class RingtonePreference extends Preference implements
true);
mShowSilent = a.getBoolean(com.android.internal.R.styleable.RingtonePreference_showSilent,
true);
+ mDialogStyle = a.getResourceId(
+ com.android.internal.R.styleable.RingtonePreference_dialogStyle, 0);
a.recycle();
}
@@ -136,6 +139,27 @@ public class RingtonePreference extends Preference implements
mShowSilent = showSilent;
}
+ /**
+ * Returns the resource id style of the ringtone dialog.
+ *
+ * @return The resource id of the style
+ * @hide
+ */
+ public int getDialogStyle() {
+ return mDialogStyle;
+ }
+
+ /**
+ * Sets the resource id style of the ringtone dialog.
+ *
+ * @param dialogStyle The resource id of the style.
+ * @see RingtoneManager#EXTRA_RINGTONE_DIALOG_THEME
+ * @hide
+ */
+ public void setDialogStyle(int dialogStyle) {
+ mDialogStyle = dialogStyle;
+ }
+
@Override
protected void onClick() {
// Launch the ringtone picker
@@ -166,6 +190,10 @@ public class RingtonePreference extends Preference implements
ringtonePickerIntent.putExtra(RingtoneManager.EXTRA_RINGTONE_DEFAULT_URI,
RingtoneManager.getDefaultUri(getRingtoneType()));
}
+ if (mDialogStyle != 0) {
+ ringtonePickerIntent.putExtra(RingtoneManager.EXTRA_RINGTONE_DIALOG_THEME,
+ mDialogStyle);
+ }
ringtonePickerIntent.putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_SILENT, mShowSilent);
ringtonePickerIntent.putExtra(RingtoneManager.EXTRA_RINGTONE_TYPE, mRingtoneType);
diff --git a/core/java/android/provider/Browser.java b/core/java/android/provider/Browser.java
index 7d05522..299a95c 100644
--- a/core/java/android/provider/Browser.java
+++ b/core/java/android/provider/Browser.java
@@ -244,6 +244,7 @@ public class Browser {
*/
public static final Cursor getAllBookmarks(ContentResolver cr) throws
IllegalStateException {
+ android.util.SeempLog.record(32);
return new MatrixCursor(new String[]{Bookmarks.URL}, 0);
}
@@ -256,6 +257,7 @@ public class Browser {
*/
public static final Cursor getAllVisitedUrls(ContentResolver cr) throws
IllegalStateException {
+ android.util.SeempLog.record(33);
return new MatrixCursor(new String[]{Combined.URL}, 0);
}
@@ -264,6 +266,7 @@ public class Browser {
}
private static final Cursor getVisitedLike(ContentResolver cr, String url) {
+ android.util.SeempLog.record(34);
boolean secure = false;
String compareString = url;
if (compareString.startsWith("http://")) {
@@ -324,6 +327,7 @@ public class Browser {
*/
@Deprecated
public static final String[] getVisitedHistory(ContentResolver cr) {
+ android.util.SeempLog.record(35);
return new String[0];
}
@@ -359,6 +363,7 @@ public class Browser {
* @removed
*/
public static final void clearHistory(ContentResolver cr) {
+ android.util.SeempLog.record(37);
}
@@ -420,6 +425,7 @@ public class Browser {
*/
public static final void requestAllIcons(ContentResolver cr, String where,
WebIconDatabase.IconListener listener) {
+ android.util.SeempLog.record(36);
// Do nothing: this is no longer used.
}
diff --git a/core/java/android/provider/CalendarContract.java b/core/java/android/provider/CalendarContract.java
index aa22041..2ede026 100644
--- a/core/java/android/provider/CalendarContract.java
+++ b/core/java/android/provider/CalendarContract.java
@@ -871,6 +871,7 @@ public final class CalendarContract {
* @return A Cursor containing all attendees for the event
*/
public static final Cursor query(ContentResolver cr, long eventId, String[] projection) {
+ android.util.SeempLog.record(54);
String[] attArgs = {Long.toString(eventId)};
return cr.query(CONTENT_URI, projection, ATTENDEES_WHERE, attArgs /* selection args */,
null /* sort order */);
@@ -1750,6 +1751,7 @@ public final class CalendarContract {
*/
public static final Cursor query(ContentResolver cr, String[] projection,
long begin, long end) {
+ android.util.SeempLog.record(54);
Uri.Builder builder = CONTENT_URI.buildUpon();
ContentUris.appendId(builder, begin);
ContentUris.appendId(builder, end);
@@ -1779,6 +1781,7 @@ public final class CalendarContract {
*/
public static final Cursor query(ContentResolver cr, String[] projection,
long begin, long end, String searchQuery) {
+ android.util.SeempLog.record(54);
Uri.Builder builder = CONTENT_SEARCH_URI.buildUpon();
ContentUris.appendId(builder, begin);
ContentUris.appendId(builder, end);
@@ -2029,6 +2032,7 @@ public final class CalendarContract {
*/
public static final Cursor query(ContentResolver cr, int startDay, int numDays,
String[] projection) {
+ android.util.SeempLog.record(54);
if (numDays < 1) {
return null;
}
@@ -2112,6 +2116,7 @@ public final class CalendarContract {
* @return A Cursor containing all reminders for the event
*/
public static final Cursor query(ContentResolver cr, long eventId, String[] projection) {
+ android.util.SeempLog.record(54);
String[] remArgs = {Long.toString(eventId)};
return cr.query(CONTENT_URI, projection, REMINDERS_WHERE, remArgs /*selection args*/,
null /* sort order */);
@@ -2262,6 +2267,7 @@ public final class CalendarContract {
*/
public static final Uri insert(ContentResolver cr, long eventId,
long begin, long end, long alarmTime, int minutes) {
+ android.util.SeempLog.record(51);
ContentValues values = new ContentValues();
values.put(CalendarAlerts.EVENT_ID, eventId);
values.put(CalendarAlerts.BEGIN, begin);
@@ -2289,6 +2295,7 @@ public final class CalendarContract {
* @hide
*/
public static final long findNextAlarmTime(ContentResolver cr, long millis) {
+ android.util.SeempLog.record(53);
String selection = ALARM_TIME + ">=" + millis;
// TODO: construct an explicit SQL query so that we can add
// "LIMIT 1" to the end and get just one result.
@@ -2412,6 +2419,7 @@ public final class CalendarContract {
*/
public static final boolean alarmExists(ContentResolver cr, long eventId,
long begin, long alarmTime) {
+ android.util.SeempLog.record(52);
// TODO: construct an explicit SQL query so that we can add
// "LIMIT 1" to the end and get just one result.
String[] projection = new String[] { ALARM_TIME };
diff --git a/core/java/android/provider/CallLog.java b/core/java/android/provider/CallLog.java
index 4f880b1..3a3eca4 100644
--- a/core/java/android/provider/CallLog.java
+++ b/core/java/android/provider/CallLog.java
@@ -164,6 +164,10 @@ public class CallLog {
public static final int MISSED_TYPE = 3;
/** Call log type for voicemails. */
public static final int VOICEMAIL_TYPE = 4;
+ /** Call log type for blacklisted calls
+ * @hide
+ */
+ public static final int BLACKLIST_TYPE = 5;
/**
* Bit-mask describing features of the call (e.g. video).
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index 8ce1cbf..0e7f487 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -1119,7 +1119,15 @@ public final class ContactsContract {
public static final String SORT_KEY_ALTERNATIVE = "sort_key_alt";
}
- interface ContactCounts {
+ /**
+ * URI parameter and cursor extras that return counts of rows grouped by the
+ * address book index, which is usually the first letter of the sort key.
+ * When this parameter is supplied, the row counts are returned in the
+ * cursor extras bundle.
+ *
+ * @hide
+ */
+ public interface ContactCounts {
/**
* Add this query parameter to a URI to get back row counts grouped by the address book
@@ -1497,6 +1505,7 @@ public final class ContactsContract {
* {@link #CONTENT_LOOKUP_URI} to attempt refreshing.
*/
public static Uri getLookupUri(ContentResolver resolver, Uri contactUri) {
+ android.util.SeempLog.record(86);
final Cursor c = resolver.query(contactUri, new String[] {
Contacts.LOOKUP_KEY, Contacts._ID
}, null, null, null);
@@ -1524,6 +1533,7 @@ public final class ContactsContract {
* provided parameters.
*/
public static Uri getLookupUri(long contactId, String lookupKey) {
+ android.util.SeempLog.record(86);
if (TextUtils.isEmpty(lookupKey)) {
return null;
}
@@ -1537,6 +1547,7 @@ public final class ContactsContract {
* Returns null if the contact cannot be found.
*/
public static Uri lookupContact(ContentResolver resolver, Uri lookupUri) {
+ android.util.SeempLog.record(87);
if (lookupUri == null) {
return null;
}
@@ -1999,6 +2010,7 @@ public final class ContactsContract {
*/
public static InputStream openContactPhotoInputStream(ContentResolver cr, Uri contactUri,
boolean preferHighres) {
+ android.util.SeempLog.record(88);
if (preferHighres) {
final Uri displayPhotoUri = Uri.withAppendedPath(contactUri,
Contacts.Photo.DISPLAY_PHOTO);
@@ -2046,6 +2058,7 @@ public final class ContactsContract {
* of the thumbnail the high-res picture is preferred
*/
public static InputStream openContactPhotoInputStream(ContentResolver cr, Uri contactUri) {
+ android.util.SeempLog.record(88);
return openContactPhotoInputStream(cr, contactUri, false);
}
}
@@ -2738,6 +2751,7 @@ public final class ContactsContract {
* entry of the given {@link RawContacts} entry.
*/
public static Uri getContactLookupUri(ContentResolver resolver, Uri rawContactUri) {
+ android.util.SeempLog.record(89);
// TODO: use a lighter query by joining rawcontacts with contacts in provider
final Uri dataUri = Uri.withAppendedPath(rawContactUri, Data.CONTENT_DIRECTORY);
final Cursor cursor = resolver.query(dataUri, new String[] {
@@ -4684,6 +4698,7 @@ public final class ContactsContract {
* </p>
*/
public static Uri getContactLookupUri(ContentResolver resolver, Uri dataUri) {
+ android.util.SeempLog.record(89);
final Cursor cursor = resolver.query(dataUri, new String[] {
RawContacts.CONTACT_ID, Contacts.LOOKUP_KEY
}, null, null, null);
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 53897e0..a3de3d1 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -64,11 +64,14 @@ import com.android.internal.widget.ILockSettings;
import java.net.URISyntaxException;
import java.text.SimpleDateFormat;
+import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
+import java.util.regex.Pattern;
/**
* The Settings provider contains global system-level device preferences.
@@ -1492,6 +1495,11 @@ public final class Settings {
// At one time in System, then Global, but now back in Secure
MOVED_TO_SECURE.add(Secure.INSTALL_NON_MARKET_APPS);
+
+ MOVED_TO_SECURE.add(System.DEV_FORCE_SHOW_NAVBAR);
+ MOVED_TO_SECURE.add(System.KEYBOARD_BRIGHTNESS);
+ MOVED_TO_SECURE.add(System.BUTTON_BRIGHTNESS);
+ MOVED_TO_SECURE.add(System.BUTTON_BACKLIGHT_TIMEOUT);
}
private static final HashSet<String> MOVED_TO_GLOBAL;
@@ -1583,6 +1591,44 @@ public final class Settings {
}
};
+ /**
+ * Put a delimited list as a string
+ * @param resolver to access the database with
+ * @param name to store
+ * @param delimiter to split
+ * @param list to join and store
+ * @hide
+ */
+ public static void putListAsDelimitedString(ContentResolver resolver, String name,
+ String delimiter, List<String> list) {
+ String store = TextUtils.join(delimiter, list);
+ putString(resolver, name, store);
+ }
+
+ /**
+ * Get a delimited string returned as a list
+ * @param resolver to access the database with
+ * @param name to store
+ * @param delimiter to split the list with
+ * @return list of strings for a specific Settings.Secure item
+ * @hide
+ */
+ public static List<String> getDelimitedStringAsList(ContentResolver resolver, String name,
+ String delimiter) {
+ String baseString = getString(resolver, name);
+ List<String> list = new ArrayList<String>();
+ if (!TextUtils.isEmpty(baseString)) {
+ final String[] array = TextUtils.split(baseString, Pattern.quote(delimiter));
+ for (String item : array) {
+ if (TextUtils.isEmpty(item)) {
+ continue;
+ }
+ list.add(item);
+ }
+ }
+ return list;
+ }
+
/** @hide */
public static void getMovedToGlobalSettings(Set<String> outKeySet) {
outKeySet.addAll(MOVED_TO_GLOBAL);
@@ -1612,6 +1658,7 @@ public final class Settings {
/** @hide */
public static String getStringForUser(ContentResolver resolver, String name,
int userHandle) {
+ android.util.SeempLog.record(android.util.SeempLog.getSeempGetApiIdFromValue(name));
if (MOVED_TO_SECURE.contains(name)) {
Log.w(TAG, "Setting " + name + " has moved from android.provider.Settings.System"
+ " to android.provider.Settings.Secure, returning read-only value.");
@@ -1639,6 +1686,7 @@ public final class Settings {
/** @hide */
public static boolean putStringForUser(ContentResolver resolver, String name, String value,
int userHandle) {
+ android.util.SeempLog.record(android.util.SeempLog.getSeempPutApiIdFromValue(name));
if (MOVED_TO_SECURE.contains(name)) {
Log.w(TAG, "Setting " + name + " has moved from android.provider.Settings.System"
+ " to android.provider.Settings.Secure, value is unchanged.");
@@ -1646,8 +1694,9 @@ public final class Settings {
}
if (MOVED_TO_GLOBAL.contains(name) || MOVED_TO_SECURE_THEN_GLOBAL.contains(name)) {
Log.w(TAG, "Setting " + name + " has moved from android.provider.Settings.System"
- + " to android.provider.Settings.Global, value is unchanged.");
- return false;
+ + " to android.provider.Settings.Global.");
+
+ return Global.putStringForUser(resolver, name, value, userHandle);
}
return sNameValueCache.putStringForUser(resolver, name, value, userHandle);
}
@@ -2433,6 +2482,31 @@ public final class Settings {
public static final int SCREEN_BRIGHTNESS_MODE_AUTOMATIC = 1;
/**
+ * The keyboard brightness to be used while the screen is on.
+ * Valid value range is between 0 and {@link PowerManager#getMaximumKeyboardBrightness()}
+ * @deprecated
+ * @hide
+ */
+ public static final String KEYBOARD_BRIGHTNESS = "keyboard_brightness";
+
+ /**
+ * The button brightness to be used while the screen is on or after a button press,
+ * depending on the value of {@link BUTTON_BACKLIGHT_TIMEOUT}.
+ * Valid value range is between 0 and {@link PowerManager#getMaximumButtonBrightness()}
+ * @deprecated
+ * @hide
+ */
+ public static final String BUTTON_BRIGHTNESS = "button_brightness";
+
+ /**
+ * The time in ms to keep the button backlight on after pressing a button.
+ * A value of 0 will keep the buttons on for as long as the screen is on.
+ * @deprecated
+ * @hide
+ */
+ public static final String BUTTON_BACKLIGHT_TIMEOUT = "button_backlight_timeout";
+
+ /**
* Control whether the process CPU usage meter should be shown.
*
* @deprecated Use {@link Global#SHOW_PROCESSES} instead
@@ -2596,6 +2670,55 @@ public final class Settings {
private static final Validator NOTIFICATIONS_USE_RING_VOLUME_VALIDATOR = sBooleanValidator;
/**
+ * Whether the blacklisting feature for phone calls is enabled
+ * @hide
+ */
+ public static final String PHONE_BLACKLIST_ENABLED = "phone_blacklist_enabled";
+
+ /**
+ * Whether a notification should be shown when a call/message is blocked
+ * @hide
+ */
+ public static final String PHONE_BLACKLIST_NOTIFY_ENABLED = "phone_blacklist_notify_enabled";
+
+ /**
+ * Whether the blacklisting feature for phone calls from private numbers is enabled
+ * @hide
+ */
+ public static final String PHONE_BLACKLIST_PRIVATE_NUMBER_MODE = "phone_blacklist_private_number_enabled";
+
+ /**
+ * Whether the blacklisting feature for phone calls from unknown numbers is enabled
+ * @hide
+ */
+ public static final String PHONE_BLACKLIST_UNKNOWN_NUMBER_MODE = "phone_blacklist_unknown_number_enabled";
+
+ /**
+ * Constants to be used for {@link PHONE_BLACKLIST_PRIVATE_NUMBER_MODE} and
+ * {@link PHONE_BLACKLIST_UNKNOWN_NUMBER_MODE}.
+ * @hide
+ */
+ public static final int BLACKLIST_DO_NOT_BLOCK = 0;
+ /**
+ * @hide
+ */
+ public static final int BLACKLIST_BLOCK = 1;
+ /**
+ * @hide
+ */
+ public static final int BLACKLIST_PHONE_SHIFT = 0;
+ /**
+ * @hide
+ */
+ public static final int BLACKLIST_MESSAGE_SHIFT = 4;
+
+ /**
+ * Whether the regex blacklisting feature for phone calls is enabled
+ * @hide
+ */
+ public static final String PHONE_BLACKLIST_REGEX_ENABLED = "phone_blacklist_regex_enabled";
+
+ /**
* 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
@@ -2723,6 +2846,15 @@ public final class Settings {
private static final Validator TEXT_AUTO_CAPS_VALIDATOR = sBooleanValidator;
/**
+ * Setting to show if system is in power off alarm mode. 1 = true, 0 = false
+ * @hide
+ */
+ public static final String POWER_OFF_ALARM_MODE = "power_off_alarm_mode";
+
+ /** Validator for POWER_OFF_ALARM_MODE */
+ private static final Validator POWER_OFF_ALARM_MODE_VALIDATOR = sBooleanValidator;
+
+ /**
* Setting to enable Auto Punctuate in text editors. 1 = On, 0 = Off. This
* feature converts two spaces to a "." and space.
*/
@@ -2788,6 +2920,14 @@ public final class Settings {
new DiscreteValueValidator(new String[] {"12", "24"});
/**
+ * Developer options - Navigation Bar show switch
+ * @deprecated Moved to CMSettings.Secure.DEV_FORCE_SHOW_NAVBAR
+ * @hide
+ */
+ public static final String DEV_FORCE_SHOW_NAVBAR = "dev_force_show_navbar";
+
+
+ /**
* Date format string
* mm/dd/yyyy
* dd/mm/yyyy
@@ -2849,6 +2989,19 @@ public final class Settings {
public static final String ANIMATOR_DURATION_SCALE = Global.ANIMATOR_DURATION_SCALE;
/**
+ * 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";
+
+ /**
* Control whether the accelerometer will be used to change screen
* orientation. If 0, it will not be used unless explicitly requested
* by the application; if 1, it will be used by default unless explicitly
@@ -3183,6 +3336,63 @@ public final class Settings {
new InclusiveFloatRangeValidator(-7, 7);
/**
+ * Show icon when stylus is used?
+ * 0 = no
+ * 1 = yes
+ * @hide
+ */
+ public static final String STYLUS_ICON_ENABLED = "stylus_icon_enabled";
+
+ /**
+ * Enable Stylus Gestures
+ *
+ * @hide
+ */
+ public static final String ENABLE_STYLUS_GESTURES = "enable_stylus_gestures";
+
+ /**
+ * Left Swipe Action
+ *
+ * @hide
+ */
+ public static final String GESTURES_LEFT_SWIPE = "gestures_left_swipe";
+
+ /**
+ * Right Swipe Action
+ *
+ * @hide
+ */
+ public static final String GESTURES_RIGHT_SWIPE = "gestures_right_swipe";
+
+ /**
+ * Up Swipe Action
+ *
+ * @hide
+ */
+ public static final String GESTURES_UP_SWIPE = "gestures_up_swipe";
+
+ /**
+ * down Swipe Action
+ *
+ * @hide
+ */
+ public static final String GESTURES_DOWN_SWIPE = "gestures_down_swipe";
+
+ /**
+ * Long press Action
+ *
+ * @hide
+ */
+ public static final String GESTURES_LONG_PRESS = "gestures_long_press";
+
+ /**
+ * double tap Action
+ *
+ * @hide
+ */
+ public static final String GESTURES_DOUBLE_TAP = "gestures_double_tap";
+
+ /**
* Whether lock-to-app will be triggered by long-press on recents.
* @hide
*/
@@ -3219,6 +3429,37 @@ public final class Settings {
* the setting value. See an example above.
*/
+ /**
+ * Whether wifi settings will connect to access point automatically
+ * 0 = automatically
+ * 1 = manually
+ * @hide
+ */
+ public static final String WIFI_AUTO_CONNECT_TYPE = "wifi_auto_connect_type";
+
+ /**
+ * Volume keys control cursor in text fields (default is 0)
+ * 0 - Disabled
+ * 1 - Volume up/down moves cursor left/right
+ * 2 - Volume up/down moves cursor right/left
+ * @hide
+ */
+ public static final String VOLUME_KEY_CURSOR_CONTROL = "volume_key_cursor_control";
+
+ /**
+ * Whether to enable voice wakeup. The value is boolean (1 or 0).
+ * @hide
+ */
+ public static final String VOICE_WAKEUP = "voice_wakeup";
+
+ /**
+ * An intent (a flattened Uri String) to launch when user voice launch
+ * action is detected. An empty or null string will launch the default
+ * voice search activity.
+ * @hide
+ */
+ public static final String VOICE_LAUNCH_INTENT = "voice_launch_intent";
+
/**
* Settings to backup. This is here so that it's in the same place as the settings
* keys and easy to update.
@@ -3270,7 +3511,12 @@ public final class Settings {
VIBRATE_WHEN_RINGING,
RINGTONE,
LOCK_TO_APP_ENABLED,
- NOTIFICATION_SOUND
+ NOTIFICATION_SOUND,
+ PHONE_BLACKLIST_ENABLED,
+ PHONE_BLACKLIST_NOTIFY_ENABLED,
+ PHONE_BLACKLIST_PRIVATE_NUMBER_MODE,
+ PHONE_BLACKLIST_UNKNOWN_NUMBER_MODE,
+ PHONE_BLACKLIST_REGEX_ENABLED,
};
/**
@@ -3323,6 +3569,7 @@ public final class Settings {
PUBLIC_SETTINGS.add(SOUND_EFFECTS_ENABLED);
PUBLIC_SETTINGS.add(HAPTIC_FEEDBACK_ENABLED);
PUBLIC_SETTINGS.add(SHOW_WEB_SUGGESTIONS);
+ PUBLIC_SETTINGS.add(POWER_OFF_ALARM_MODE);
}
/**
@@ -3448,6 +3695,7 @@ public final class Settings {
VALIDATORS.put(WIFI_STATIC_NETMASK, WIFI_STATIC_NETMASK_VALIDATOR);
VALIDATORS.put(WIFI_STATIC_DNS1, WIFI_STATIC_DNS1_VALIDATOR);
VALIDATORS.put(WIFI_STATIC_DNS2, WIFI_STATIC_DNS2_VALIDATOR);
+ VALIDATORS.put(POWER_OFF_ALARM_MODE, POWER_OFF_ALARM_MODE_VALIDATOR);
}
/**
@@ -3872,6 +4120,44 @@ public final class Settings {
MOVED_TO_GLOBAL.add(Settings.Global.WEBVIEW_DATA_REDUCTION_PROXY_KEY);
}
+ /**
+ * Put a delimited list as a string
+ * @param resolver to access the database with
+ * @param name to store
+ * @param delimiter to split
+ * @param list to join and store
+ * @hide
+ */
+ public static void putListAsDelimitedString(ContentResolver resolver, String name,
+ String delimiter, List<String> list) {
+ String store = TextUtils.join(delimiter, list);
+ putString(resolver, name, store);
+ }
+
+ /**
+ * Get a delimited string returned as a list
+ * @param resolver to access the database with
+ * @param name to store
+ * @param delimiter to split the list with
+ * @return list of strings for a specific Settings.Secure item
+ * @hide
+ */
+ public static List<String> getDelimitedStringAsList(ContentResolver resolver, String name,
+ String delimiter) {
+ String baseString = getString(resolver, name);
+ List<String> list = new ArrayList<String>();
+ if (!TextUtils.isEmpty(baseString)) {
+ final String[] array = TextUtils.split(baseString, Pattern.quote(delimiter));
+ for (String item : array) {
+ if (TextUtils.isEmpty(item)) {
+ continue;
+ }
+ list.add(item);
+ }
+ }
+ return list;
+ }
+
/** @hide */
public static void getMovedToGlobalSettings(Set<String> outKeySet) {
outKeySet.addAll(MOVED_TO_GLOBAL);
@@ -4588,6 +4874,12 @@ public final class Settings {
public static final String PARENTAL_CONTROL_REDIRECT_URL = "parental_control_redirect_url";
/**
+ * Known good originating source sms addresses
+ * @hide
+ */
+ public static final String PROTECTED_SMS_ADDRESSES = "protected_sms_addresses";
+
+ /**
* Settings classname to launch when Settings is clicked from All
* Applications. Needed because of user testing between the old
* and new Settings apps.
@@ -5155,6 +5447,12 @@ public final class Settings {
"connectivity_release_pending_intent_delay_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},
@@ -5692,6 +5990,12 @@ public final class Settings {
public static final String ASSISTANT = "assistant";
/**
+ * Default theme to use. If empty, use system.
+ * @hide
+ */
+ public static final String DEFAULT_THEME_PACKAGE = "default_theme_package";
+
+ /**
* Whether the camera launch gesture should be disabled.
*
* @hide
@@ -5707,6 +6011,7 @@ public final class Settings {
public static final String CAMERA_DOUBLE_TAP_POWER_GESTURE_DISABLED =
"camera_double_tap_power_gesture_disabled";
+
/**
* This are the settings to be backed up.
*
@@ -5763,7 +6068,7 @@ public final class Settings {
MOUNT_UMS_NOTIFY_ENABLED,
SLEEP_TIMEOUT,
DOUBLE_TAP_TO_WAKE,
- CAMERA_GESTURE_DISABLED,
+ CAMERA_GESTURE_DISABLED
};
/**
@@ -6170,6 +6475,14 @@ public final class Settings {
public static final String ADB_ENABLED = "adb_enabled";
/**
+ * String to contain power menu actions
+ * @deprecated Use {@link CMSettings.Secure#POWER_MENU_ACTIONS} instead
+ * @hide
+ */
+ @Deprecated
+ public static final String POWER_MENU_ACTIONS = "power_menu_actions";
+
+ /**
* Whether Views are allowed to save their attribute data.
* @hide
*/
@@ -7227,6 +7540,9 @@ public final class Settings {
BLUETOOTH_A2DP_SINK_PRIORITY_PREFIX = "bluetooth_a2dp_sink_priority_";
/** {@hide} */
public static final String
+ BLUETOOTH_A2DP_SRC_PRIORITY_PREFIX = "bluetooth_a2dp_src_priority_";
+ /** {@hide} */
+ public static final String
BLUETOOTH_INPUT_DEVICE_PRIORITY_PREFIX = "bluetooth_input_device_priority_";
/** {@hide} */
public static final String
@@ -7327,6 +7643,14 @@ public final class Settings {
}
/**
+ * Get the key that retrieves a bluetooth a2dp src's priority.
+ * @hide
+ */
+ public static final String getBluetoothA2dpSrcPriorityKey(String address) {
+ return BLUETOOTH_A2DP_SRC_PRIORITY_PREFIX + address.toUpperCase(Locale.ROOT);
+ }
+
+ /**
* Get the key that retrieves a bluetooth Input Device's priority.
* @hide
*/
@@ -7557,13 +7881,22 @@ public final class Settings {
/**
* Defines global runtime overrides to window policy.
*
- * See {@link com.android.server.policy.PolicyControl} for value format.
+ * See {@link android.view.WindowManagerPolicyControl} for value format.
*
* @hide
*/
public static final String POLICY_CONTROL = "policy_control";
/**
+ * Defines global runtime overrides to window policy style.
+ *
+ * See {@link android.view.WindowManagerPolicyControl} for value definitions.
+ *
+ * @hide
+ */
+ public static final String POLICY_CONTROL_STYLE = "policy_control_style";
+
+ /**
* Defines global zen mode. ZEN_MODE_OFF, ZEN_MODE_IMPORTANT_INTERRUPTIONS,
* or ZEN_MODE_NO_INTERRUPTIONS.
*
@@ -7653,7 +7986,7 @@ public final class Settings {
public static final String REQUIRE_PASSWORD_TO_DECRYPT = "require_password_to_decrypt";
/**
- * Whether the Volte/VT is enabled
+ * Whether the Volte is enabled
* <p>
* Type: int (0 for false, 1 for true)
* @hide
@@ -7661,6 +7994,15 @@ public final class Settings {
public static final String ENHANCED_4G_MODE_ENABLED = "volte_vt_enabled";
/**
+ * Whether VT (Video Telephony over IMS) is enabled
+ * <p>
+ * Type: int (0 for false, 1 for true)
+ *
+ * @hide
+ */
+ public static final String VT_IMS_ENABLED = "vt_ims_enabled";
+
+ /**
* Whether WFC is enabled
* <p>
* Type: int (0 for false, 1 for true)
@@ -7743,6 +8085,7 @@ public final class Settings {
static {
MOVED_TO_SECURE = new HashSet<String>(1);
MOVED_TO_SECURE.add(Settings.Global.INSTALL_NON_MARKET_APPS);
+ MOVED_TO_SECURE.add(Settings.Global.POWER_MENU_ACTIONS);
}
/** @hide */
@@ -7751,6 +8094,44 @@ public final class Settings {
}
/**
+ * Put a delimited list as a string
+ * @param resolver to access the database with
+ * @param name to store
+ * @param delimiter to split
+ * @param list to join and store
+ * @hide
+ */
+ public static void putListAsDelimitedString(ContentResolver resolver, String name,
+ String delimiter, List<String> list) {
+ String store = TextUtils.join(delimiter, list);
+ putString(resolver, name, store);
+ }
+
+ /**
+ * Get a delimited string returned as a list
+ * @param resolver to access the database with
+ * @param name to store
+ * @param delimiter to split the list with
+ * @return list of strings for a specific Settings.Secure item
+ * @hide
+ */
+ public static List<String> getDelimitedStringAsList(ContentResolver resolver, String name,
+ String delimiter) {
+ String baseString = getString(resolver, name);
+ List<String> list = new ArrayList<String>();
+ if (!TextUtils.isEmpty(baseString)) {
+ final String[] array = TextUtils.split(baseString, Pattern.quote(delimiter));
+ for (String item : array) {
+ if (TextUtils.isEmpty(item)) {
+ continue;
+ }
+ list.add(item);
+ }
+ }
+ return list;
+ }
+
+ /**
* Look up a name in the database.
* @param resolver to access the database with
* @param name to look up in the table
@@ -7806,6 +8187,12 @@ public final class Settings {
* @return the corresponding content URI, or null if not present
*/
public static Uri getUriFor(String name) {
+ if (MOVED_TO_SECURE.contains(name)) {
+ Log.w(TAG, "Setting " + name + " has moved from android.provider.Settings.Global"
+ + " to android.provider.Settings.Secure, returning Secure URI.");
+ return Secure.getUriFor(Secure.CONTENT_URI, name);
+ }
+
return getUriFor(CONTENT_URI, name);
}
diff --git a/core/java/android/provider/ThemesContract.java b/core/java/android/provider/ThemesContract.java
new file mode 100644
index 0000000..af7ab26
--- /dev/null
+++ b/core/java/android/provider/ThemesContract.java
@@ -0,0 +1,731 @@
+package android.provider;
+
+import android.net.Uri;
+
+/**
+ * @hide
+ */
+public class ThemesContract {
+ public static final String AUTHORITY = "com.cyanogenmod.themes";
+ public static final Uri AUTHORITY_URI = Uri.parse("content://" + AUTHORITY);
+
+ public static class ThemesColumns {
+ public static final Uri CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI, "themes");
+
+ /**
+ * The unique ID for a row.
+ * <P>Type: INTEGER (long)</P>
+ */
+ public static final String _ID = "_id";
+
+ /**
+ * The user visible title.
+ * <P>Type: TEXT</P>
+ */
+ public static final String TITLE = "title";
+
+ /**
+ * Unique text to identify the apk pkg. ie "com.foo.bar"
+ * <P>Type: TEXT</P>
+ */
+ public static final String PKG_NAME = "pkg_name";
+
+ /**
+ * A 32 bit RRGGBB color representative of the themes color scheme
+ * <P>Type: INTEGER</P>
+ */
+ public static final String PRIMARY_COLOR = "primary_color";
+
+ /**
+ * A 2nd 32 bit RRGGBB color representative of the themes color scheme
+ * <P>Type: INTEGER</P>
+ */
+ public static final String SECONDARY_COLOR = "secondary_color";
+
+ /**
+ * Name of the author of the theme
+ * <P>Type: TEXT</P>
+ */
+ public static final String AUTHOR = "author";
+
+ /**
+ * The time that this row was created on its originating client (msecs
+ * since the epoch).
+ * <P>Type: INTEGER</P>
+ */
+ public static final String DATE_CREATED = "created";
+
+ /**
+ * URI to an image that shows the homescreen with the theme applied
+ * since the epoch).
+ * <P>Type: TEXT</P>
+ */
+ public static final String HOMESCREEN_URI = "homescreen_uri";
+
+ /**
+ * URI to an image that shows the lockscreen with theme applied
+ * <P>Type: TEXT</P>
+ */
+ public static final String LOCKSCREEN_URI = "lockscreen_uri";
+
+ /**
+ * URI to an image that shows the style (aka skin) with theme applied
+ * <P>Type: TEXT</P>
+ */
+ public static final String STYLE_URI = "style_uri";
+
+ /**
+ * TODO: Figure structure for actual animation instead of static
+ * URI to an image of the boot_anim.
+ * <P>Type: TEXT</P>
+ */
+ public static final String BOOT_ANIM_URI = "bootanim_uri";
+
+ /**
+ * URI to an image of the status bar for this theme.
+ * <P>Type: TEXT</P>
+ */
+ public static final String STATUSBAR_URI = "status_uri";
+
+ /**
+ * URI to an image of the fonts in this theme.
+ * <P>Type: TEXT</P>
+ */
+ public static final String FONT_URI = "font_uri";
+
+ /**
+ * URI to an image of the fonts in this theme.
+ * <P>Type: TEXT</P>
+ */
+ public static final String ICON_URI = "icon_uri";
+
+ /**
+ * URI to an image of the fonts in this theme.
+ * <P>Type: TEXT</P>
+ */
+ public static final String OVERLAYS_URI = "overlays_uri";
+
+ /**
+ * 1 if theme modifies the launcher/homescreen else 0
+ * <P>Type: INTEGER</P>
+ * <P>Default: 0</P>
+ */
+ public static final String MODIFIES_LAUNCHER = "mods_homescreen";
+
+ /**
+ * 1 if theme modifies the lockscreen else 0
+ * <P>Type: INTEGER</P>
+ * <P>Default: 0</P>
+ */
+ public static final String MODIFIES_LOCKSCREEN = "mods_lockscreen";
+
+ /**
+ * 1 if theme modifies icons else 0
+ * <P>Type: INTEGER</P>
+ * <P>Default: 0</P>
+ */
+ public static final String MODIFIES_ICONS = "mods_icons";
+
+ /**
+ * 1 if theme modifies fonts
+ * <P>Type: INTEGER</P>
+ * <P>Default: 0</P>
+ */
+ public static final String MODIFIES_FONTS = "mods_fonts";
+
+ /**
+ * 1 if theme modifies boot animation
+ * <P>Type: INTEGER</P>
+ * <P>Default: 0</P>
+ */
+ public static final String MODIFIES_BOOT_ANIM = "mods_bootanim";
+
+ /**
+ * 1 if theme modifies notifications
+ * <P>Type: INTEGER</P>
+ * <P>Default: 0</P>
+ */
+ public static final String MODIFIES_NOTIFICATIONS = "mods_notifications";
+
+ /**
+ * 1 if theme modifies alarm sounds
+ * <P>Type: INTEGER</P>
+ * <P>Default: 0</P>
+ */
+ public static final String MODIFIES_ALARMS = "mods_alarms";
+
+ /**
+ * 1 if theme modifies ringtones
+ * <P>Type: INTEGER</P>
+ * <P>Default: 0</P>
+ */
+ public static final String MODIFIES_RINGTONES = "mods_ringtones";
+
+ /**
+ * 1 if theme has overlays
+ * <P>Type: INTEGER</P>
+ * <P>Default: 0</P>
+ */
+ public static final String MODIFIES_OVERLAYS = "mods_overlays";
+
+ /**
+ * 1 if theme has an overlay for SystemUI/StatusBar
+ * <P>Type: INTEGER</P>
+ * <P>Default: 0</P>
+ */
+ public static final String MODIFIES_STATUS_BAR = "mods_status_bar";
+
+ /**
+ * 1 if theme has an overlay for SystemUI/NavBar
+ * <P>Type: INTEGER</P>
+ * <P>Default: 0</P>
+ */
+ public static final String MODIFIES_NAVIGATION_BAR = "mods_navigation_bar";
+
+ /**
+ * 1 if theme has a live lock screen
+ * <P>Type: INTEGER</P>
+ * <P>Default: 0</P>
+ */
+ public static final String MODIFIES_LIVE_LOCK_SCREEN = "mods_live_lock_screen";
+
+ /**
+ * URI to the theme's wallpaper. We should support multiple wallpaper
+ * but for now we will just have 1.
+ * <P>Type: TEXT</P>
+ */
+ public static final String WALLPAPER_URI = "wallpaper_uri";
+
+ /**
+ * 1 if this row should actually be presented as a theme to the user.
+ * For example if a "theme" only modifies one component (ex icons) then
+ * we do not present it to the user under the themes table.
+ * <P>Type: INTEGER</P>
+ * <P>Default: 0</P>
+ */
+ public static final String PRESENT_AS_THEME = "present_as_theme";
+
+ /**
+ * 1 if this theme is a legacy theme.
+ * <P>Type: INTEGER</P>
+ * <P>Default: 0</P>
+ */
+ public static final String IS_LEGACY_THEME = "is_legacy_theme";
+
+ /**
+ * 1 if this theme is the system default theme.
+ * <P>Type: INTEGER</P>
+ * <P>Default: 0</P>
+ */
+ public static final String IS_DEFAULT_THEME = "is_default_theme";
+
+ /**
+ * 1 if this theme is a legacy iconpack. A legacy icon pack is an APK that was written
+ * for Trebuchet or a 3rd party launcher.
+ * <P>Type: INTEGER</P>
+ * <P>Default: 0</P>
+ */
+ public static final String IS_LEGACY_ICONPACK = "is_legacy_iconpack";
+
+ /**
+ * install/update time in millisecs. When the row is inserted this column
+ * is populated by the PackageInfo. It is used for syncing to PM
+ * <P>Type: INTEGER</P>
+ * <P>Default: 0</P>
+ */
+ public static final String LAST_UPDATE_TIME = "updateTime";
+
+ /**
+ * install time in millisecs. When the row is inserted this column
+ * is populated by the PackageInfo.
+ * <P>Type: INTEGER</P>
+ * <P>Default: 0</P>
+ */
+ public static final String INSTALL_TIME = "install_time";
+
+ /**
+ * The target API this theme supports
+ * is populated by the PackageInfo.
+ * <P>Type: INTEGER</P>
+ * <P>Default: 0</P>
+ */
+ public static final String TARGET_API = "target_api";
+
+ /**
+ * The install state of the theme.
+ * Can be one of the following:
+ * {@link InstallState#UNKNOWN}
+ * {@link InstallState#INSTALLING}
+ * {@link InstallState#UPDATING}
+ * {@link InstallState#INSTALLED}
+ * <P>Type: INTEGER</P>
+ * <P>Default: 0</P>
+ */
+ public static final String INSTALL_STATE = "install_state";
+
+ public static class InstallState {
+ public static final int UNKNOWN = 0;
+ public static final int INSTALLING = 1;
+ public static final int UPDATING = 2;
+ public static final int INSTALLED = 3;
+ }
+ }
+
+ /**
+ * Key-value table which assigns a component (ex wallpaper) to a theme's package
+ */
+ public static class MixnMatchColumns {
+ public static final Uri CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI, "mixnmatch");
+
+ /**
+ * The unique key for a row. See the KEY_* constants
+ * for valid examples
+ * <P>Type: TEXT</P>
+ */
+ public static final String COL_KEY = "key";
+
+ /**
+ * The package name that corresponds to a given component.
+ * <P>Type: String</P>
+ */
+ public static final String COL_VALUE = "value";
+
+ /**
+ * The package name that corresponds to where this component was applied from previously
+ * <P>Type: String</P>
+ */
+ public static final String COL_PREV_VALUE = "previous_value";
+
+ /**
+ * Time when this entry was last updated
+ * <P>Type: INTEGER</P>
+ */
+ public static final String COL_UPDATE_TIME = "update_time";
+
+ /*
+ * The unique ID for the component within a theme.
+ * Always 0 unless multiples of a component exist.
+ * <P>Type: INTEGER (long)</P>
+ */
+ public static final String COL_COMPONENT_ID = "component_id";
+
+ /**
+ * Valid keys
+ */
+ public static final String KEY_HOMESCREEN = "mixnmatch_homescreen";
+ public static final String KEY_LOCKSCREEN = "mixnmatch_lockscreen";
+ public static final String KEY_ICONS = "mixnmatch_icons";
+ public static final String KEY_STATUS_BAR = "mixnmatch_status_bar";
+ public static final String KEY_BOOT_ANIM = "mixnmatch_boot_anim";
+ public static final String KEY_FONT = "mixnmatch_font";
+ public static final String KEY_ALARM = "mixnmatch_alarm";
+ public static final String KEY_NOTIFICATIONS = "mixnmatch_notifications";
+ public static final String KEY_RINGTONE = "mixnmatch_ringtone";
+ public static final String KEY_OVERLAYS = "mixnmatch_overlays";
+ public static final String KEY_NAVIGATION_BAR = "mixnmatch_navigation_bar";
+ public static final String KEY_LIVE_LOCK_SCREEN = "mixnmatch_live_lock_screen";
+
+ public static final String[] ROWS = { KEY_HOMESCREEN,
+ KEY_LOCKSCREEN,
+ KEY_ICONS,
+ KEY_STATUS_BAR,
+ KEY_BOOT_ANIM,
+ KEY_FONT,
+ KEY_NOTIFICATIONS,
+ KEY_RINGTONE,
+ KEY_ALARM,
+ KEY_OVERLAYS,
+ KEY_NAVIGATION_BAR,
+ KEY_LIVE_LOCK_SCREEN
+ };
+
+ /**
+ * For a given key value in the MixNMatch table, return the column
+ * associated with it in the Themes Table. This is useful for URI based
+ * elements like wallpaper where the caller wishes to determine the
+ * wallpaper URI.
+ */
+ public static String componentToImageColName(String component) {
+ if (component.equals(MixnMatchColumns.KEY_HOMESCREEN)) {
+ return ThemesColumns.HOMESCREEN_URI;
+ } else if (component.equals(MixnMatchColumns.KEY_LOCKSCREEN)) {
+ return ThemesColumns.LOCKSCREEN_URI;
+ } else if (component.equals(MixnMatchColumns.KEY_BOOT_ANIM)) {
+ return ThemesColumns.BOOT_ANIM_URI;
+ } else if (component.equals(MixnMatchColumns.KEY_FONT)) {
+ return ThemesColumns.FONT_URI;
+ } else if (component.equals(MixnMatchColumns.KEY_ICONS)) {
+ return ThemesColumns.ICON_URI;
+ } else if (component.equals(MixnMatchColumns.KEY_STATUS_BAR)) {
+ return ThemesColumns.STATUSBAR_URI;
+ } else if (component.equals(MixnMatchColumns.KEY_NOTIFICATIONS)) {
+ throw new IllegalArgumentException("Notifications mixnmatch component does not have a related column");
+ } else if (component.equals(MixnMatchColumns.KEY_RINGTONE)) {
+ throw new IllegalArgumentException("Ringtone mixnmatch component does not have a related column");
+ } else if (component.equals(MixnMatchColumns.KEY_OVERLAYS)) {
+ return ThemesColumns.OVERLAYS_URI;
+ } else if (component.equals(MixnMatchColumns.KEY_STATUS_BAR)) {
+ throw new IllegalArgumentException(
+ "Status bar mixnmatch component does not have a related column");
+ } else if (component.equals(MixnMatchColumns.KEY_NAVIGATION_BAR)) {
+ throw new IllegalArgumentException(
+ "Navigation bar mixnmatch component does not have a related column");
+ } else if (component.equals(MixnMatchColumns.KEY_LIVE_LOCK_SCREEN)) {
+ throw new IllegalArgumentException(
+ "Live lock screen mixnmatch component does not have a related column");
+ }
+ return null;
+ }
+
+ /**
+ * A component in the themes table (IE "mods_wallpaper") has an
+ * equivalent key in mixnmatch table
+ */
+ public static String componentToMixNMatchKey(String component) {
+ if (component.equals(ThemesColumns.MODIFIES_LAUNCHER)) {
+ return MixnMatchColumns.KEY_HOMESCREEN;
+ } else if (component.equals(ThemesColumns.MODIFIES_ICONS)) {
+ return MixnMatchColumns.KEY_ICONS;
+ } else if (component.equals(ThemesColumns.MODIFIES_LOCKSCREEN)) {
+ return MixnMatchColumns.KEY_LOCKSCREEN;
+ } else if (component.equals(ThemesColumns.MODIFIES_FONTS)) {
+ return MixnMatchColumns.KEY_FONT;
+ } else if (component.equals(ThemesColumns.MODIFIES_BOOT_ANIM)) {
+ return MixnMatchColumns.KEY_BOOT_ANIM;
+ } else if (component.equals(ThemesColumns.MODIFIES_ALARMS)) {
+ return MixnMatchColumns.KEY_ALARM;
+ } else if (component.equals(ThemesColumns.MODIFIES_NOTIFICATIONS)) {
+ return MixnMatchColumns.KEY_NOTIFICATIONS;
+ } else if (component.equals(ThemesColumns.MODIFIES_RINGTONES)) {
+ return MixnMatchColumns.KEY_RINGTONE;
+ } else if (component.equals(ThemesColumns.MODIFIES_OVERLAYS)) {
+ return MixnMatchColumns.KEY_OVERLAYS;
+ } else if (component.equals(ThemesColumns.MODIFIES_STATUS_BAR)) {
+ return MixnMatchColumns.KEY_STATUS_BAR;
+ } else if (component.equals(ThemesColumns.MODIFIES_NAVIGATION_BAR)) {
+ return MixnMatchColumns.KEY_NAVIGATION_BAR;
+ } else if (component.equals(ThemesColumns.MODIFIES_LIVE_LOCK_SCREEN)) {
+ return MixnMatchColumns.KEY_LIVE_LOCK_SCREEN;
+ }
+ return null;
+ }
+
+ /**
+ * A mixnmatch key in has an
+ * equivalent value in the themes table
+ */
+ public static String mixNMatchKeyToComponent(String mixnmatchKey) {
+ if (mixnmatchKey.equals(MixnMatchColumns.KEY_HOMESCREEN)) {
+ return ThemesColumns.MODIFIES_LAUNCHER;
+ } else if (mixnmatchKey.equals(MixnMatchColumns.KEY_ICONS)) {
+ return ThemesColumns.MODIFIES_ICONS;
+ } else if (mixnmatchKey.equals(MixnMatchColumns.KEY_LOCKSCREEN)) {
+ return ThemesColumns.MODIFIES_LOCKSCREEN;
+ } else if (mixnmatchKey.equals(MixnMatchColumns.KEY_FONT)) {
+ return ThemesColumns.MODIFIES_FONTS;
+ } else if (mixnmatchKey.equals(MixnMatchColumns.KEY_BOOT_ANIM)) {
+ return ThemesColumns.MODIFIES_BOOT_ANIM;
+ } else if (mixnmatchKey.equals(MixnMatchColumns.KEY_ALARM)) {
+ return ThemesColumns.MODIFIES_ALARMS;
+ } else if (mixnmatchKey.equals(MixnMatchColumns.KEY_NOTIFICATIONS)) {
+ return ThemesColumns.MODIFIES_NOTIFICATIONS;
+ } else if (mixnmatchKey.equals(MixnMatchColumns.KEY_RINGTONE)) {
+ return ThemesColumns.MODIFIES_RINGTONES;
+ } else if (mixnmatchKey.equals(MixnMatchColumns.KEY_OVERLAYS)) {
+ return ThemesColumns.MODIFIES_OVERLAYS;
+ } else if (mixnmatchKey.equals(MixnMatchColumns.KEY_STATUS_BAR)) {
+ return ThemesColumns.MODIFIES_STATUS_BAR;
+ } else if (mixnmatchKey.equals(MixnMatchColumns.KEY_NAVIGATION_BAR)) {
+ return ThemesColumns.MODIFIES_NAVIGATION_BAR;
+ } else if (mixnmatchKey.equals(MixnMatchColumns.KEY_LIVE_LOCK_SCREEN)) {
+ return ThemesColumns.MODIFIES_LIVE_LOCK_SCREEN;
+ }
+ return null;
+ }
+ }
+
+ /**
+ * Table containing cached preview files for a given theme
+ */
+ public static class PreviewColumns {
+ /**
+ * Uri for retrieving the previews table.
+ * Querying the themes provider using this URI will return a cursor with a key and value
+ * columns, and a row for each component.
+ */
+ public static final Uri CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI, "previews");
+
+ /**
+ * Uri for retrieving the previews for the currently applied components.
+ * Querying the themes provider using this URI will return a cursor with a single row
+ * containing all the previews for the components that are currently applied.
+ */
+ public static final Uri APPLIED_URI = Uri.withAppendedPath(AUTHORITY_URI,
+ "applied_previews");
+
+ /**
+ * Uri for retrieving the default previews for the theme.
+ * Querying the themes provider using this URI will return a cursor with a single row
+ * containing all the previews for the default components of the current theme.
+ */
+ public static final Uri COMPONENTS_URI = Uri.withAppendedPath(AUTHORITY_URI,
+ "components_previews");
+
+ /**
+ * The unique ID for a row.
+ * <P>Type: INTEGER (long)</P>
+ */
+ public static final String _ID = "_id";
+
+ /**
+ * The unique ID for the theme these previews belong to.
+ * <P>Type: INTEGER (long)</P>
+ */
+ public static final String THEME_ID = "theme_id";
+
+ /**
+ * The unique ID for the component within a theme.
+ * <P>Type: INTEGER (long)</P>
+ */
+ public static final String COMPONENT_ID = "component_id";
+
+ /**
+ * The unique key for a row. See the Valid key constants section below
+ * for valid examples
+ * <P>Type: TEXT</P>
+ */
+ public static final String COL_KEY = "key";
+
+ /**
+ * The package name that corresponds to a given component.
+ * <P>Type: String</P>
+ */
+ public static final String COL_VALUE = "value";
+
+ /**
+ * Valid keys
+ */
+
+ /**
+ * Cached image of the themed status bar background.
+ * <P>Type: String (file path)</P>
+ */
+ public static final String STATUSBAR_BACKGROUND = "statusbar_background";
+
+ /**
+ * Cached image of the themed bluetooth status icon.
+ * <P>Type: String (file path)</P>
+ */
+ public static final String STATUSBAR_BLUETOOTH_ICON = "statusbar_bluetooth_icon";
+
+ /**
+ * Cached image of the themed wifi status icon.
+ * <P>Type: String (file path)</P>
+ */
+ public static final String STATUSBAR_WIFI_ICON = "statusbar_wifi_icon";
+
+ /**
+ * Cached image of the themed cellular signal status icon.
+ * <P>Type: String (file path)</P>
+ */
+ public static final String STATUSBAR_SIGNAL_ICON = "statusbar_signal_icon";
+
+ /**
+ * Cached image of the themed battery using portrait style.
+ * <P>Type: String (file path)</P>
+ */
+ public static final String STATUSBAR_BATTERY_PORTRAIT = "statusbar_battery_portrait";
+
+ /**
+ * Cached image of the themed battery using landscape style.
+ * <P>Type: String (file path)</P>
+ */
+ public static final String STATUSBAR_BATTERY_LANDSCAPE = "statusbar_battery_landscape";
+
+ /**
+ * Cached image of the themed battery using circle style.
+ * <P>Type: String (file path)</P>
+ */
+ public static final String STATUSBAR_BATTERY_CIRCLE = "statusbar_battery_circle";
+
+ /**
+ * The themed color used for clock text in the status bar.
+ * <P>Type: INTEGER (int)</P>
+ */
+ public static final String STATUSBAR_CLOCK_TEXT_COLOR = "statusbar_clock_text_color";
+
+ /**
+ * The themed margin value between the wifi and rssi signal icons.
+ * <P>Type: INTEGER (int)</P>
+ */
+ public static final String STATUSBAR_WIFI_COMBO_MARGIN_END = "wifi_combo_margin_end";
+
+ /**
+ * Cached image of the themed navigation bar background.
+ * <P>Type: String (file path)</P>
+ */
+ public static final String NAVBAR_BACKGROUND = "navbar_background";
+
+ /**
+ * Cached image of the themed back button.
+ * <P>Type: String (file path)</P>
+ */
+ public static final String NAVBAR_BACK_BUTTON = "navbar_back_button";
+
+ /**
+ * Cached image of the themed home button.
+ * <P>Type: String (file path)</P>
+ */
+ public static final String NAVBAR_HOME_BUTTON = "navbar_home_button";
+
+ /**
+ * Cached image of the themed recents button.
+ * <P>Type: String (file path)</P>
+ */
+ public static final String NAVBAR_RECENT_BUTTON = "navbar_recent_button";
+
+ /**
+ * Cached image of the 1/3 icons
+ * <P>Type: String (file path)</P>
+ */
+ public static final String ICON_PREVIEW_1 = "icon_preview_1";
+
+ /**
+ * Cached image of the 2/3 icons
+ * <P>Type: String (file path)</P>
+ */
+ public static final String ICON_PREVIEW_2 = "icon_preview_2";
+
+ /**
+ * Cached image of the 3/3 icons
+ * <P>Type: String (file path)</P>
+ */
+ public static final String ICON_PREVIEW_3 = "icon_preview_3";
+
+ /**
+ * Full path to the theme's wallpaper asset.
+ * <P>Type: String (file path)</P>
+ */
+ public static final String WALLPAPER_FULL = "wallpaper_full";
+
+ /**
+ * Cached preview of the theme's wallpaper which is larger than the thumbnail
+ * but smaller than the full sized wallpaper.
+ * <P>Type: String (file path)</P>
+ */
+ public static final String WALLPAPER_PREVIEW = "wallpaper_preview";
+
+ /**
+ * Cached thumbnail of the theme's wallpaper
+ * <P>Type: String (file path)</P>
+ */
+ public static final String WALLPAPER_THUMBNAIL = "wallpaper_thumbnail";
+
+ /**
+ * Cached preview of the theme's lockscreen wallpaper which is larger than the thumbnail
+ * but smaller than the full sized lockscreen wallpaper.
+ * <P>Type: String (file path)</P>
+ */
+ public static final String LOCK_WALLPAPER_PREVIEW = "lock_wallpaper_preview";
+
+ /**
+ * Cached thumbnail of the theme's lockscreen wallpaper
+ * <P>Type: String (file path)</P>
+ */
+ public static final String LOCK_WALLPAPER_THUMBNAIL = "lock_wallpaper_thumbnail";
+
+ /**
+ * Cached preview of UI controls representing the theme's style
+ * <P>Type: String (file path)</P>
+ */
+ public static final String STYLE_PREVIEW = "style_preview";
+
+ /**
+ * Cached thumbnail preview of UI controls representing the theme's style
+ * <P>Type: String (file path)</P>
+ */
+ public static final String STYLE_THUMBNAIL = "style_thumbnail";
+
+ /**
+ * Cached thumbnail of the theme's boot animation
+ * <P>Type: String (file path)</P>
+ */
+ public static final String BOOTANIMATION_THUMBNAIL = "bootanimation_thumbnail";
+
+ /**
+ * Cached preview of live lock screen
+ * <P>Type: String (file path)</P>
+ */
+ public static final String LIVE_LOCK_SCREEN_PREVIEW = "live_lock_screen_preview";
+
+ /**
+ * Cached thumbnail preview of live lock screen
+ * <P>Type: String (file path)</P>
+ */
+ public static final String LIVE_LOCK_SCREEN_THUMBNAIL = "live_lock_screen_thumbnail";
+
+ public static final String[] VALID_KEYS = {
+ STATUSBAR_BACKGROUND,
+ STATUSBAR_BLUETOOTH_ICON,
+ STATUSBAR_WIFI_ICON,
+ STATUSBAR_SIGNAL_ICON,
+ STATUSBAR_BATTERY_PORTRAIT,
+ STATUSBAR_BATTERY_LANDSCAPE,
+ STATUSBAR_BATTERY_CIRCLE,
+ STATUSBAR_CLOCK_TEXT_COLOR,
+ STATUSBAR_WIFI_COMBO_MARGIN_END,
+ NAVBAR_BACKGROUND,
+ NAVBAR_BACK_BUTTON,
+ NAVBAR_HOME_BUTTON,
+ NAVBAR_RECENT_BUTTON,
+ ICON_PREVIEW_1,
+ ICON_PREVIEW_2,
+ ICON_PREVIEW_3,
+ WALLPAPER_FULL,
+ WALLPAPER_PREVIEW,
+ WALLPAPER_THUMBNAIL,
+ LOCK_WALLPAPER_PREVIEW,
+ LOCK_WALLPAPER_THUMBNAIL,
+ STYLE_PREVIEW,
+ STYLE_THUMBNAIL,
+ BOOTANIMATION_THUMBNAIL,
+ LIVE_LOCK_SCREEN_PREVIEW,
+ LIVE_LOCK_SCREEN_THUMBNAIL,
+ };
+ }
+
+ public static class Intent {
+ /**
+ * Action sent from the provider when a theme has been fully installed. Fully installed
+ * means that the apk was installed by PackageManager and the theme resources were
+ * processed and cached by {@link com.android.server.ThemeService}
+ * Requires the {@link android.Manifest.permission#READ_THEMES} permission to receive
+ * this broadcast.
+ */
+ public static final String ACTION_THEME_INSTALLED =
+ "themescontract.intent.action.THEME_INSTALLED";
+
+ /**
+ * Action sent from the provider when a theme has been updated.
+ * Requires the {@link android.Manifest.permission#READ_THEMES} permission to receive
+ * this broadcast.
+ */
+ public static final String ACTION_THEME_UPDATED =
+ "themescontract.intent.action.THEME_UPDATED";
+
+ /**
+ * Action sent from the provider when a theme has been removed.
+ * Requires the {@link android.Manifest.permission#READ_THEMES} permission to receive
+ * this broadcast.
+ */
+ public static final String ACTION_THEME_REMOVED =
+ "themescontract.intent.action.THEME_REMOVED";
+
+ /**
+ * Uri scheme used to broadcast the theme's package name when broadcasting
+ * {@link android.provider.ThemesContract.Intent#ACTION_THEME_INSTALLED} or
+ * {@link android.provider.ThemesContract.Intent#ACTION_THEME_REMOVED}
+ */
+ public static final String URI_SCHEME_PACKAGE = "package";
+ }
+}
diff --git a/core/java/android/service/dreams/DreamManagerInternal.java b/core/java/android/service/dreams/DreamManagerInternal.java
index ff7cef9..c750b5e 100644
--- a/core/java/android/service/dreams/DreamManagerInternal.java
+++ b/core/java/android/service/dreams/DreamManagerInternal.java
@@ -42,4 +42,9 @@ public abstract class DreamManagerInternal {
* Called by the power manager to determine whether a dream is running.
*/
public abstract boolean isDreaming();
+
+ /**
+ * Called by the power manager to determine whether the dream has gone to doze mode.
+ */
+ public abstract boolean isDozing();
}
diff --git a/core/java/android/service/dreams/IDreamManager.aidl b/core/java/android/service/dreams/IDreamManager.aidl
index be3f3b3..78dda0c 100644
--- a/core/java/android/service/dreams/IDreamManager.aidl
+++ b/core/java/android/service/dreams/IDreamManager.aidl
@@ -30,7 +30,10 @@ interface IDreamManager {
ComponentName getDefaultDreamComponent();
void testDream(in ComponentName componentName);
boolean isDreaming();
+ boolean isDozing();
void finishSelf(in IBinder token, boolean immediate);
void startDozing(in IBinder token, int screenState, int screenBrightness);
void stopDozing(in IBinder token);
+ void setLidState(int state);
+ int getLidState();
}
diff --git a/core/java/android/service/gesture/EdgeGestureManager.java b/core/java/android/service/gesture/EdgeGestureManager.java
new file mode 100644
index 0000000..7c0ab2e
--- /dev/null
+++ b/core/java/android/service/gesture/EdgeGestureManager.java
@@ -0,0 +1,205 @@
+/*
+ * Copyright (C) 2013 The CyanogenMod Project (Jens Doll)
+ *
+ * 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.service.gesture;
+
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.service.gesture.IEdgeGestureActivationListener;
+import android.service.gesture.IEdgeGestureHostCallback;
+import android.service.gesture.IEdgeGestureService;
+import android.util.Slog;
+
+import com.android.internal.util.gesture.EdgeGesturePosition;
+
+/**
+ * This is a simple Manager class for edge gesture service on the application side. The application need
+ * {@code INJECT_EVENTS} permission to register {@code EdgeGestureActivationListener}s.<br>
+ * See {@link android.service.gesture.IEdgeGestureService} for more information.
+ *
+ * @see android.service.gesture.IEdgeGestureService
+ * @hide
+ */
+public class EdgeGestureManager {
+ public static final String TAG = "EdgeGestureManager";
+ public static final boolean DEBUG = false;
+
+ private static EdgeGestureManager sInstance;
+
+ private final IEdgeGestureService mPs;
+
+ public static abstract class EdgeGestureActivationListener {
+ private Handler mHandler;
+ private IEdgeGestureHostCallback mCallback;
+
+ private class Delegator extends IEdgeGestureActivationListener.Stub {
+ public void onEdgeGestureActivation(final int touchX, final int touchY, final int positionIndex, final int flags)
+ throws RemoteException {
+ mHandler.post(new Runnable() {
+ public void run() {
+ EdgeGestureActivationListener.this.onEdgeGestureActivation(touchX, touchY, EdgeGesturePosition.values()[positionIndex], flags);
+ }
+ });
+ }
+ }
+ private Delegator mDelegator;
+
+ public EdgeGestureActivationListener() {
+ this(Looper.getMainLooper());
+ }
+
+ public EdgeGestureActivationListener(Looper looper) {
+ mHandler = new Handler(looper);
+ mDelegator = new Delegator();
+ }
+
+ /* package */ void setHostCallback(IEdgeGestureHostCallback hostCallback) {
+ mCallback = hostCallback;
+ }
+
+ /**
+ * Override this to receive activations from the edge gesture service.
+ *
+ * @param touchX the last X position a touch event was registered.
+ * @param touchY the last Y position a touch event was registered.
+ * @param position the position of the activation.
+ * @param flags currently 0.
+ * @see IEdgeGestureActivationListener#onEdgeGestureActivation(int, int, int, int)
+ */
+ public abstract void onEdgeGestureActivation(int touchX, int touchY, EdgeGesturePosition position, int flags);
+
+ /**
+ * After being activated, this allows the edge gesture control to steal focus from the current
+ * window.
+ *
+ * @see IEdgeGestureHostCallback#gainTouchFocus(IBinder)
+ */
+ public boolean gainTouchFocus(IBinder applicationWindowToken) {
+ try {
+ return mCallback.gainTouchFocus(applicationWindowToken);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "gainTouchFocus failed: " + e.getMessage());
+ /* fall through */
+ }
+ return false;
+ }
+
+ public boolean dropEventsUntilLift() {
+ try {
+ return mCallback.dropEventsUntilLift();
+ } catch (RemoteException e) {
+ Slog.w(TAG, "dropNextEvents failed: " + e.getMessage());
+ /* fall through */
+ }
+ return false;
+ }
+
+ /**
+ * Turns listening for edge gesture activation gestures on again, after it was disabled during
+ * the call to the listener.
+ *
+ * @see IEdgeGestureHostCallback#restoreListenerState()
+ */
+ public void restoreListenerState() {
+ if (DEBUG) {
+ Slog.d(TAG, "restore listener state: " + Thread.currentThread().getName());
+ }
+ try {
+ mCallback.restoreListenerState();
+ } catch (RemoteException e) {
+ Slog.w(TAG, "restoreListenerState failed: " + e.getMessage());
+ /* fall through */
+ }
+ }
+ }
+
+ private EdgeGestureManager(IEdgeGestureService ps) {
+ mPs = ps;
+ }
+
+ /**
+ * Gets an instance of the edge gesture manager.
+ *
+ * @return The edge gesture manager instance.
+ * @hide
+ */
+ public static EdgeGestureManager getInstance() {
+ synchronized (EdgeGestureManager.class) {
+ if (sInstance == null) {
+ IBinder b = ServiceManager.getService("edgegestureservice");
+ sInstance = new EdgeGestureManager(IEdgeGestureService.Stub.asInterface(b));
+ }
+ return sInstance;
+ }
+ }
+
+ /**
+ * Checks if the edge gesture service is present.
+ * <p>
+ * Since the service is only started at boot time and is bound to the system server, this
+ * is constant for the devices up time.
+ *
+ * @return {@code true} when the edge gesture service is running on this device.
+ * @hide
+ */
+ public boolean isPresent() {
+ return mPs != null;
+ }
+
+ /**
+ * Register a listener for edge gesture activation gestures. Initially the listener
+ * is set to listen for no position. Use updateedge gestureActivationListener() to
+ * bind the listener to positions.
+ *
+ * @param listener is the activation listener.
+ * @return {@code true} if the registration was successful.
+ * @hide
+ */
+ public boolean setEdgeGestureActivationListener(EdgeGestureActivationListener listener) {
+ if (DEBUG) {
+ Slog.d(TAG, "Set edge gesture activation listener");
+ }
+ try {
+ IEdgeGestureHostCallback callback = mPs.registerEdgeGestureActivationListener(listener.mDelegator);
+ listener.setHostCallback(callback);
+ return true;
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to set edge gesture activation listener: " + e.getMessage());
+ return false;
+ }
+ }
+
+ /**
+ * Update the listener to react on gestures in the given positions.
+ *
+ * @param listener is a already registered listener.
+ * @param positions is a bit mask describing the positions to listen to.
+ * @hide
+ */
+ public void updateEdgeGestureActivationListener(EdgeGestureActivationListener listener, int positions) {
+ if (DEBUG) {
+ Slog.d(TAG, "Update edge gesture activation listener: 0x" + Integer.toHexString(positions));
+ }
+ try {
+ mPs.updateEdgeGestureActivationListener(listener.mDelegator.asBinder(), positions);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to update edge gesture activation listener: " + e.getMessage());
+ }
+ }
+
+}
diff --git a/core/java/android/service/gesture/IEdgeGestureActivationListener.aidl b/core/java/android/service/gesture/IEdgeGestureActivationListener.aidl
new file mode 100644
index 0000000..0c9b24a
--- /dev/null
+++ b/core/java/android/service/gesture/IEdgeGestureActivationListener.aidl
@@ -0,0 +1,14 @@
+
+package android.service.gesture;
+
+import android.view.InputEvent;
+
+/** @hide */
+interface IEdgeGestureActivationListener {
+
+ /** Called when a gesture is detected that fits to the activation gesture. At this point in
+ * time gesture detection is disabled. Call IEdgeGestureHostCallback.restoreState() to
+ * recover from this.
+ */
+ oneway void onEdgeGestureActivation(int touchX, int touchY, int positionIndex, int flags);
+} \ No newline at end of file
diff --git a/core/java/android/service/gesture/IEdgeGestureHostCallback.aidl b/core/java/android/service/gesture/IEdgeGestureHostCallback.aidl
new file mode 100644
index 0000000..c261550
--- /dev/null
+++ b/core/java/android/service/gesture/IEdgeGestureHostCallback.aidl
@@ -0,0 +1,20 @@
+package android.service.gesture;
+
+/** @hide */
+interface IEdgeGestureHostCallback {
+
+ /** After being activated, this allows to steal focus from the current
+ * window
+ */
+ boolean gainTouchFocus(IBinder windowToken);
+
+ /** Turns listening for activation gestures on again, after it was disabled during
+ * the call to the listener.
+ */
+ oneway void restoreListenerState();
+
+ /*
+ * Tells filter to drop all events till touch up
+ */
+ boolean dropEventsUntilLift();
+} \ No newline at end of file
diff --git a/core/java/android/service/gesture/IEdgeGestureService.aidl b/core/java/android/service/gesture/IEdgeGestureService.aidl
new file mode 100644
index 0000000..342cf71
--- /dev/null
+++ b/core/java/android/service/gesture/IEdgeGestureService.aidl
@@ -0,0 +1,20 @@
+package android.service.gesture;
+
+import android.service.gesture.IEdgeGestureActivationListener;
+import android.service.gesture.IEdgeGestureHostCallback;
+
+/** @hide */
+interface IEdgeGestureService {
+
+ /** Register a listener for activation gestures. Initially the listener
+ * is set to listen for no position. Use updateEdgeGestureActivationListener() to
+ * bind the listener to positions.
+ * Use the returned IEdgeGestureHostCallback to manipulate the state after activation.
+ */
+ IEdgeGestureHostCallback registerEdgeGestureActivationListener(in IEdgeGestureActivationListener listener);
+
+ /** Update the listener to react on gestures in the given positions.
+ */
+ void updateEdgeGestureActivationListener(in IBinder listener, int positionFlags);
+
+} \ No newline at end of file
diff --git a/core/java/android/service/gesture/IGestureService.aidl b/core/java/android/service/gesture/IGestureService.aidl
new file mode 100644
index 0000000..1944d50
--- /dev/null
+++ b/core/java/android/service/gesture/IGestureService.aidl
@@ -0,0 +1,11 @@
+package android.service.gesture;
+
+import android.app.PendingIntent;
+
+/** @hide */
+interface IGestureService {
+
+ void setOnLongPressPendingIntent(in PendingIntent pendingIntent);
+ void setOnDoubleClickPendingIntent(in PendingIntent pendingIntent);
+
+}
diff --git a/core/java/android/service/gesture/package.html b/core/java/android/service/gesture/package.html
new file mode 100644
index 0000000..c9f96a6
--- /dev/null
+++ b/core/java/android/service/gesture/package.html
@@ -0,0 +1,5 @@
+<body>
+
+{@hide}
+
+</body>
diff --git a/core/java/android/speech/SpeechRecognizer.java b/core/java/android/speech/SpeechRecognizer.java
index 88e2ede..3eb24e4 100644
--- a/core/java/android/speech/SpeechRecognizer.java
+++ b/core/java/android/speech/SpeechRecognizer.java
@@ -260,6 +260,7 @@ public class SpeechRecognizer {
* not set explicitly, default values will be used by the recognizer.
*/
public void startListening(final Intent recognizerIntent) {
+ android.util.SeempLog.record(72);
if (recognizerIntent == null) {
throw new IllegalArgumentException("intent must not be null");
}
diff --git a/core/java/android/text/TextUtils.java b/core/java/android/text/TextUtils.java
index d8f7158..75fd2da 100644
--- a/core/java/android/text/TextUtils.java
+++ b/core/java/android/text/TextUtils.java
@@ -1754,19 +1754,21 @@ public class TextUtils {
* Be careful: this code will need to be updated when vertical scripts will be supported
*/
public static int getLayoutDirectionFromLocale(Locale locale) {
+ boolean mirror = SystemProperties.getBoolean(Settings.Global.DEVELOPMENT_FORCE_RTL, false);
if (locale != null && !locale.equals(Locale.ROOT)) {
final String scriptSubtag = ICU.addLikelySubtags(locale).getScript();
if (scriptSubtag == null) return getLayoutDirectionFromFirstChar(locale);
if (scriptSubtag.equalsIgnoreCase(ARAB_SCRIPT_SUBTAG) ||
scriptSubtag.equalsIgnoreCase(HEBR_SCRIPT_SUBTAG)) {
- return View.LAYOUT_DIRECTION_RTL;
+ // If forcing into RTL layout mode and language is RTL
+ // return LTR as default, else RTL
+ return mirror ? View.LAYOUT_DIRECTION_LTR : View.LAYOUT_DIRECTION_RTL;
}
}
- // If forcing into RTL layout mode, return RTL as default, else LTR
- return SystemProperties.getBoolean(Settings.Global.DEVELOPMENT_FORCE_RTL, false)
- ? View.LAYOUT_DIRECTION_RTL
- : View.LAYOUT_DIRECTION_LTR;
+ // If forcing into RTL layout mode and language is LTR
+ // return RTL as default, else LTR
+ return mirror ? View.LAYOUT_DIRECTION_RTL : View.LAYOUT_DIRECTION_LTR;
}
/**
diff --git a/core/java/android/text/format/DateFormat.java b/core/java/android/text/format/DateFormat.java
index 3ed37b3..998fa9d 100755
--- a/core/java/android/text/format/DateFormat.java
+++ b/core/java/android/text/format/DateFormat.java
@@ -177,12 +177,23 @@ public class DateFormat {
* @hide
*/
public static boolean is24HourFormat(Context context, int userHandle) {
- String value = Settings.System.getStringForUser(context.getContentResolver(),
+ String setting = Settings.System.getStringForUser(context.getContentResolver(),
Settings.System.TIME_12_24, userHandle);
+ Locale locale = context.getResources().getConfiguration().locale;
+ return is24HourFormat(setting, locale);
+ }
- if (value == null) {
- Locale locale = context.getResources().getConfiguration().locale;
-
+ /**
+ * Returns true if user preference with the given user handle is set to 24-hour format.
+ * @param setting value of the TIME_12_24 system setting, which may be null
+ * @param locale current default locale for this device
+ * @param userHandle the user handle of the user to query.
+ * @return true if 24 hour time format is selected, false otherwise.
+ *
+ * @hide
+ */
+ public static boolean is24HourFormat(String setting, Locale locale) {
+ if (setting == null) {
synchronized (sLocaleLock) {
if (sIs24HourLocale != null && sIs24HourLocale.equals(locale)) {
return sIs24Hour;
@@ -197,23 +208,23 @@ public class DateFormat {
String pattern = sdf.toPattern();
if (pattern.indexOf('H') >= 0) {
- value = "24";
+ setting = "24";
} else {
- value = "12";
+ setting = "12";
}
} else {
- value = "12";
+ setting = "12";
}
synchronized (sLocaleLock) {
sIs24HourLocale = locale;
- sIs24Hour = value.equals("24");
+ sIs24Hour = setting.equals("24");
}
return sIs24Hour;
}
- return value.equals("24");
+ return setting.equals("24");
}
/**
diff --git a/core/java/android/text/method/MetaKeyKeyListener.java b/core/java/android/text/method/MetaKeyKeyListener.java
index e9db5fd..569ca60 100644
--- a/core/java/android/text/method/MetaKeyKeyListener.java
+++ b/core/java/android/text/method/MetaKeyKeyListener.java
@@ -23,6 +23,9 @@ import android.text.Spanned;
import android.view.KeyEvent;
import android.view.View;
import android.view.KeyCharacterMap;
+import android.os.IPowerManager;
+import android.os.RemoteException;
+import android.os.ServiceManager;
/**
* This base class encapsulates the behavior for tracking the state of
@@ -273,6 +276,14 @@ public abstract class MetaKeyKeyListener {
adjust(content, CAP);
adjust(content, ALT);
adjust(content, SYM);
+ try {
+ IPowerManager power = IPowerManager.Stub.asInterface(
+ ServiceManager.getService("power"));
+ if (getMetaState(content, META_SHIFT_ON) <= 0)
+ power.setKeyboardLight(false, 1);
+ if (getMetaState(content, META_ALT_ON) <= 0)
+ power.setKeyboardLight(false, 2);
+ } catch (RemoteException doe) {}
}
/**
@@ -325,12 +336,32 @@ public abstract class MetaKeyKeyListener {
public boolean onKeyDown(View view, Editable content, int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_SHIFT_LEFT || keyCode == KeyEvent.KEYCODE_SHIFT_RIGHT) {
press(content, CAP);
+ try {
+ IPowerManager power = IPowerManager.Stub.asInterface(
+ ServiceManager.getService("power"));
+ int state = content.getSpanFlags(CAP);
+ if (state == PRESSED || state == LOCKED) {
+ power.setKeyboardLight(true, 1);
+ } else {
+ power.setKeyboardLight(false, 1);
+ }
+ } catch (RemoteException doe) {}
return true;
}
if (keyCode == KeyEvent.KEYCODE_ALT_LEFT || keyCode == KeyEvent.KEYCODE_ALT_RIGHT
|| keyCode == KeyEvent.KEYCODE_NUM) {
press(content, ALT);
+ try {
+ IPowerManager power = IPowerManager.Stub.asInterface(
+ ServiceManager.getService("power"));
+ int state = content.getSpanFlags(ALT);
+ if (state == PRESSED || state == LOCKED) {
+ power.setKeyboardLight(true, 2);
+ } else {
+ power.setKeyboardLight(false, 2);
+ }
+ } catch (RemoteException doe) {}
return true;
}
diff --git a/core/java/android/util/DisplayMetrics.java b/core/java/android/util/DisplayMetrics.java
index 9a69600..2b654ad 100644
--- a/core/java/android/util/DisplayMetrics.java
+++ b/core/java/android/util/DisplayMetrics.java
@@ -16,6 +16,7 @@
package android.util;
+import android.graphics.Bitmap;
import android.os.SystemProperties;
@@ -138,7 +139,20 @@ public class DisplayMetrics {
* density for a display in {@link #densityDpi}.
*/
@Deprecated
- public static int DENSITY_DEVICE = getDeviceDensity();
+ public static int DENSITY_DEVICE;
+
+ /** @hide */
+ public static int DENSITY_PREFERRED;
+
+ /** @hide */
+ public static int DENSITY_DEVICE_DEFAULT;
+
+ static {
+ DENSITY_DEVICE = SystemProperties.getInt("qemu.sf.lcd_density", SystemProperties
+ .getInt("ro.sf.lcd_density", DENSITY_DEFAULT));
+ DENSITY_DEVICE_DEFAULT = DENSITY_DEVICE;
+ DENSITY_PREFERRED = SystemProperties.getInt("persist.sys.lcd_density", DENSITY_DEVICE);
+ }
/**
* The absolute width of the display in pixels.
@@ -229,6 +243,18 @@ public class DisplayMetrics {
*/
public float noncompatYdpi;
+ /** @hide */
+ public void setDensity(int inDensity) {
+ density = inDensity / (float) DENSITY_DEFAULT;
+ densityDpi = inDensity;
+ scaledDensity = density;
+ xdpi = inDensity;
+ ydpi = inDensity;
+
+ DENSITY_DEVICE = inDensity;
+ Bitmap.setDefaultDensity(inDensity);
+ }
+
public DisplayMetrics() {
}
@@ -319,13 +345,4 @@ public class DisplayMetrics {
", height=" + heightPixels + ", scaledDensity=" + scaledDensity +
", xdpi=" + xdpi + ", ydpi=" + ydpi + "}";
}
-
- private static int getDeviceDensity() {
- // qemu.sf.lcd_density can be used to override ro.sf.lcd_density
- // when running in the emulator, allowing for dynamic configurations.
- // The reason for this is that ro.sf.lcd_density is write-once and is
- // set by the init process when it parses build.prop before anything else.
- return SystemProperties.getInt("qemu.sf.lcd_density",
- SystemProperties.getInt("ro.sf.lcd_density", DENSITY_DEFAULT));
- }
}
diff --git a/core/java/android/util/NativeTextHelper.java b/core/java/android/util/NativeTextHelper.java
new file mode 100644
index 0000000..eb380e9
--- /dev/null
+++ b/core/java/android/util/NativeTextHelper.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2015, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package android.util;
+
+import android.content.Context;
+
+/**
+ *@hide
+ */
+public class NativeTextHelper {
+
+ /**
+ * parse the string to current language.
+ *
+ * @param context base context of the application
+ * @param originalString original string
+ * @param defPackage the target package where the local language strings
+ * defined
+ * @param originNamesId the id of the original string array.
+ * @param localNamesId the id of the local string keys.
+ * @return local language string
+ */
+ private static final String getLocalString(Context context, String originalString,
+ String defPackage, int originNamesId, int localNamesId) {
+ String[] origNames = context.getResources().getStringArray(originNamesId);
+ String[] localNames = context.getResources().getStringArray(localNamesId);
+ for (int i = 0; i < origNames.length; i++) {
+ if (origNames[i].equalsIgnoreCase(originalString)) {
+ return context.getString(context.getResources().getIdentifier(localNames[i],
+ "string", defPackage));
+ }
+ }
+ return originalString;
+ }
+
+ /**
+ * parse the string to current language string in public resources.
+ *
+ * @param context base context of the application
+ * @param originalString original string
+ * @param originNamesId the id of the original string array.
+ * @param localNamesId the id of the local string keys.
+ * @return local language string
+ */
+ public static final String getLocalString(Context context, String originalString,
+ int originNamesId, int localNamesId) {
+ return getLocalString(context, originalString, "android", originNamesId, localNamesId);
+ }
+
+ /**
+ * parse the string to current language string in current resources.
+ *
+ * @param context base context of the application
+ * @param originalString original string
+ * @param originNamesId the id of the original string array.
+ * @param localNamesId the id of the local string keys.
+ * @return local language string
+ */
+ public static final String getInternalLocalString(Context context, String originalString,
+ int originNamesId,
+ int localNamesId) {
+ return getLocalString(context, originalString, context.getPackageName(), originNamesId,
+ localNamesId);
+ }
+
+}
diff --git a/core/java/android/util/SeempLog.java b/core/java/android/util/SeempLog.java
new file mode 100644
index 0000000..6e6cce6
--- /dev/null
+++ b/core/java/android/util/SeempLog.java
@@ -0,0 +1,758 @@
+/*
+ * Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package android.util;
+
+import com.android.internal.os.RuntimeInit;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.net.UnknownHostException;
+import java.util.Hashtable;
+import java.util.Map;
+import java.util.List;
+import java.util.Iterator;
+import android.util.Log;
+import android.provider.Settings;
+
+/**
+ * SeempLog
+ *
+ * @hide
+ */
+public final class SeempLog {
+ private SeempLog() {
+ }
+
+ /**
+ * Send a log message to the seemp log.
+ * @param api The api triggering this message.
+ */
+ public static int record(int api) {
+ return seemp_println_native(api, "");
+ }
+
+ /**
+ * Send a log message to the seemp log.
+ * @param api The api triggering this message.
+ * @param msg The message you would like logged.
+ */
+ public static int record_str(int api, String msg) {
+ if ( msg != null ) {
+ return seemp_println_native(api, msg);
+ }
+ else {
+ return seemp_println_native(api, "");
+ }
+ }
+
+ public static int record_sensor(int api,
+ android.hardware.Sensor sensor) {
+ if ( sensor != null ) {
+ return seemp_println_native(api, "sensor="+sensor.getType());
+ }
+ else {
+ return seemp_println_native(api, "sensor=-1");
+ }
+ }
+
+ public static int record_sensor_rate(int api,
+ android.hardware.Sensor sensor, int rate) {
+ if ( sensor != null ) {
+ return seemp_println_native(api,
+ "sensor="+sensor.getType() + ",rate="+rate);
+ }
+ else {
+ return seemp_println_native(api, "sensor=-1,rate=" + rate);
+ }
+ }
+
+ public static int record_uri(int api, android.net.Uri uri) {
+ if ( uri != null ) {
+ return seemp_println_native(api, "uri, " + uri.toString());
+ }
+ else {
+ return seemp_println_native(api, "uri, null" );
+ }
+ }
+
+ public static int record_vg_layout(int api,
+ android.view.ViewGroup.LayoutParams params) {
+ try {
+ android.view.WindowManager.LayoutParams p =
+ (android.view.WindowManager.LayoutParams) params;
+ if ( p != null ) {
+ return seemp_println_native(api,
+ "window_type=" + p.type + ",window_flag=" + p.flags);
+ }
+ else {
+ return seemp_println_native(api, "");
+ }
+ } catch (ClassCastException cce) {
+ return seemp_println_native(api, "");
+ }
+ }
+
+ /** @hide */ public static native int seemp_println_native(int api, String msg);
+
+ public static final int SEEMP_API_android_provider_Settings__get_ANDROID_ID_ = 7;
+ public static final int SEEMP_API_android_provider_Settings__get_ACCELEROMETER_ROTATION_ = 96;
+ public static final int SEEMP_API_android_provider_Settings__get_USER_ROTATION_ = 97;
+ public static final int SEEMP_API_android_provider_Settings__get_ADB_ENABLED_ = 98;
+ public static final int SEEMP_API_android_provider_Settings__get_DEBUG_APP_ = 99;
+ public static final int SEEMP_API_android_provider_Settings__get_WAIT_FOR_DEBUGGER_ = 100;
+ public static final int SEEMP_API_android_provider_Settings__get_AIRPLANE_MODE_ON_ = 101;
+ public static final int SEEMP_API_android_provider_Settings__get_AIRPLANE_MODE_RADIOS_ = 102;
+ public static final int SEEMP_API_android_provider_Settings__get_ALARM_ALERT_ = 103;
+ public static final int SEEMP_API_android_provider_Settings__get_NEXT_ALARM_FORMATTED_ = 104;
+ public static final int SEEMP_API_android_provider_Settings__get_ALWAYS_FINISH_ACTIVITIES_ = 105;
+ public static final int SEEMP_API_android_provider_Settings__get_LOGGING_ID_ = 106;
+ public static final int SEEMP_API_android_provider_Settings__get_ANIMATOR_DURATION_SCALE_ = 107;
+ public static final int SEEMP_API_android_provider_Settings__get_WINDOW_ANIMATION_SCALE_ = 108;
+ public static final int SEEMP_API_android_provider_Settings__get_FONT_SCALE_ = 109;
+ public static final int SEEMP_API_android_provider_Settings__get_SCREEN_BRIGHTNESS_ = 110;
+ public static final int SEEMP_API_android_provider_Settings__get_SCREEN_BRIGHTNESS_MODE_ = 111;
+ public static final int SEEMP_API_android_provider_Settings__get_SCREEN_BRIGHTNESS_MODE_AUTOMATIC_ = 112;
+ public static final int SEEMP_API_android_provider_Settings__get_SCREEN_BRIGHTNESS_MODE_MANUAL_ = 113;
+ public static final int SEEMP_API_android_provider_Settings__get_SCREEN_OFF_TIMEOUT_ = 114;
+ public static final int SEEMP_API_android_provider_Settings__get_DIM_SCREEN_ = 115;
+ public static final int SEEMP_API_android_provider_Settings__get_TRANSITION_ANIMATION_SCALE_ = 116;
+ public static final int SEEMP_API_android_provider_Settings__get_STAY_ON_WHILE_PLUGGED_IN_ = 117;
+ public static final int SEEMP_API_android_provider_Settings__get_WALLPAPER_ACTIVITY_ = 118;
+ public static final int SEEMP_API_android_provider_Settings__get_SHOW_PROCESSES_ = 119;
+ public static final int SEEMP_API_android_provider_Settings__get_SHOW_WEB_SUGGESTIONS_ = 120;
+ public static final int SEEMP_API_android_provider_Settings__get_SHOW_GTALK_SERVICE_STATUS_ = 121;
+ public static final int SEEMP_API_android_provider_Settings__get_USE_GOOGLE_MAIL_ = 122;
+ public static final int SEEMP_API_android_provider_Settings__get_AUTO_TIME_ = 123;
+ public static final int SEEMP_API_android_provider_Settings__get_AUTO_TIME_ZONE_ = 124;
+ public static final int SEEMP_API_android_provider_Settings__get_DATE_FORMAT_ = 125;
+ public static final int SEEMP_API_android_provider_Settings__get_TIME_12_24_ = 126;
+ public static final int SEEMP_API_android_provider_Settings__get_BLUETOOTH_DISCOVERABILITY_ = 127;
+ public static final int SEEMP_API_android_provider_Settings__get_BLUETOOTH_DISCOVERABILITY_TIMEOUT_ = 128;
+ public static final int SEEMP_API_android_provider_Settings__get_BLUETOOTH_ON_ = 129;
+ public static final int SEEMP_API_android_provider_Settings__get_DEVICE_PROVISIONED_ = 130;
+ public static final int SEEMP_API_android_provider_Settings__get_SETUP_WIZARD_HAS_RUN_ = 131;
+ public static final int SEEMP_API_android_provider_Settings__get_DTMF_TONE_WHEN_DIALING_ = 132;
+ public static final int SEEMP_API_android_provider_Settings__get_END_BUTTON_BEHAVIOR_ = 133;
+ public static final int SEEMP_API_android_provider_Settings__get_RINGTONE_ = 134;
+ public static final int SEEMP_API_android_provider_Settings__get_MODE_RINGER_ = 135;
+ public static final int SEEMP_API_android_provider_Settings__get_INSTALL_NON_MARKET_APPS_ = 136;
+ public static final int SEEMP_API_android_provider_Settings__get_LOCATION_PROVIDERS_ALLOWED_ = 137;
+ public static final int SEEMP_API_android_provider_Settings__get_LOCK_PATTERN_ENABLED_ = 138;
+ public static final int SEEMP_API_android_provider_Settings__get_LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED_ = 139;
+ public static final int SEEMP_API_android_provider_Settings__get_LOCK_PATTERN_VISIBLE_ = 140;
+ public static final int SEEMP_API_android_provider_Settings__get_NETWORK_PREFERENCE_ = 141;
+ public static final int SEEMP_API_android_provider_Settings__get_DATA_ROAMING_ = 142;
+ public static final int SEEMP_API_android_provider_Settings__get_HTTP_PROXY_ = 143;
+ public static final int SEEMP_API_android_provider_Settings__get_PARENTAL_CONTROL_ENABLED_ = 144;
+ public static final int SEEMP_API_android_provider_Settings__get_PARENTAL_CONTROL_LAST_UPDATE_ = 145;
+ public static final int SEEMP_API_android_provider_Settings__get_PARENTAL_CONTROL_REDIRECT_URL_ = 146;
+ public static final int SEEMP_API_android_provider_Settings__get_RADIO_BLUETOOTH_ = 147;
+ public static final int SEEMP_API_android_provider_Settings__get_RADIO_CELL_ = 148;
+ public static final int SEEMP_API_android_provider_Settings__get_RADIO_NFC_ = 149;
+ public static final int SEEMP_API_android_provider_Settings__get_RADIO_WIFI_ = 150;
+ public static final int SEEMP_API_android_provider_Settings__get_SYS_PROP_SETTING_VERSION_ = 151;
+ public static final int SEEMP_API_android_provider_Settings__get_SETTINGS_CLASSNAME_ = 152;
+ public static final int SEEMP_API_android_provider_Settings__get_TEXT_AUTO_CAPS_ = 153;
+ public static final int SEEMP_API_android_provider_Settings__get_TEXT_AUTO_PUNCTUATE_ = 154;
+ public static final int SEEMP_API_android_provider_Settings__get_TEXT_AUTO_REPLACE_ = 155;
+ public static final int SEEMP_API_android_provider_Settings__get_TEXT_SHOW_PASSWORD_ = 156;
+ public static final int SEEMP_API_android_provider_Settings__get_USB_MASS_STORAGE_ENABLED_ = 157;
+ public static final int SEEMP_API_android_provider_Settings__get_VIBRATE_ON_ = 158;
+ public static final int SEEMP_API_android_provider_Settings__get_HAPTIC_FEEDBACK_ENABLED_ = 159;
+ public static final int SEEMP_API_android_provider_Settings__get_VOLUME_ALARM_ = 160;
+ public static final int SEEMP_API_android_provider_Settings__get_VOLUME_BLUETOOTH_SCO_ = 161;
+ public static final int SEEMP_API_android_provider_Settings__get_VOLUME_MUSIC_ = 162;
+ public static final int SEEMP_API_android_provider_Settings__get_VOLUME_NOTIFICATION_ = 163;
+ public static final int SEEMP_API_android_provider_Settings__get_VOLUME_RING_ = 164;
+ public static final int SEEMP_API_android_provider_Settings__get_VOLUME_SYSTEM_ = 165;
+ public static final int SEEMP_API_android_provider_Settings__get_VOLUME_VOICE_ = 166;
+ public static final int SEEMP_API_android_provider_Settings__get_SOUND_EFFECTS_ENABLED_ = 167;
+ public static final int SEEMP_API_android_provider_Settings__get_MODE_RINGER_STREAMS_AFFECTED_ = 168;
+ public static final int SEEMP_API_android_provider_Settings__get_MUTE_STREAMS_AFFECTED_ = 169;
+ public static final int SEEMP_API_android_provider_Settings__get_NOTIFICATION_SOUND_ = 170;
+ public static final int SEEMP_API_android_provider_Settings__get_APPEND_FOR_LAST_AUDIBLE_ = 171;
+ public static final int SEEMP_API_android_provider_Settings__get_WIFI_MAX_DHCP_RETRY_COUNT_ = 172;
+ public static final int SEEMP_API_android_provider_Settings__get_WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS_ = 173;
+ public static final int SEEMP_API_android_provider_Settings__get_WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON_ = 174;
+ public static final int SEEMP_API_android_provider_Settings__get_WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY_ = 175;
+ public static final int SEEMP_API_android_provider_Settings__get_WIFI_NUM_OPEN_NETWORKS_KEPT_ = 176;
+ public static final int SEEMP_API_android_provider_Settings__get_WIFI_ON_ = 177;
+ public static final int SEEMP_API_android_provider_Settings__get_WIFI_SLEEP_POLICY_ = 178;
+ public static final int SEEMP_API_android_provider_Settings__get_WIFI_SLEEP_POLICY_DEFAULT_ = 179;
+ public static final int SEEMP_API_android_provider_Settings__get_WIFI_SLEEP_POLICY_NEVER_ = 180;
+ public static final int SEEMP_API_android_provider_Settings__get_WIFI_SLEEP_POLICY_NEVER_WHILE_PLUGGED_ = 181;
+ public static final int SEEMP_API_android_provider_Settings__get_WIFI_STATIC_DNS1_ = 182;
+ public static final int SEEMP_API_android_provider_Settings__get_WIFI_STATIC_DNS2_ = 183;
+ public static final int SEEMP_API_android_provider_Settings__get_WIFI_STATIC_GATEWAY_ = 184;
+ public static final int SEEMP_API_android_provider_Settings__get_WIFI_STATIC_IP_ = 185;
+ public static final int SEEMP_API_android_provider_Settings__get_WIFI_STATIC_NETMASK_ = 186;
+ public static final int SEEMP_API_android_provider_Settings__get_WIFI_USE_STATIC_IP_ = 187;
+ public static final int SEEMP_API_android_provider_Settings__get_WIFI_WATCHDOG_ACCEPTABLE_PACKET_LOSS_PERCENTAGE_ = 188;
+ public static final int SEEMP_API_android_provider_Settings__get_WIFI_WATCHDOG_AP_COUNT_ = 189;
+ public static final int SEEMP_API_android_provider_Settings__get_WIFI_WATCHDOG_BACKGROUND_CHECK_DELAY_MS_ = 190;
+ public static final int SEEMP_API_android_provider_Settings__get_WIFI_WATCHDOG_BACKGROUND_CHECK_ENABLED_ = 191;
+ public static final int SEEMP_API_android_provider_Settings__get_WIFI_WATCHDOG_BACKGROUND_CHECK_TIMEOUT_MS_ = 192;
+ public static final int SEEMP_API_android_provider_Settings__get_WIFI_WATCHDOG_INITIAL_IGNORED_PING_COUNT_ = 193;
+ public static final int SEEMP_API_android_provider_Settings__get_WIFI_WATCHDOG_MAX_AP_CHECKS_ = 194;
+ public static final int SEEMP_API_android_provider_Settings__get_WIFI_WATCHDOG_ON_ = 195;
+ public static final int SEEMP_API_android_provider_Settings__get_WIFI_WATCHDOG_PING_COUNT_ = 196;
+ public static final int SEEMP_API_android_provider_Settings__get_WIFI_WATCHDOG_PING_DELAY_MS_ = 197;
+ public static final int SEEMP_API_android_provider_Settings__get_WIFI_WATCHDOG_PING_TIMEOUT_MS_ = 198;
+ public static final int SEEMP_API_android_provider_Settings__put_ACCELEROMETER_ROTATION_ = 199;
+ public static final int SEEMP_API_android_provider_Settings__put_USER_ROTATION_ = 200;
+ public static final int SEEMP_API_android_provider_Settings__put_ADB_ENABLED_ = 201;
+ public static final int SEEMP_API_android_provider_Settings__put_DEBUG_APP_ = 202;
+ public static final int SEEMP_API_android_provider_Settings__put_WAIT_FOR_DEBUGGER_ = 203;
+ public static final int SEEMP_API_android_provider_Settings__put_AIRPLANE_MODE_ON_ = 204;
+ public static final int SEEMP_API_android_provider_Settings__put_AIRPLANE_MODE_RADIOS_ = 205;
+ public static final int SEEMP_API_android_provider_Settings__put_ALARM_ALERT_ = 206;
+ public static final int SEEMP_API_android_provider_Settings__put_NEXT_ALARM_FORMATTED_ = 207;
+ public static final int SEEMP_API_android_provider_Settings__put_ALWAYS_FINISH_ACTIVITIES_ = 208;
+ public static final int SEEMP_API_android_provider_Settings__put_ANDROID_ID_ = 209;
+ public static final int SEEMP_API_android_provider_Settings__put_LOGGING_ID_ = 210;
+ public static final int SEEMP_API_android_provider_Settings__put_ANIMATOR_DURATION_SCALE_ = 211;
+ public static final int SEEMP_API_android_provider_Settings__put_WINDOW_ANIMATION_SCALE_ = 212;
+ public static final int SEEMP_API_android_provider_Settings__put_FONT_SCALE_ = 213;
+ public static final int SEEMP_API_android_provider_Settings__put_SCREEN_BRIGHTNESS_ = 214;
+ public static final int SEEMP_API_android_provider_Settings__put_SCREEN_BRIGHTNESS_MODE_ = 215;
+ public static final int SEEMP_API_android_provider_Settings__put_SCREEN_BRIGHTNESS_MODE_AUTOMATIC_ = 216;
+ public static final int SEEMP_API_android_provider_Settings__put_SCREEN_BRIGHTNESS_MODE_MANUAL_ = 217;
+ public static final int SEEMP_API_android_provider_Settings__put_SCREEN_OFF_TIMEOUT_ = 218;
+ public static final int SEEMP_API_android_provider_Settings__put_DIM_SCREEN_ = 219;
+ public static final int SEEMP_API_android_provider_Settings__put_TRANSITION_ANIMATION_SCALE_ = 220;
+ public static final int SEEMP_API_android_provider_Settings__put_STAY_ON_WHILE_PLUGGED_IN_ = 221;
+ public static final int SEEMP_API_android_provider_Settings__put_WALLPAPER_ACTIVITY_ = 222;
+ public static final int SEEMP_API_android_provider_Settings__put_SHOW_PROCESSES_ = 223;
+ public static final int SEEMP_API_android_provider_Settings__put_SHOW_WEB_SUGGESTIONS_ = 224;
+ public static final int SEEMP_API_android_provider_Settings__put_SHOW_GTALK_SERVICE_STATUS_ = 225;
+ public static final int SEEMP_API_android_provider_Settings__put_USE_GOOGLE_MAIL_ = 226;
+ public static final int SEEMP_API_android_provider_Settings__put_AUTO_TIME_ = 227;
+ public static final int SEEMP_API_android_provider_Settings__put_AUTO_TIME_ZONE_ = 228;
+ public static final int SEEMP_API_android_provider_Settings__put_DATE_FORMAT_ = 229;
+ public static final int SEEMP_API_android_provider_Settings__put_TIME_12_24_ = 230;
+ public static final int SEEMP_API_android_provider_Settings__put_BLUETOOTH_DISCOVERABILITY_ = 231;
+ public static final int SEEMP_API_android_provider_Settings__put_BLUETOOTH_DISCOVERABILITY_TIMEOUT_ = 232;
+ public static final int SEEMP_API_android_provider_Settings__put_BLUETOOTH_ON_ = 233;
+ public static final int SEEMP_API_android_provider_Settings__put_DEVICE_PROVISIONED_ = 234;
+ public static final int SEEMP_API_android_provider_Settings__put_SETUP_WIZARD_HAS_RUN_ = 235;
+ public static final int SEEMP_API_android_provider_Settings__put_DTMF_TONE_WHEN_DIALING_ = 236;
+ public static final int SEEMP_API_android_provider_Settings__put_END_BUTTON_BEHAVIOR_ = 237;
+ public static final int SEEMP_API_android_provider_Settings__put_RINGTONE_ = 238;
+ public static final int SEEMP_API_android_provider_Settings__put_MODE_RINGER_ = 239;
+ public static final int SEEMP_API_android_provider_Settings__put_INSTALL_NON_MARKET_APPS_ = 240;
+ public static final int SEEMP_API_android_provider_Settings__put_LOCATION_PROVIDERS_ALLOWED_ = 241;
+ public static final int SEEMP_API_android_provider_Settings__put_LOCK_PATTERN_ENABLED_ = 242;
+ public static final int SEEMP_API_android_provider_Settings__put_LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED_ = 243;
+ public static final int SEEMP_API_android_provider_Settings__put_LOCK_PATTERN_VISIBLE_ = 244;
+ public static final int SEEMP_API_android_provider_Settings__put_NETWORK_PREFERENCE_ = 245;
+ public static final int SEEMP_API_android_provider_Settings__put_DATA_ROAMING_ = 246;
+ public static final int SEEMP_API_android_provider_Settings__put_HTTP_PROXY_ = 247;
+ public static final int SEEMP_API_android_provider_Settings__put_PARENTAL_CONTROL_ENABLED_ = 248;
+ public static final int SEEMP_API_android_provider_Settings__put_PARENTAL_CONTROL_LAST_UPDATE_ = 249;
+ public static final int SEEMP_API_android_provider_Settings__put_PARENTAL_CONTROL_REDIRECT_URL_ = 250;
+ public static final int SEEMP_API_android_provider_Settings__put_RADIO_BLUETOOTH_ = 251;
+ public static final int SEEMP_API_android_provider_Settings__put_RADIO_CELL_ = 252;
+ public static final int SEEMP_API_android_provider_Settings__put_RADIO_NFC_ = 253;
+ public static final int SEEMP_API_android_provider_Settings__put_RADIO_WIFI_ = 254;
+ public static final int SEEMP_API_android_provider_Settings__put_SYS_PROP_SETTING_VERSION_ = 255;
+ public static final int SEEMP_API_android_provider_Settings__put_SETTINGS_CLASSNAME_ = 256;
+ public static final int SEEMP_API_android_provider_Settings__put_TEXT_AUTO_CAPS_ = 257;
+ public static final int SEEMP_API_android_provider_Settings__put_TEXT_AUTO_PUNCTUATE_ = 258;
+ public static final int SEEMP_API_android_provider_Settings__put_TEXT_AUTO_REPLACE_ = 259;
+ public static final int SEEMP_API_android_provider_Settings__put_TEXT_SHOW_PASSWORD_ = 260;
+ public static final int SEEMP_API_android_provider_Settings__put_USB_MASS_STORAGE_ENABLED_ = 261;
+ public static final int SEEMP_API_android_provider_Settings__put_VIBRATE_ON_ = 262;
+ public static final int SEEMP_API_android_provider_Settings__put_HAPTIC_FEEDBACK_ENABLED_ = 263;
+ public static final int SEEMP_API_android_provider_Settings__put_VOLUME_ALARM_ = 264;
+ public static final int SEEMP_API_android_provider_Settings__put_VOLUME_BLUETOOTH_SCO_ = 265;
+ public static final int SEEMP_API_android_provider_Settings__put_VOLUME_MUSIC_ = 266;
+ public static final int SEEMP_API_android_provider_Settings__put_VOLUME_NOTIFICATION_ = 267;
+ public static final int SEEMP_API_android_provider_Settings__put_VOLUME_RING_ = 268;
+ public static final int SEEMP_API_android_provider_Settings__put_VOLUME_SYSTEM_ = 269;
+ public static final int SEEMP_API_android_provider_Settings__put_VOLUME_VOICE_ = 270;
+ public static final int SEEMP_API_android_provider_Settings__put_SOUND_EFFECTS_ENABLED_ = 271;
+ public static final int SEEMP_API_android_provider_Settings__put_MODE_RINGER_STREAMS_AFFECTED_ = 272;
+ public static final int SEEMP_API_android_provider_Settings__put_MUTE_STREAMS_AFFECTED_ = 273;
+ public static final int SEEMP_API_android_provider_Settings__put_NOTIFICATION_SOUND_ = 274;
+ public static final int SEEMP_API_android_provider_Settings__put_APPEND_FOR_LAST_AUDIBLE_ = 275;
+ public static final int SEEMP_API_android_provider_Settings__put_WIFI_MAX_DHCP_RETRY_COUNT_ = 276;
+ public static final int SEEMP_API_android_provider_Settings__put_WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS_ = 277;
+ public static final int SEEMP_API_android_provider_Settings__put_WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON_ = 278;
+ public static final int SEEMP_API_android_provider_Settings__put_WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY_ = 279;
+ public static final int SEEMP_API_android_provider_Settings__put_WIFI_NUM_OPEN_NETWORKS_KEPT_ = 280;
+ public static final int SEEMP_API_android_provider_Settings__put_WIFI_ON_ = 281;
+ public static final int SEEMP_API_android_provider_Settings__put_WIFI_SLEEP_POLICY_ = 282;
+ public static final int SEEMP_API_android_provider_Settings__put_WIFI_SLEEP_POLICY_DEFAULT_ = 283;
+ public static final int SEEMP_API_android_provider_Settings__put_WIFI_SLEEP_POLICY_NEVER_ = 284;
+ public static final int SEEMP_API_android_provider_Settings__put_WIFI_SLEEP_POLICY_NEVER_WHILE_PLUGGED_ = 285;
+ public static final int SEEMP_API_android_provider_Settings__put_WIFI_STATIC_DNS1_ = 286;
+ public static final int SEEMP_API_android_provider_Settings__put_WIFI_STATIC_DNS2_ = 287;
+ public static final int SEEMP_API_android_provider_Settings__put_WIFI_STATIC_GATEWAY_ = 288;
+ public static final int SEEMP_API_android_provider_Settings__put_WIFI_STATIC_IP_ = 289;
+ public static final int SEEMP_API_android_provider_Settings__put_WIFI_STATIC_NETMASK_ = 290;
+ public static final int SEEMP_API_android_provider_Settings__put_WIFI_USE_STATIC_IP_ = 291;
+ public static final int SEEMP_API_android_provider_Settings__put_WIFI_WATCHDOG_ACCEPTABLE_PACKET_LOSS_PERCENTAGE_ = 292;
+ public static final int SEEMP_API_android_provider_Settings__put_WIFI_WATCHDOG_AP_COUNT_ = 293;
+ public static final int SEEMP_API_android_provider_Settings__put_WIFI_WATCHDOG_BACKGROUND_CHECK_DELAY_MS_ = 294;
+ public static final int SEEMP_API_android_provider_Settings__put_WIFI_WATCHDOG_BACKGROUND_CHECK_ENABLED_ = 295;
+ public static final int SEEMP_API_android_provider_Settings__put_WIFI_WATCHDOG_BACKGROUND_CHECK_TIMEOUT_MS_ = 296;
+ public static final int SEEMP_API_android_provider_Settings__put_WIFI_WATCHDOG_INITIAL_IGNORED_PING_COUNT_ = 297;
+ public static final int SEEMP_API_android_provider_Settings__put_WIFI_WATCHDOG_MAX_AP_CHECKS_ = 298;
+ public static final int SEEMP_API_android_provider_Settings__put_WIFI_WATCHDOG_ON_ = 299;
+ public static final int SEEMP_API_android_provider_Settings__put_WIFI_WATCHDOG_PING_COUNT_ = 300;
+ public static final int SEEMP_API_android_provider_Settings__put_WIFI_WATCHDOG_PING_DELAY_MS_ = 301;
+ public static final int SEEMP_API_android_provider_Settings__put_WIFI_WATCHDOG_PING_TIMEOUT_MS_ = 302;
+
+ private final static java.util.Map<String,Integer> value_to_get_map;
+ static {
+ value_to_get_map = new java.util.HashMap<String,Integer>( 198 );
+ value_to_get_map.put(Settings.System.NOTIFICATION_SOUND,
+ SEEMP_API_android_provider_Settings__get_NOTIFICATION_SOUND_);
+ value_to_get_map.put(Settings.System.DTMF_TONE_WHEN_DIALING,
+ SEEMP_API_android_provider_Settings__get_DTMF_TONE_WHEN_DIALING_);
+ value_to_get_map.put(Settings.System.LOCK_PATTERN_ENABLED,
+ SEEMP_API_android_provider_Settings__get_LOCK_PATTERN_ENABLED_);
+ value_to_get_map.put(Settings.System.WIFI_MAX_DHCP_RETRY_COUNT,
+ SEEMP_API_android_provider_Settings__get_WIFI_MAX_DHCP_RETRY_COUNT_);
+ value_to_get_map.put(Settings.System.AUTO_TIME,
+ SEEMP_API_android_provider_Settings__get_AUTO_TIME_);
+ value_to_get_map.put(Settings.System.SETUP_WIZARD_HAS_RUN,
+ SEEMP_API_android_provider_Settings__get_SETUP_WIZARD_HAS_RUN_);
+ value_to_get_map.put(Settings.System.SYS_PROP_SETTING_VERSION,
+ SEEMP_API_android_provider_Settings__get_SYS_PROP_SETTING_VERSION_);
+ value_to_get_map.put(Settings.System.WIFI_WATCHDOG_BACKGROUND_CHECK_TIMEOUT_MS,
+ SEEMP_API_android_provider_Settings__get_WIFI_WATCHDOG_BACKGROUND_CHECK_TIMEOUT_MS_);
+ value_to_get_map.put(Settings.System.LOCATION_PROVIDERS_ALLOWED,
+ SEEMP_API_android_provider_Settings__get_LOCATION_PROVIDERS_ALLOWED_);
+ value_to_get_map.put(Settings.System.ALARM_ALERT,
+ SEEMP_API_android_provider_Settings__get_ALARM_ALERT_);
+ value_to_get_map.put(Settings.System.VIBRATE_ON,
+ SEEMP_API_android_provider_Settings__get_VIBRATE_ON_);
+ value_to_get_map.put(Settings.System.USB_MASS_STORAGE_ENABLED,
+ SEEMP_API_android_provider_Settings__get_USB_MASS_STORAGE_ENABLED_);
+ value_to_get_map.put(Settings.System.WIFI_WATCHDOG_PING_DELAY_MS,
+ SEEMP_API_android_provider_Settings__get_WIFI_WATCHDOG_PING_DELAY_MS_);
+ value_to_get_map.put(Settings.System.FONT_SCALE,
+ SEEMP_API_android_provider_Settings__get_FONT_SCALE_);
+ value_to_get_map.put(Settings.System.WIFI_WATCHDOG_AP_COUNT,
+ SEEMP_API_android_provider_Settings__get_WIFI_WATCHDOG_AP_COUNT_);
+ value_to_get_map.put(Settings.System.ALWAYS_FINISH_ACTIVITIES,
+ SEEMP_API_android_provider_Settings__get_ALWAYS_FINISH_ACTIVITIES_);
+ value_to_get_map.put(Settings.System.ACCELEROMETER_ROTATION,
+ SEEMP_API_android_provider_Settings__get_ACCELEROMETER_ROTATION_);
+ value_to_get_map.put(Settings.System.WIFI_WATCHDOG_PING_TIMEOUT_MS,
+ SEEMP_API_android_provider_Settings__get_WIFI_WATCHDOG_PING_TIMEOUT_MS_);
+ value_to_get_map.put(Settings.System.VOLUME_NOTIFICATION,
+ SEEMP_API_android_provider_Settings__get_VOLUME_NOTIFICATION_);
+ value_to_get_map.put(Settings.System.AIRPLANE_MODE_ON,
+ SEEMP_API_android_provider_Settings__get_AIRPLANE_MODE_ON_);
+ value_to_get_map.put(Settings.System.WIFI_WATCHDOG_BACKGROUND_CHECK_DELAY_MS,
+ SEEMP_API_android_provider_Settings__get_WIFI_WATCHDOG_BACKGROUND_CHECK_DELAY_MS_);
+ value_to_get_map.put(Settings.System.WIFI_STATIC_IP,
+ SEEMP_API_android_provider_Settings__get_WIFI_STATIC_IP_);
+ value_to_get_map.put(Settings.System.RADIO_BLUETOOTH,
+ SEEMP_API_android_provider_Settings__get_RADIO_BLUETOOTH_);
+ value_to_get_map.put(Settings.System.BLUETOOTH_DISCOVERABILITY_TIMEOUT,
+ SEEMP_API_android_provider_Settings__get_BLUETOOTH_DISCOVERABILITY_TIMEOUT_);
+ value_to_get_map.put(Settings.System.VOLUME_RING,
+ SEEMP_API_android_provider_Settings__get_VOLUME_RING_);
+ value_to_get_map.put(Settings.System.MODE_RINGER_STREAMS_AFFECTED,
+ SEEMP_API_android_provider_Settings__get_MODE_RINGER_STREAMS_AFFECTED_);
+ value_to_get_map.put(Settings.System.VOLUME_SYSTEM,
+ SEEMP_API_android_provider_Settings__get_VOLUME_SYSTEM_);
+ value_to_get_map.put(Settings.System.SCREEN_OFF_TIMEOUT,
+ SEEMP_API_android_provider_Settings__get_SCREEN_OFF_TIMEOUT_);
+ value_to_get_map.put(Settings.System.RADIO_WIFI,
+ SEEMP_API_android_provider_Settings__get_RADIO_WIFI_);
+ value_to_get_map.put(Settings.System.AUTO_TIME_ZONE,
+ SEEMP_API_android_provider_Settings__get_AUTO_TIME_ZONE_);
+ value_to_get_map.put(Settings.System.TEXT_AUTO_CAPS,
+ SEEMP_API_android_provider_Settings__get_TEXT_AUTO_CAPS_);
+ value_to_get_map.put(Settings.System.WALLPAPER_ACTIVITY,
+ SEEMP_API_android_provider_Settings__get_WALLPAPER_ACTIVITY_);
+ value_to_get_map.put(Settings.System.ANIMATOR_DURATION_SCALE,
+ SEEMP_API_android_provider_Settings__get_ANIMATOR_DURATION_SCALE_);
+ value_to_get_map.put(Settings.System.WIFI_NUM_OPEN_NETWORKS_KEPT,
+ SEEMP_API_android_provider_Settings__get_WIFI_NUM_OPEN_NETWORKS_KEPT_);
+ value_to_get_map.put(Settings.System.LOCK_PATTERN_VISIBLE,
+ SEEMP_API_android_provider_Settings__get_LOCK_PATTERN_VISIBLE_);
+ value_to_get_map.put(Settings.System.VOLUME_VOICE,
+ SEEMP_API_android_provider_Settings__get_VOLUME_VOICE_);
+ value_to_get_map.put(Settings.System.DEBUG_APP,
+ SEEMP_API_android_provider_Settings__get_DEBUG_APP_);
+ value_to_get_map.put(Settings.System.WIFI_ON,
+ SEEMP_API_android_provider_Settings__get_WIFI_ON_);
+ value_to_get_map.put(Settings.System.TEXT_SHOW_PASSWORD,
+ SEEMP_API_android_provider_Settings__get_TEXT_SHOW_PASSWORD_);
+ value_to_get_map.put(Settings.System.WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY,
+ SEEMP_API_android_provider_Settings__get_WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY_);
+ value_to_get_map.put(Settings.System.WIFI_SLEEP_POLICY,
+ SEEMP_API_android_provider_Settings__get_WIFI_SLEEP_POLICY_);
+ value_to_get_map.put(Settings.System.VOLUME_MUSIC,
+ SEEMP_API_android_provider_Settings__get_VOLUME_MUSIC_);
+ value_to_get_map.put(Settings.System.PARENTAL_CONTROL_LAST_UPDATE,
+ SEEMP_API_android_provider_Settings__get_PARENTAL_CONTROL_LAST_UPDATE_);
+ value_to_get_map.put(Settings.System.DEVICE_PROVISIONED,
+ SEEMP_API_android_provider_Settings__get_DEVICE_PROVISIONED_);
+ value_to_get_map.put(Settings.System.HTTP_PROXY,
+ SEEMP_API_android_provider_Settings__get_HTTP_PROXY_);
+ value_to_get_map.put(Settings.System.ANDROID_ID,
+ SEEMP_API_android_provider_Settings__get_ANDROID_ID_);
+ value_to_get_map.put(Settings.System.WIFI_WATCHDOG_MAX_AP_CHECKS,
+ SEEMP_API_android_provider_Settings__get_WIFI_WATCHDOG_MAX_AP_CHECKS_);
+ value_to_get_map.put(Settings.System.END_BUTTON_BEHAVIOR,
+ SEEMP_API_android_provider_Settings__get_END_BUTTON_BEHAVIOR_);
+ value_to_get_map.put(Settings.System.NEXT_ALARM_FORMATTED,
+ SEEMP_API_android_provider_Settings__get_NEXT_ALARM_FORMATTED_);
+ value_to_get_map.put(Settings.System.RADIO_CELL,
+ SEEMP_API_android_provider_Settings__get_RADIO_CELL_);
+ value_to_get_map.put(Settings.System.PARENTAL_CONTROL_ENABLED,
+ SEEMP_API_android_provider_Settings__get_PARENTAL_CONTROL_ENABLED_);
+ value_to_get_map.put(Settings.System.BLUETOOTH_ON,
+ SEEMP_API_android_provider_Settings__get_BLUETOOTH_ON_);
+ value_to_get_map.put(Settings.System.WINDOW_ANIMATION_SCALE,
+ SEEMP_API_android_provider_Settings__get_WINDOW_ANIMATION_SCALE_);
+ value_to_get_map.put(Settings.System.WIFI_WATCHDOG_BACKGROUND_CHECK_ENABLED,
+ SEEMP_API_android_provider_Settings__get_WIFI_WATCHDOG_BACKGROUND_CHECK_ENABLED_);
+ value_to_get_map.put(Settings.System.BLUETOOTH_DISCOVERABILITY,
+ SEEMP_API_android_provider_Settings__get_BLUETOOTH_DISCOVERABILITY_);
+ value_to_get_map.put(Settings.System.WIFI_STATIC_DNS1,
+ SEEMP_API_android_provider_Settings__get_WIFI_STATIC_DNS1_);
+ value_to_get_map.put(Settings.System.WIFI_STATIC_DNS2,
+ SEEMP_API_android_provider_Settings__get_WIFI_STATIC_DNS2_);
+ value_to_get_map.put(Settings.System.HAPTIC_FEEDBACK_ENABLED,
+ SEEMP_API_android_provider_Settings__get_HAPTIC_FEEDBACK_ENABLED_);
+ value_to_get_map.put(Settings.System.SHOW_WEB_SUGGESTIONS,
+ SEEMP_API_android_provider_Settings__get_SHOW_WEB_SUGGESTIONS_);
+ value_to_get_map.put(Settings.System.PARENTAL_CONTROL_REDIRECT_URL,
+ SEEMP_API_android_provider_Settings__get_PARENTAL_CONTROL_REDIRECT_URL_);
+ value_to_get_map.put(Settings.System.DATE_FORMAT,
+ SEEMP_API_android_provider_Settings__get_DATE_FORMAT_);
+ value_to_get_map.put(Settings.System.RADIO_NFC,
+ SEEMP_API_android_provider_Settings__get_RADIO_NFC_);
+ value_to_get_map.put(Settings.System.AIRPLANE_MODE_RADIOS,
+ SEEMP_API_android_provider_Settings__get_AIRPLANE_MODE_RADIOS_);
+ value_to_get_map.put(Settings.System.LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED,
+ SEEMP_API_android_provider_Settings__get_LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED_);
+ value_to_get_map.put(Settings.System.TIME_12_24,
+ SEEMP_API_android_provider_Settings__get_TIME_12_24_);
+ value_to_get_map.put(Settings.System.WIFI_WATCHDOG_INITIAL_IGNORED_PING_COUNT,
+ SEEMP_API_android_provider_Settings__get_WIFI_WATCHDOG_INITIAL_IGNORED_PING_COUNT_);
+ value_to_get_map.put(Settings.System.VOLUME_BLUETOOTH_SCO,
+ SEEMP_API_android_provider_Settings__get_VOLUME_BLUETOOTH_SCO_);
+ value_to_get_map.put(Settings.System.USER_ROTATION,
+ SEEMP_API_android_provider_Settings__get_USER_ROTATION_);
+ value_to_get_map.put(Settings.System.WIFI_STATIC_GATEWAY,
+ SEEMP_API_android_provider_Settings__get_WIFI_STATIC_GATEWAY_);
+ value_to_get_map.put(Settings.System.STAY_ON_WHILE_PLUGGED_IN,
+ SEEMP_API_android_provider_Settings__get_STAY_ON_WHILE_PLUGGED_IN_);
+ value_to_get_map.put(Settings.System.SOUND_EFFECTS_ENABLED,
+ SEEMP_API_android_provider_Settings__get_SOUND_EFFECTS_ENABLED_);
+ value_to_get_map.put(Settings.System.WIFI_WATCHDOG_PING_COUNT,
+ SEEMP_API_android_provider_Settings__get_WIFI_WATCHDOG_PING_COUNT_);
+ value_to_get_map.put(Settings.System.DATA_ROAMING,
+ SEEMP_API_android_provider_Settings__get_DATA_ROAMING_);
+ value_to_get_map.put(Settings.System.SETTINGS_CLASSNAME,
+ SEEMP_API_android_provider_Settings__get_SETTINGS_CLASSNAME_);
+ value_to_get_map.put(Settings.System.TRANSITION_ANIMATION_SCALE,
+ SEEMP_API_android_provider_Settings__get_TRANSITION_ANIMATION_SCALE_);
+ value_to_get_map.put(Settings.System.WAIT_FOR_DEBUGGER,
+ SEEMP_API_android_provider_Settings__get_WAIT_FOR_DEBUGGER_);
+ value_to_get_map.put(Settings.System.INSTALL_NON_MARKET_APPS,
+ SEEMP_API_android_provider_Settings__get_INSTALL_NON_MARKET_APPS_);
+ value_to_get_map.put(Settings.System.ADB_ENABLED,
+ SEEMP_API_android_provider_Settings__get_ADB_ENABLED_);
+ value_to_get_map.put(Settings.System.WIFI_USE_STATIC_IP,
+ SEEMP_API_android_provider_Settings__get_WIFI_USE_STATIC_IP_);
+ value_to_get_map.put(Settings.System.DIM_SCREEN,
+ SEEMP_API_android_provider_Settings__get_DIM_SCREEN_);
+ value_to_get_map.put(Settings.System.VOLUME_ALARM,
+ SEEMP_API_android_provider_Settings__get_VOLUME_ALARM_);
+ value_to_get_map.put(Settings.System.WIFI_WATCHDOG_ON,
+ SEEMP_API_android_provider_Settings__get_WIFI_WATCHDOG_ON_);
+ value_to_get_map.put(Settings.System.WIFI_STATIC_NETMASK,
+ SEEMP_API_android_provider_Settings__get_WIFI_STATIC_NETMASK_);
+ value_to_get_map.put(Settings.System.NETWORK_PREFERENCE,
+ SEEMP_API_android_provider_Settings__get_NETWORK_PREFERENCE_);
+ value_to_get_map.put(Settings.System.SHOW_PROCESSES,
+ SEEMP_API_android_provider_Settings__get_SHOW_PROCESSES_);
+ value_to_get_map.put(Settings.System.TEXT_AUTO_REPLACE,
+ SEEMP_API_android_provider_Settings__get_TEXT_AUTO_REPLACE_);
+ value_to_get_map.put(Settings.System.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON,
+ SEEMP_API_android_provider_Settings__get_WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON_);
+ value_to_get_map.put(Settings.System.APPEND_FOR_LAST_AUDIBLE,
+ SEEMP_API_android_provider_Settings__get_APPEND_FOR_LAST_AUDIBLE_);
+ value_to_get_map.put(Settings.System.SHOW_GTALK_SERVICE_STATUS,
+ SEEMP_API_android_provider_Settings__get_SHOW_GTALK_SERVICE_STATUS_);
+ value_to_get_map.put(Settings.System.SCREEN_BRIGHTNESS,
+ SEEMP_API_android_provider_Settings__get_SCREEN_BRIGHTNESS_);
+ value_to_get_map.put(Settings.System.USE_GOOGLE_MAIL,
+ SEEMP_API_android_provider_Settings__get_USE_GOOGLE_MAIL_);
+ value_to_get_map.put(Settings.System.RINGTONE,
+ SEEMP_API_android_provider_Settings__get_RINGTONE_);
+ value_to_get_map.put(Settings.System.LOGGING_ID,
+ SEEMP_API_android_provider_Settings__get_LOGGING_ID_);
+ value_to_get_map.put(Settings.System.MODE_RINGER,
+ SEEMP_API_android_provider_Settings__get_MODE_RINGER_);
+ value_to_get_map.put(Settings.System.MUTE_STREAMS_AFFECTED,
+ SEEMP_API_android_provider_Settings__get_MUTE_STREAMS_AFFECTED_);
+ value_to_get_map.put(Settings.System.WIFI_WATCHDOG_ACCEPTABLE_PACKET_LOSS_PERCENTAGE,
+ SEEMP_API_android_provider_Settings__get_WIFI_WATCHDOG_ACCEPTABLE_PACKET_LOSS_PERCENTAGE_);
+ value_to_get_map.put(Settings.System.TEXT_AUTO_PUNCTUATE,
+ SEEMP_API_android_provider_Settings__get_TEXT_AUTO_PUNCTUATE_);
+ value_to_get_map.put(Settings.System.WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS,
+ SEEMP_API_android_provider_Settings__get_WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS_);
+ value_to_get_map.put(Settings.System.SCREEN_BRIGHTNESS_MODE,
+ SEEMP_API_android_provider_Settings__get_SCREEN_BRIGHTNESS_MODE_);
+ }
+
+ public static int getSeempGetApiIdFromValue( String v )
+ {
+ Integer result = value_to_get_map.get( v );
+ if (result == null)
+ {
+ result = -1;
+ }
+ return result;
+ }
+
+ private final static java.util.Map<String,Integer> value_to_put_map;
+ static {
+ value_to_put_map = new java.util.HashMap<String,Integer>( 198 );
+ value_to_put_map.put(Settings.System.NOTIFICATION_SOUND,
+ SEEMP_API_android_provider_Settings__put_NOTIFICATION_SOUND_);
+ value_to_put_map.put(Settings.System.DTMF_TONE_WHEN_DIALING,
+ SEEMP_API_android_provider_Settings__put_DTMF_TONE_WHEN_DIALING_);
+ value_to_put_map.put(Settings.System.LOCK_PATTERN_ENABLED,
+ SEEMP_API_android_provider_Settings__put_LOCK_PATTERN_ENABLED_);
+ value_to_put_map.put(Settings.System.WIFI_MAX_DHCP_RETRY_COUNT,
+ SEEMP_API_android_provider_Settings__put_WIFI_MAX_DHCP_RETRY_COUNT_);
+ value_to_put_map.put(Settings.System.AUTO_TIME,
+ SEEMP_API_android_provider_Settings__put_AUTO_TIME_);
+ value_to_put_map.put(Settings.System.SETUP_WIZARD_HAS_RUN,
+ SEEMP_API_android_provider_Settings__put_SETUP_WIZARD_HAS_RUN_);
+ value_to_put_map.put(Settings.System.SYS_PROP_SETTING_VERSION,
+ SEEMP_API_android_provider_Settings__put_SYS_PROP_SETTING_VERSION_);
+ value_to_put_map.put(Settings.System.WIFI_WATCHDOG_BACKGROUND_CHECK_TIMEOUT_MS,
+ SEEMP_API_android_provider_Settings__put_WIFI_WATCHDOG_BACKGROUND_CHECK_TIMEOUT_MS_);
+ value_to_put_map.put(Settings.System.LOCATION_PROVIDERS_ALLOWED,
+ SEEMP_API_android_provider_Settings__put_LOCATION_PROVIDERS_ALLOWED_);
+ value_to_put_map.put(Settings.System.ALARM_ALERT,
+ SEEMP_API_android_provider_Settings__put_ALARM_ALERT_);
+ value_to_put_map.put(Settings.System.VIBRATE_ON,
+ SEEMP_API_android_provider_Settings__put_VIBRATE_ON_);
+ value_to_put_map.put(Settings.System.USB_MASS_STORAGE_ENABLED,
+ SEEMP_API_android_provider_Settings__put_USB_MASS_STORAGE_ENABLED_);
+ value_to_put_map.put(Settings.System.WIFI_WATCHDOG_PING_DELAY_MS,
+ SEEMP_API_android_provider_Settings__put_WIFI_WATCHDOG_PING_DELAY_MS_);
+ value_to_put_map.put(Settings.System.FONT_SCALE,
+ SEEMP_API_android_provider_Settings__put_FONT_SCALE_);
+ value_to_put_map.put(Settings.System.WIFI_WATCHDOG_AP_COUNT,
+ SEEMP_API_android_provider_Settings__put_WIFI_WATCHDOG_AP_COUNT_);
+ value_to_put_map.put(Settings.System.ALWAYS_FINISH_ACTIVITIES,
+ SEEMP_API_android_provider_Settings__put_ALWAYS_FINISH_ACTIVITIES_);
+ value_to_put_map.put(Settings.System.ACCELEROMETER_ROTATION,
+ SEEMP_API_android_provider_Settings__put_ACCELEROMETER_ROTATION_);
+ value_to_put_map.put(Settings.System.WIFI_WATCHDOG_PING_TIMEOUT_MS,
+ SEEMP_API_android_provider_Settings__put_WIFI_WATCHDOG_PING_TIMEOUT_MS_);
+ value_to_put_map.put(Settings.System.VOLUME_NOTIFICATION,
+ SEEMP_API_android_provider_Settings__put_VOLUME_NOTIFICATION_);
+ value_to_put_map.put(Settings.System.AIRPLANE_MODE_ON,
+ SEEMP_API_android_provider_Settings__put_AIRPLANE_MODE_ON_);
+ value_to_put_map.put(Settings.System.WIFI_WATCHDOG_BACKGROUND_CHECK_DELAY_MS,
+ SEEMP_API_android_provider_Settings__put_WIFI_WATCHDOG_BACKGROUND_CHECK_DELAY_MS_);
+ value_to_put_map.put(Settings.System.WIFI_STATIC_IP,
+ SEEMP_API_android_provider_Settings__put_WIFI_STATIC_IP_);
+ value_to_put_map.put(Settings.System.RADIO_BLUETOOTH,
+ SEEMP_API_android_provider_Settings__put_RADIO_BLUETOOTH_);
+ value_to_put_map.put(Settings.System.BLUETOOTH_DISCOVERABILITY_TIMEOUT,
+ SEEMP_API_android_provider_Settings__put_BLUETOOTH_DISCOVERABILITY_TIMEOUT_);
+ value_to_put_map.put(Settings.System.VOLUME_RING,
+ SEEMP_API_android_provider_Settings__put_VOLUME_RING_);
+ value_to_put_map.put(Settings.System.MODE_RINGER_STREAMS_AFFECTED,
+ SEEMP_API_android_provider_Settings__put_MODE_RINGER_STREAMS_AFFECTED_);
+ value_to_put_map.put(Settings.System.VOLUME_SYSTEM,
+ SEEMP_API_android_provider_Settings__put_VOLUME_SYSTEM_);
+ value_to_put_map.put(Settings.System.SCREEN_OFF_TIMEOUT,
+ SEEMP_API_android_provider_Settings__put_SCREEN_OFF_TIMEOUT_);
+ value_to_put_map.put(Settings.System.RADIO_WIFI,
+ SEEMP_API_android_provider_Settings__put_RADIO_WIFI_);
+ value_to_put_map.put(Settings.System.AUTO_TIME_ZONE,
+ SEEMP_API_android_provider_Settings__put_AUTO_TIME_ZONE_);
+ value_to_put_map.put(Settings.System.TEXT_AUTO_CAPS,
+ SEEMP_API_android_provider_Settings__put_TEXT_AUTO_CAPS_);
+ value_to_put_map.put(Settings.System.WALLPAPER_ACTIVITY,
+ SEEMP_API_android_provider_Settings__put_WALLPAPER_ACTIVITY_);
+ value_to_put_map.put(Settings.System.ANIMATOR_DURATION_SCALE,
+ SEEMP_API_android_provider_Settings__put_ANIMATOR_DURATION_SCALE_);
+ value_to_put_map.put(Settings.System.WIFI_NUM_OPEN_NETWORKS_KEPT,
+ SEEMP_API_android_provider_Settings__put_WIFI_NUM_OPEN_NETWORKS_KEPT_);
+ value_to_put_map.put(Settings.System.LOCK_PATTERN_VISIBLE,
+ SEEMP_API_android_provider_Settings__put_LOCK_PATTERN_VISIBLE_);
+ value_to_put_map.put(Settings.System.VOLUME_VOICE,
+ SEEMP_API_android_provider_Settings__put_VOLUME_VOICE_);
+ value_to_put_map.put(Settings.System.DEBUG_APP,
+ SEEMP_API_android_provider_Settings__put_DEBUG_APP_);
+ value_to_put_map.put(Settings.System.WIFI_ON,
+ SEEMP_API_android_provider_Settings__put_WIFI_ON_);
+ value_to_put_map.put(Settings.System.TEXT_SHOW_PASSWORD,
+ SEEMP_API_android_provider_Settings__put_TEXT_SHOW_PASSWORD_);
+ value_to_put_map.put(Settings.System.WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY,
+ SEEMP_API_android_provider_Settings__put_WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY_);
+ value_to_put_map.put(Settings.System.WIFI_SLEEP_POLICY,
+ SEEMP_API_android_provider_Settings__put_WIFI_SLEEP_POLICY_);
+ value_to_put_map.put(Settings.System.VOLUME_MUSIC,
+ SEEMP_API_android_provider_Settings__put_VOLUME_MUSIC_);
+ value_to_put_map.put(Settings.System.PARENTAL_CONTROL_LAST_UPDATE,
+ SEEMP_API_android_provider_Settings__put_PARENTAL_CONTROL_LAST_UPDATE_);
+ value_to_put_map.put(Settings.System.DEVICE_PROVISIONED,
+ SEEMP_API_android_provider_Settings__put_DEVICE_PROVISIONED_);
+ value_to_put_map.put(Settings.System.HTTP_PROXY,
+ SEEMP_API_android_provider_Settings__put_HTTP_PROXY_);
+ value_to_put_map.put(Settings.System.ANDROID_ID,
+ SEEMP_API_android_provider_Settings__put_ANDROID_ID_);
+ value_to_put_map.put(Settings.System.WIFI_WATCHDOG_MAX_AP_CHECKS,
+ SEEMP_API_android_provider_Settings__put_WIFI_WATCHDOG_MAX_AP_CHECKS_);
+ value_to_put_map.put(Settings.System.END_BUTTON_BEHAVIOR,
+ SEEMP_API_android_provider_Settings__put_END_BUTTON_BEHAVIOR_);
+ value_to_put_map.put(Settings.System.NEXT_ALARM_FORMATTED,
+ SEEMP_API_android_provider_Settings__put_NEXT_ALARM_FORMATTED_);
+ value_to_put_map.put(Settings.System.RADIO_CELL,
+ SEEMP_API_android_provider_Settings__put_RADIO_CELL_);
+ value_to_put_map.put(Settings.System.PARENTAL_CONTROL_ENABLED,
+ SEEMP_API_android_provider_Settings__put_PARENTAL_CONTROL_ENABLED_);
+ value_to_put_map.put(Settings.System.BLUETOOTH_ON,
+ SEEMP_API_android_provider_Settings__put_BLUETOOTH_ON_);
+ value_to_put_map.put(Settings.System.WINDOW_ANIMATION_SCALE,
+ SEEMP_API_android_provider_Settings__put_WINDOW_ANIMATION_SCALE_);
+ value_to_put_map.put(Settings.System.WIFI_WATCHDOG_BACKGROUND_CHECK_ENABLED,
+ SEEMP_API_android_provider_Settings__put_WIFI_WATCHDOG_BACKGROUND_CHECK_ENABLED_);
+ value_to_put_map.put(Settings.System.BLUETOOTH_DISCOVERABILITY,
+ SEEMP_API_android_provider_Settings__put_BLUETOOTH_DISCOVERABILITY_);
+ value_to_put_map.put(Settings.System.WIFI_STATIC_DNS1,
+ SEEMP_API_android_provider_Settings__put_WIFI_STATIC_DNS1_);
+ value_to_put_map.put(Settings.System.WIFI_STATIC_DNS2,
+ SEEMP_API_android_provider_Settings__put_WIFI_STATIC_DNS2_);
+ value_to_put_map.put(Settings.System.HAPTIC_FEEDBACK_ENABLED,
+ SEEMP_API_android_provider_Settings__put_HAPTIC_FEEDBACK_ENABLED_);
+ value_to_put_map.put(Settings.System.SHOW_WEB_SUGGESTIONS,
+ SEEMP_API_android_provider_Settings__put_SHOW_WEB_SUGGESTIONS_);
+ value_to_put_map.put(Settings.System.PARENTAL_CONTROL_REDIRECT_URL,
+ SEEMP_API_android_provider_Settings__put_PARENTAL_CONTROL_REDIRECT_URL_);
+ value_to_put_map.put(Settings.System.DATE_FORMAT,
+ SEEMP_API_android_provider_Settings__put_DATE_FORMAT_);
+ value_to_put_map.put(Settings.System.RADIO_NFC,
+ SEEMP_API_android_provider_Settings__put_RADIO_NFC_);
+ value_to_put_map.put(Settings.System.AIRPLANE_MODE_RADIOS,
+ SEEMP_API_android_provider_Settings__put_AIRPLANE_MODE_RADIOS_);
+ value_to_put_map.put(Settings.System.LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED,
+ SEEMP_API_android_provider_Settings__put_LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED_);
+ value_to_put_map.put(Settings.System.TIME_12_24,
+ SEEMP_API_android_provider_Settings__put_TIME_12_24_);
+ value_to_put_map.put(Settings.System.WIFI_WATCHDOG_INITIAL_IGNORED_PING_COUNT,
+ SEEMP_API_android_provider_Settings__put_WIFI_WATCHDOG_INITIAL_IGNORED_PING_COUNT_);
+ value_to_put_map.put(Settings.System.VOLUME_BLUETOOTH_SCO,
+ SEEMP_API_android_provider_Settings__put_VOLUME_BLUETOOTH_SCO_);
+ value_to_put_map.put(Settings.System.USER_ROTATION,
+ SEEMP_API_android_provider_Settings__put_USER_ROTATION_);
+ value_to_put_map.put(Settings.System.WIFI_STATIC_GATEWAY,
+ SEEMP_API_android_provider_Settings__put_WIFI_STATIC_GATEWAY_);
+ value_to_put_map.put(Settings.System.STAY_ON_WHILE_PLUGGED_IN,
+ SEEMP_API_android_provider_Settings__put_STAY_ON_WHILE_PLUGGED_IN_);
+ value_to_put_map.put(Settings.System.SOUND_EFFECTS_ENABLED,
+ SEEMP_API_android_provider_Settings__put_SOUND_EFFECTS_ENABLED_);
+ value_to_put_map.put(Settings.System.WIFI_WATCHDOG_PING_COUNT,
+ SEEMP_API_android_provider_Settings__put_WIFI_WATCHDOG_PING_COUNT_);
+ value_to_put_map.put(Settings.System.DATA_ROAMING,
+ SEEMP_API_android_provider_Settings__put_DATA_ROAMING_);
+ value_to_put_map.put(Settings.System.SETTINGS_CLASSNAME,
+ SEEMP_API_android_provider_Settings__put_SETTINGS_CLASSNAME_);
+ value_to_put_map.put(Settings.System.TRANSITION_ANIMATION_SCALE,
+ SEEMP_API_android_provider_Settings__put_TRANSITION_ANIMATION_SCALE_);
+ value_to_put_map.put(Settings.System.WAIT_FOR_DEBUGGER,
+ SEEMP_API_android_provider_Settings__put_WAIT_FOR_DEBUGGER_);
+ value_to_put_map.put(Settings.System.INSTALL_NON_MARKET_APPS,
+ SEEMP_API_android_provider_Settings__put_INSTALL_NON_MARKET_APPS_);
+ value_to_put_map.put(Settings.System.ADB_ENABLED,
+ SEEMP_API_android_provider_Settings__put_ADB_ENABLED_);
+ value_to_put_map.put(Settings.System.WIFI_USE_STATIC_IP,
+ SEEMP_API_android_provider_Settings__put_WIFI_USE_STATIC_IP_);
+ value_to_put_map.put(Settings.System.DIM_SCREEN,
+ SEEMP_API_android_provider_Settings__put_DIM_SCREEN_);
+ value_to_put_map.put(Settings.System.VOLUME_ALARM,
+ SEEMP_API_android_provider_Settings__put_VOLUME_ALARM_);
+ value_to_put_map.put(Settings.System.WIFI_WATCHDOG_ON,
+ SEEMP_API_android_provider_Settings__put_WIFI_WATCHDOG_ON_);
+ value_to_put_map.put(Settings.System.WIFI_STATIC_NETMASK,
+ SEEMP_API_android_provider_Settings__put_WIFI_STATIC_NETMASK_);
+ value_to_put_map.put(Settings.System.NETWORK_PREFERENCE,
+ SEEMP_API_android_provider_Settings__put_NETWORK_PREFERENCE_);
+ value_to_put_map.put(Settings.System.SHOW_PROCESSES,
+ SEEMP_API_android_provider_Settings__put_SHOW_PROCESSES_);
+ value_to_put_map.put(Settings.System.TEXT_AUTO_REPLACE,
+ SEEMP_API_android_provider_Settings__put_TEXT_AUTO_REPLACE_);
+ value_to_put_map.put(Settings.System.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON,
+ SEEMP_API_android_provider_Settings__put_WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON_);
+ value_to_put_map.put(Settings.System.APPEND_FOR_LAST_AUDIBLE,
+ SEEMP_API_android_provider_Settings__put_APPEND_FOR_LAST_AUDIBLE_);
+ value_to_put_map.put(Settings.System.SHOW_GTALK_SERVICE_STATUS,
+ SEEMP_API_android_provider_Settings__put_SHOW_GTALK_SERVICE_STATUS_);
+ value_to_put_map.put(Settings.System.SCREEN_BRIGHTNESS,
+ SEEMP_API_android_provider_Settings__put_SCREEN_BRIGHTNESS_);
+ value_to_put_map.put(Settings.System.USE_GOOGLE_MAIL,
+ SEEMP_API_android_provider_Settings__put_USE_GOOGLE_MAIL_);
+ value_to_put_map.put(Settings.System.RINGTONE,
+ SEEMP_API_android_provider_Settings__put_RINGTONE_);
+ value_to_put_map.put(Settings.System.LOGGING_ID,
+ SEEMP_API_android_provider_Settings__put_LOGGING_ID_);
+ value_to_put_map.put(Settings.System.MODE_RINGER,
+ SEEMP_API_android_provider_Settings__put_MODE_RINGER_);
+ value_to_put_map.put(Settings.System.MUTE_STREAMS_AFFECTED,
+ SEEMP_API_android_provider_Settings__put_MUTE_STREAMS_AFFECTED_);
+ value_to_put_map.put(Settings.System.WIFI_WATCHDOG_ACCEPTABLE_PACKET_LOSS_PERCENTAGE,
+ SEEMP_API_android_provider_Settings__put_WIFI_WATCHDOG_ACCEPTABLE_PACKET_LOSS_PERCENTAGE_);
+ value_to_put_map.put(Settings.System.TEXT_AUTO_PUNCTUATE,
+ SEEMP_API_android_provider_Settings__put_TEXT_AUTO_PUNCTUATE_);
+ value_to_put_map.put(Settings.System.WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS,
+ SEEMP_API_android_provider_Settings__put_WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS_);
+ value_to_put_map.put(Settings.System.SCREEN_BRIGHTNESS_MODE,
+ SEEMP_API_android_provider_Settings__put_SCREEN_BRIGHTNESS_MODE_);
+ }
+
+ public static int getSeempPutApiIdFromValue( String v )
+ {
+ Integer result = value_to_put_map.get( v );
+ if (result == null)
+ {
+ result = -1;
+ }
+ return result;
+ }
+}
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index 1269ad9..7b2d299 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -778,6 +778,9 @@ public final class Display {
synchronized (this) {
updateDisplayInfoLocked();
mDisplayInfo.getAppMetrics(outMetrics, mDisplayAdjustments);
+ if (getDisplayId() == DEFAULT_DISPLAY) {
+ outMetrics.densityDpi = DisplayMetrics.DENSITY_DEVICE_DEFAULT;
+ }
}
}
diff --git a/core/java/android/view/DisplayInfo.java b/core/java/android/view/DisplayInfo.java
index ee76274..d43b962 100644
--- a/core/java/android/view/DisplayInfo.java
+++ b/core/java/android/view/DisplayInfo.java
@@ -564,6 +564,9 @@ public final class DisplayInfo implements Parcelable {
if (!compatInfo.equals(CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO)) {
compatInfo.applyToDisplayMetrics(outMetrics);
+ } else if (type == Display.TYPE_BUILT_IN
+ && (flags & Display.FLAG_PRESENTATION) == 0) {
+ outMetrics.setDensity(DisplayMetrics.DENSITY_PREFERRED);
}
}
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 5994d4f..55735c7 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -130,7 +130,7 @@ interface IWindowManager
boolean inKeyguardRestrictedInputMode();
void dismissKeyguard();
void keyguardGoingAway(boolean disableWindowAnimations,
- boolean keyguardGoingToNotificationShade);
+ boolean keyguardGoingToNotificationShade, boolean keyguardShowingMedia);
void closeSystemDialogs(String reason);
@@ -232,6 +232,16 @@ interface IWindowManager
Bitmap screenshotApplications(IBinder appToken, int displayId, int maxWidth, int maxHeight);
/**
+ * Get the current x offset for the wallpaper
+ */
+ int getLastWallpaperX();
+
+ /**
+ * Get the current y offset for the wallpaper
+ */
+ int getLastWallpaperY();
+
+ /**
* Called by the status bar to notify Views of changes to System UI visiblity.
*/
oneway void statusBarVisibilityChanged(int visibility);
@@ -240,6 +250,12 @@ interface IWindowManager
* Device has a software navigation bar (separate from the status bar).
*/
boolean hasNavigationBar();
+ boolean hasPermanentMenuKey();
+
+ /**
+ * Device needs a software navigation bar (because it has no hardware keys).
+ */
+ boolean needsNavigationBar();
/**
* Lock the device immediately with the specified options (can be null).
diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl
index 73b4a6e..3956237 100644
--- a/core/java/android/view/IWindowSession.aidl
+++ b/core/java/android/view/IWindowSession.aidl
@@ -185,6 +185,16 @@ interface IWindowSession {
*/
void setWallpaperDisplayOffset(IBinder windowToken, int x, int y);
+ /**
+ * Get the current x offset for the wallpaper
+ */
+ int getLastWallpaperX();
+
+ /**
+ * Get the current y offset for the wallpaper
+ */
+ int getLastWallpaperY();
+
Bundle sendWallpaperCommand(IBinder window, String action, int x, int y,
int z, in Bundle extras, boolean sync);
diff --git a/core/java/android/view/InputDevice.java b/core/java/android/view/InputDevice.java
index cc4598d..7642ed9 100644
--- a/core/java/android/view/InputDevice.java
+++ b/core/java/android/view/InputDevice.java
@@ -256,6 +256,18 @@ public final class InputDevice implements Parcelable {
public static final int SOURCE_TOUCH_NAVIGATION = 0x00200000 | SOURCE_CLASS_NONE;
/**
+ * The input source is a touch device whose motions should be interpreted as gestures.
+ *
+ * For example, an upward swipe should be treated the same as a swipe of the touchscreen.
+ * The same should apply for left, right, down swipes. Complex gestures may also be input.
+ *
+ * @see #SOURCE_CLASS_NONE
+ *
+ * @hide
+ */
+ public static final int SOURCE_GESTURE_SENSOR = 0x00400000 | SOURCE_CLASS_NONE;
+
+ /**
* The input source is a joystick.
* (It may also be a {@link #SOURCE_GAMEPAD}).
*
@@ -948,6 +960,7 @@ public final class InputDevice implements Parcelable {
appendSourceDescriptionIfApplicable(description, SOURCE_TOUCHPAD, "touchpad");
appendSourceDescriptionIfApplicable(description, SOURCE_JOYSTICK, "joystick");
appendSourceDescriptionIfApplicable(description, SOURCE_GAMEPAD, "gamepad");
+ appendSourceDescriptionIfApplicable(description, SOURCE_GESTURE_SENSOR, "gesture");
description.append(" )\n");
final int numAxes = mMotionRanges.size();
diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java
index a9bf92b..d5847be 100644
--- a/core/java/android/view/KeyEvent.java
+++ b/core/java/android/view/KeyEvent.java
@@ -1828,8 +1828,14 @@ public class KeyEvent extends InputEvent implements Parcelable {
switch (keyCode) {
case KeyEvent.KEYCODE_BACK:
case KeyEvent.KEYCODE_MENU:
+ case KeyEvent.KEYCODE_HOME:
case KeyEvent.KEYCODE_WAKEUP:
case KeyEvent.KEYCODE_PAIRING:
+ case KeyEvent.KEYCODE_VOLUME_UP:
+ case KeyEvent.KEYCODE_VOLUME_DOWN:
+ case KeyEvent.KEYCODE_VOLUME_MUTE:
+ case KeyEvent.KEYCODE_CAMERA:
+ case KeyEvent.KEYCODE_FOCUS:
return true;
}
return false;
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index bcf9b2c..e839468 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -58,6 +58,11 @@ public class SurfaceControl {
private static native void nativeSetWindowCrop(long nativeObject, int l, int t, int r, int b);
private static native void nativeSetLayerStack(long nativeObject, int layerStack);
+ private static native void nativeSetBlur(long nativeObject, float blur);
+ private static native void nativeSetBlurMaskSurface(long nativeObject, long maskLayerNativeObject);
+ private static native void nativeSetBlurMaskSampling(long nativeObject, int blurMaskSampling);
+ private static native void nativeSetBlurMaskAlphaThreshold(long nativeObject, float alpha);
+
private static native boolean nativeClearContentFrameStats(long nativeObject);
private static native boolean nativeGetContentFrameStats(long nativeObject, WindowContentFrameStats outStats);
private static native boolean nativeClearAnimationFrameStats();
@@ -170,6 +175,11 @@ public class SurfaceControl {
public static final int FX_SURFACE_NORMAL = 0x00000000;
/**
+ * Surface creation flag: Creates a blur surface.
+ */
+ public static final int FX_SURFACE_BLUR = 0x00010000;
+
+ /**
* Surface creation flag: Creates a Dim surface.
* Everything behind this surface is dimmed by the amount specified
* in {@link #setAlpha}. It is an error to lock a Dim surface, since it
@@ -215,6 +225,12 @@ public class SurfaceControl {
*/
public static final int BUILT_IN_DISPLAY_ID_HDMI = 1;
+ /**
+ * Built-in physical display id: Attached HDMI display.
+ * Use only with {@link SurfaceControl#getBuiltInDisplay(int)}.
+ */
+ public static final int BUILT_IN_DISPLAY_ID_TERTIARY = 2;
+
/* Display power modes * /
/**
@@ -378,6 +394,29 @@ public class SurfaceControl {
nativeSetSize(mNativeObject, w, h);
}
+ public void setBlur(float blur) {
+ checkNotReleased();
+ nativeSetBlur(mNativeObject, blur);
+ }
+
+ public void setBlurMaskSurface(SurfaceControl maskSurface) {
+ checkNotReleased();
+ if (maskSurface != null) {
+ maskSurface.checkNotReleased();
+ }
+ nativeSetBlurMaskSurface(mNativeObject, maskSurface == null ? 0:maskSurface.mNativeObject);
+ }
+
+ public void setBlurMaskSampling(int blurMaskSampling) {
+ checkNotReleased();
+ nativeSetBlurMaskSampling(mNativeObject, blurMaskSampling);
+ }
+
+ public void setBlurMaskAlphaThreshold(float alpha) {
+ checkNotReleased();
+ nativeSetBlurMaskAlphaThreshold(mNativeObject, alpha);
+ }
+
public void hide() {
checkNotReleased();
nativeSetFlags(mNativeObject, SURFACE_HIDDEN, SURFACE_HIDDEN);
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index dea004e..93345c2 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -9284,6 +9284,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
final int actionMasked = event.getActionMasked();
if (actionMasked == MotionEvent.ACTION_DOWN) {
+ android.util.SeempLog.record(3);
// Defensive cleanup for new gesture
stopNestedScroll();
}
@@ -9828,6 +9829,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @param event The KeyEvent object that defines the button action.
*/
public boolean onKeyDown(int keyCode, KeyEvent event) {
+ android.util.SeempLog.record(4);
boolean result = false;
if (KeyEvent.isConfirmKey(keyCode)) {
@@ -9872,6 +9874,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @param event The KeyEvent object that defines the button action.
*/
public boolean onKeyUp(int keyCode, KeyEvent event) {
+ android.util.SeempLog.record(5);
if (KeyEvent.isConfirmKey(keyCode)) {
if ((mViewFlags & ENABLED_MASK) == DISABLED) {
return true;
@@ -10269,6 +10272,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @return True if the event was handled, false otherwise.
*/
public boolean onTouchEvent(MotionEvent event) {
+ android.util.SeempLog.record(3);
final float x = event.getX();
final float y = event.getY();
final int viewFlags = mViewFlags;
@@ -15940,8 +15944,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
RenderNode renderNode = null;
Bitmap cache = null;
int layerType = getLayerType(); // TODO: signify cache state with just 'cache' local
- if (layerType == LAYER_TYPE_SOFTWARE
- || (!drawingWithRenderNode && layerType != LAYER_TYPE_NONE)) {
+ if (!drawingWithRenderNode && layerType != LAYER_TYPE_NONE) {
// If not drawing with RenderNode, treat HW layers as SW
layerType = LAYER_TYPE_SOFTWARE;
buildDrawingCache(true);
@@ -21717,7 +21720,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
/**
* Last global system UI visibility reported by the window manager.
*/
- int mGlobalSystemUiVisibility;
+ int mGlobalSystemUiVisibility = -1;
/**
* True if a view in this hierarchy has an OnSystemUiVisibilityChangeListener
diff --git a/core/java/android/view/ViewConfiguration.java b/core/java/android/view/ViewConfiguration.java
index 4d584a3..93f5779 100644
--- a/core/java/android/view/ViewConfiguration.java
+++ b/core/java/android/view/ViewConfiguration.java
@@ -317,7 +317,7 @@ public class ViewConfiguration {
case HAS_PERMANENT_MENU_KEY_AUTODETECT: {
IWindowManager wm = WindowManagerGlobal.getWindowManagerService();
try {
- sHasPermanentMenuKey = !wm.hasNavigationBar();
+ sHasPermanentMenuKey = wm.hasPermanentMenuKey();
sHasPermanentMenuKeySet = true;
} catch (RemoteException ex) {
sHasPermanentMenuKey = false;
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index c222a82..3616622 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -199,6 +199,7 @@ public abstract class Window {
private boolean mHaveWindowFormat = false;
private boolean mHaveDimAmount = false;
+ private boolean mHaveBlurAmount = false;
private int mDefaultWindowFormat = PixelFormat.OPAQUE;
private boolean mHasSoftInputMode = false;
@@ -818,6 +819,13 @@ public abstract class Window {
setPrivateFlags(flags, flags);
}
+ /** @hide */
+ public void setBlurMaskAlphaThreshold(float alpha) {
+ final WindowManager.LayoutParams attrs = getAttributes();
+ attrs.blurMaskAlphaThreshold = alpha;
+ dispatchWindowAttributesChanged(attrs);
+ }
+
/**
* Convenience function to clear the flag bits as specified in flags, as
* per {@link #setFlags}.
@@ -829,6 +837,11 @@ public abstract class Window {
setFlags(0, flags);
}
+ /** @hide */
+ public void clearPrivateFlags(int flags) {
+ setPrivateFlags(0, flags);
+ }
+
/**
* Set the flags of the window, as per the
* {@link WindowManager.LayoutParams WindowManager.LayoutParams}
@@ -856,6 +869,10 @@ public abstract class Window {
}
private void setPrivateFlags(int flags, int mask) {
+ if ((flags & mask & WindowManager.LayoutParams.PRIVATE_FLAG_PREVENT_POWER_KEY) != 0){
+ mContext.enforceCallingOrSelfPermission("android.permission.PREVENT_POWER_KEY",
+ "No permission to prevent power key");
+ }
final WindowManager.LayoutParams attrs = getAttributes();
attrs.privateFlags = (attrs.privateFlags & ~mask) | (flags & mask);
dispatchWindowAttributesChanged(attrs);
@@ -895,6 +912,19 @@ public abstract class Window {
}
/**
+ * Set the amount of blur behind the window when using
+ * {@link WindowManager.LayoutParams#FLAG_BLUR_BEHIND}.
+ * This feature may not be supported by all devices.
+ * {@hide}
+ */
+ public void setBlurAmount(float amount) {
+ final WindowManager.LayoutParams attrs = getAttributes();
+ attrs.blurAmount = amount;
+ mHaveBlurAmount = true;
+ dispatchWindowAttributesChanged(attrs);
+ }
+
+ /**
* Specify custom window attributes. <strong>PLEASE NOTE:</strong> the
* layout params you give here should generally be from values previously
* retrieved with {@link #getAttributes()}; you probably do not want to
@@ -1404,6 +1434,11 @@ public abstract class Window {
return mHaveDimAmount;
}
+ /** @hide */
+ protected boolean haveBlurAmount() {
+ return mHaveBlurAmount;
+ }
+
public abstract void setChildDrawable(int featureId, Drawable drawable);
public abstract void setChildInt(int featureId, int value);
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 45bc1df..3ff8844 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -1128,6 +1128,42 @@ public interface WindowManager extends ViewManager {
public static final int PRIVATE_FLAG_FORCE_STATUS_BAR_VISIBLE_TRANSPARENT = 0x00001000;
/**
+ * {@hide}
+ */
+ public static final int PRIVATE_FLAG_STATUS_HIDE_FORCED = 0x00800000;
+
+ /**
+ * {@hide}
+ */
+ public static final int PRIVATE_FLAG_NAV_HIDE_FORCED = 0x01000000;
+
+ /**
+ * The window had not set FULLSCREEN flag so don't handle it as fullscreen in layoutWindowLw
+ *
+ * {@hide}
+ */
+ public static final int PRIVATE_FLAG_WAS_NOT_FULLSCREEN = 0x02000000;
+
+ /**
+ * Window flag: Overrides default power key behavior
+ * {@hide}
+ */
+ public static final int PRIVATE_FLAG_PREVENT_POWER_KEY = 0x20000000;
+
+ /**
+ * Window flag: adding additional blur layer and set this as masking layer
+ * {@hide}
+ */
+ public static final int PRIVATE_FLAG_BLUR_WITH_MASKING = 0x40000000;
+
+ /**
+ * Window flag: adding additional blur layer and set this as masking layer.
+ * This is faster and ugglier than non-scaled version.
+ * {@hide}
+ */
+ public static final int PRIVATE_FLAG_BLUR_WITH_MASKING_SCALED = 0x80000000;
+
+ /**
* Control flags that are private to the platform.
* @hide
*/
@@ -1389,6 +1425,15 @@ public interface WindowManager extends ViewManager {
public float dimAmount = 1.0f;
/**
+ * When {@link #FLAG_BLUR_BEHIND} is set, this is the amount of blur
+ * to apply. Range is from 1.0 for maximum to 0.0 for no
+ * blur.
+ * @hide
+ */
+ public float blurAmount = 1.0f;
+
+
+ /**
* Default value for {@link #screenBrightness} and {@link #buttonBrightness}
* indicating that the brightness value is not overridden for this window
* and normal brightness policy should be used.
@@ -1581,6 +1626,14 @@ public interface WindowManager extends ViewManager {
*/
public long userActivityTimeout = -1;
+ /**
+ * Threshold value that blur masking layer uses to determine whether
+ * to use or discard the blurred color.
+ * Value should be between 0.0 and 1.0
+ * @hide
+ */
+ public float blurMaskAlphaThreshold = 0.0f;
+
public LayoutParams() {
super(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
type = TYPE_APPLICATION;
@@ -1667,6 +1720,7 @@ public interface WindowManager extends ViewManager {
out.writeInt(windowAnimations);
out.writeFloat(alpha);
out.writeFloat(dimAmount);
+ out.writeFloat(blurAmount);
out.writeFloat(screenBrightness);
out.writeFloat(buttonBrightness);
out.writeInt(rotationAnimation);
@@ -1687,6 +1741,7 @@ public interface WindowManager extends ViewManager {
out.writeInt(surfaceInsets.bottom);
out.writeInt(hasManualSurfaceInsets ? 1 : 0);
out.writeInt(needsMenuKey);
+ out.writeFloat(blurMaskAlphaThreshold);
}
public static final Parcelable.Creator<LayoutParams> CREATOR
@@ -1717,6 +1772,7 @@ public interface WindowManager extends ViewManager {
windowAnimations = in.readInt();
alpha = in.readFloat();
dimAmount = in.readFloat();
+ blurAmount = in.readFloat();
screenBrightness = in.readFloat();
buttonBrightness = in.readFloat();
rotationAnimation = in.readInt();
@@ -1737,6 +1793,7 @@ public interface WindowManager extends ViewManager {
surfaceInsets.bottom = in.readInt();
hasManualSurfaceInsets = in.readInt() != 0;
needsMenuKey = in.readInt();
+ blurMaskAlphaThreshold = in.readFloat();
}
@SuppressWarnings({"PointlessBitwiseExpression"})
@@ -1776,6 +1833,10 @@ public interface WindowManager extends ViewManager {
/** {@hide} */
public static final int PREFERRED_DISPLAY_MODE_ID = 1 << 23;
/** {@hide} */
+ public static final int BLUR_AMOUNT_CHANGED = 1 << 29;
+ /** {@hide} */
+ public static final int BLUR_MASK_ALPHA_THRESHOLD_CHANGED = 1 << 30;
+ /** {@hide} */
public static final int EVERYTHING_CHANGED = 0xffffffff;
// internal buffer to backup/restore parameters under compatibility mode.
@@ -1870,6 +1931,10 @@ public interface WindowManager extends ViewManager {
dimAmount = o.dimAmount;
changes |= DIM_AMOUNT_CHANGED;
}
+ if (blurAmount != o.blurAmount) {
+ blurAmount = o.blurAmount;
+ changes |= BLUR_AMOUNT_CHANGED;
+ }
if (screenBrightness != o.screenBrightness) {
screenBrightness = o.screenBrightness;
changes |= SCREEN_BRIGHTNESS_CHANGED;
@@ -1935,6 +2000,11 @@ public interface WindowManager extends ViewManager {
changes |= NEEDS_MENU_KEY_CHANGED;
}
+ if (blurMaskAlphaThreshold != o.blurMaskAlphaThreshold) {
+ blurMaskAlphaThreshold = o.blurMaskAlphaThreshold;
+ changes |= BLUR_MASK_ALPHA_THRESHOLD_CHANGED;
+ }
+
return changes;
}
diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java
index 98e9f54..95e291c 100644
--- a/core/java/android/view/WindowManagerImpl.java
+++ b/core/java/android/view/WindowManagerImpl.java
@@ -81,12 +81,14 @@ public final class WindowManagerImpl implements WindowManager {
@Override
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
+ android.util.SeempLog.record_vg_layout(383,params);
applyDefaultToken(params);
mGlobal.addView(view, params, mDisplay, mParentWindow);
}
@Override
public void updateViewLayout(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
+ android.util.SeempLog.record_vg_layout(384,params);
applyDefaultToken(params);
mGlobal.updateViewLayout(view, params);
}
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index aaf6052..a962f2a 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -453,6 +453,8 @@ public interface WindowManagerPolicy {
/** Unregister a system listener for touch events */
void unregisterPointerEventListener(PointerEventListener listener);
+
+ void addSystemUIVisibilityFlag(int flags);
}
public interface PointerEventListener {
@@ -778,7 +780,8 @@ public interface WindowManagerPolicy {
* Create and return an animation to let the wallpaper disappear after being shown on a force
* hiding window.
*/
- public Animation createForceHideWallpaperExitAnimation(boolean goingToNotificationShade);
+ public Animation createForceHideWallpaperExitAnimation(boolean goingToNotificationShade,
+ boolean keyguardShowingMedia);
/**
* Called from the input reader thread before a key is enqueued.
@@ -1237,6 +1240,12 @@ public interface WindowManagerPolicy {
* Specifies whether there is an on-screen navigation bar separate from the status bar.
*/
public boolean hasNavigationBar();
+ public boolean hasPermanentMenuKey();
+
+ /**
+ * Specifies whether the device needs a navigation bar (because it has no hardware buttons)
+ */
+ public boolean needsNavigationBar();
/**
* Lock the device now.
diff --git a/core/java/android/view/WindowManagerPolicyControl.java b/core/java/android/view/WindowManagerPolicyControl.java
new file mode 100644
index 0000000..cdba239
--- /dev/null
+++ b/core/java/android/view/WindowManagerPolicyControl.java
@@ -0,0 +1,451 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+import android.app.ActivityManager;
+import android.content.Context;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.util.ArraySet;
+import android.util.Slog;
+import android.view.WindowManager.LayoutParams;
+import android.view.WindowManagerPolicy.WindowState;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.Iterator;
+
+/**
+ * Runtime adjustments applied to the global window policy.
+ *
+ * This includes forcing immersive mode behavior for one or both system bars (based on a package
+ * list) and permanently disabling immersive mode confirmations for specific packages.
+ *
+ * Control by setting {@link Settings.Global.POLICY_CONTROL} to one or more name-value pairs.
+ * e.g.
+ * to force immersive mode everywhere:
+ * "immersive.full=*"
+ * to force transient status for all apps except a specific package:
+ * "immersive.status=apps,-com.package"
+ * to disable the immersive mode confirmations for specific packages:
+ * "immersive.preconfirms=com.package.one,com.package.two"
+ *
+ * Separate multiple name-value pairs with ':'
+ * e.g. "immersive.status=apps:immersive.preconfirms=*"
+ *
+ * @hide
+ */
+public class WindowManagerPolicyControl {
+ private static String TAG = "PolicyControl";
+ private static boolean DEBUG = false;
+
+ private static final String NAME_IMMERSIVE_FULL = "immersive.full";
+ private static final String NAME_IMMERSIVE_STATUS = "immersive.status";
+ private static final String NAME_IMMERSIVE_NAVIGATION = "immersive.navigation";
+ private static final String NAME_IMMERSIVE_PRECONFIRMATIONS = "immersive.preconfirms";
+
+ private static int sDefaultImmersiveStyle;
+ private static String sSettingValue;
+ private static Filter sImmersivePreconfirmationsFilter;
+ private static Filter sImmersiveStatusFilter;
+ private static Filter sImmersiveNavigationFilter;
+
+ /**
+ * Accessible constants for Settings
+ */
+ public final static class ImmersiveDefaultStyles {
+ public final static int IMMERSIVE_FULL = 0;
+ public final static int IMMERSIVE_STATUS = 1;
+ public final static int IMMERSIVE_NAVIGATION = 2;
+ }
+
+ public static int getSystemUiVisibility(WindowState win, LayoutParams attrs) {
+ attrs = attrs != null ? attrs : win.getAttrs();
+ int vis = win != null ? win.getSystemUiVisibility() : attrs.systemUiVisibility;
+ if (sImmersiveStatusFilter != null && sImmersiveStatusFilter.matches(attrs)
+ && (sDefaultImmersiveStyle == ImmersiveDefaultStyles.IMMERSIVE_FULL ||
+ sDefaultImmersiveStyle == ImmersiveDefaultStyles.IMMERSIVE_STATUS)) {
+ vis |= View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
+ | View.SYSTEM_UI_FLAG_FULLSCREEN
+ | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
+ vis &= ~(View.SYSTEM_UI_FLAG_LAYOUT_STABLE
+ | View.STATUS_BAR_TRANSLUCENT);
+ }
+ if (sImmersiveNavigationFilter != null && sImmersiveNavigationFilter.matches(attrs)
+ && (sDefaultImmersiveStyle == ImmersiveDefaultStyles.IMMERSIVE_FULL ||
+ sDefaultImmersiveStyle == ImmersiveDefaultStyles.IMMERSIVE_NAVIGATION)) {
+ vis |= View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
+ | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
+ | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
+ vis &= ~(View.SYSTEM_UI_FLAG_LAYOUT_STABLE
+ | View.NAVIGATION_BAR_TRANSLUCENT);
+ }
+ return vis;
+ }
+
+ public static int getWindowFlags(WindowState win, LayoutParams attrs) {
+ attrs = attrs != null ? attrs : win.getAttrs();
+ int flags = attrs.flags;
+
+ if (sImmersiveStatusFilter != null && sImmersiveStatusFilter.matches(attrs)
+ && (sDefaultImmersiveStyle == ImmersiveDefaultStyles.IMMERSIVE_FULL ||
+ sDefaultImmersiveStyle == ImmersiveDefaultStyles.IMMERSIVE_STATUS)) {
+ flags |= WindowManager.LayoutParams.FLAG_FULLSCREEN;
+ flags &= ~(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS
+ | WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
+ }
+ if (sImmersiveNavigationFilter != null && sImmersiveNavigationFilter.matches(attrs)
+ && (sDefaultImmersiveStyle == ImmersiveDefaultStyles.IMMERSIVE_FULL ||
+ sDefaultImmersiveStyle == ImmersiveDefaultStyles.IMMERSIVE_NAVIGATION)) {
+ flags &= ~WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION;
+ }
+ return flags;
+ }
+
+ public static int getPrivateWindowFlags(WindowState win, LayoutParams attrs) {
+ attrs = attrs != null ? attrs : win.getAttrs();
+ int privateFlags = attrs.privateFlags;
+
+ if (sImmersiveStatusFilter != null && sImmersiveNavigationFilter != null &&
+ sImmersiveStatusFilter.isEnabledForAll()
+ && sImmersiveNavigationFilter.isEnabledForAll()) {
+
+ if ((attrs.flags & LayoutParams.FLAG_FULLSCREEN) == 0) {
+ privateFlags |= LayoutParams.PRIVATE_FLAG_WAS_NOT_FULLSCREEN;
+ }
+
+ switch (sDefaultImmersiveStyle) {
+ case ImmersiveDefaultStyles.IMMERSIVE_FULL:
+ privateFlags |= LayoutParams.PRIVATE_FLAG_NAV_HIDE_FORCED;
+ privateFlags |= LayoutParams.PRIVATE_FLAG_STATUS_HIDE_FORCED;
+ return privateFlags;
+ case ImmersiveDefaultStyles.IMMERSIVE_STATUS:
+ privateFlags |= LayoutParams.PRIVATE_FLAG_STATUS_HIDE_FORCED;
+ return privateFlags;
+ case ImmersiveDefaultStyles.IMMERSIVE_NAVIGATION:
+ privateFlags |= LayoutParams.PRIVATE_FLAG_NAV_HIDE_FORCED;
+ return privateFlags;
+ }
+ }
+
+ if (sImmersiveStatusFilter != null && sImmersiveStatusFilter.matches(attrs)) {
+ if ((attrs.flags & LayoutParams.FLAG_FULLSCREEN) == 0) {
+ privateFlags |= LayoutParams.PRIVATE_FLAG_WAS_NOT_FULLSCREEN;
+ }
+ privateFlags |= LayoutParams.PRIVATE_FLAG_STATUS_HIDE_FORCED;
+ }
+
+ if (sImmersiveNavigationFilter != null && sImmersiveNavigationFilter.matches(attrs)) {
+ privateFlags |= LayoutParams.PRIVATE_FLAG_NAV_HIDE_FORCED;
+ }
+
+ return privateFlags;
+ }
+
+ public static boolean immersiveStatusFilterMatches(String packageName) {
+ return sImmersiveStatusFilter != null && sImmersiveStatusFilter.matches(packageName);
+ }
+
+ public static boolean immersiveNavigationFilterMatches(String packageName) {
+ return sImmersiveNavigationFilter != null
+ && sImmersiveNavigationFilter.matches(packageName);
+ }
+
+ public static int adjustClearableFlags(WindowState win, int clearableFlags) {
+ final LayoutParams attrs = win != null ? win.getAttrs() : null;
+ if (sImmersiveStatusFilter != null && sImmersiveStatusFilter.matches(attrs)) {
+ clearableFlags &= ~View.SYSTEM_UI_FLAG_FULLSCREEN;
+ }
+ return clearableFlags;
+ }
+
+ public static boolean disableImmersiveConfirmation(String pkg) {
+ return (sImmersivePreconfirmationsFilter != null
+ && sImmersivePreconfirmationsFilter.matches(pkg))
+ || ActivityManager.isRunningInTestHarness();
+ }
+
+ public static void reloadFromSetting(Context context) {
+ reloadStyleFromSetting(context, Settings.Global.POLICY_CONTROL_STYLE);
+ reloadFromSetting(context, Settings.Global.POLICY_CONTROL);
+ }
+
+ public static void reloadFromSetting(Context context, String key) {
+ if (DEBUG) Slog.d(TAG, "reloadFromSetting()");
+ String value = null;
+ try {
+ value = Settings.Global.getStringForUser(context.getContentResolver(),
+ key,
+ UserHandle.USER_CURRENT);
+ if (sSettingValue != null && sSettingValue.equals(value)) return;
+ setFilters(value);
+ sSettingValue = value;
+ } catch (Throwable t) {
+ Slog.w(TAG, "Error loading policy control, value=" + value, t);
+ }
+ }
+
+ public static void reloadStyleFromSetting(Context context, String key) {
+ sDefaultImmersiveStyle = Settings.Global.getInt(context.getContentResolver(),
+ key, WindowManagerPolicyControl.ImmersiveDefaultStyles.IMMERSIVE_FULL);
+ if (DEBUG) Slog.d(TAG, "reloadStyleFromSetting " + sDefaultImmersiveStyle);
+ }
+
+ public static void saveToSettings(Context context) {
+ saveToSettings(context, Settings.Global.POLICY_CONTROL);
+ }
+
+ public static void saveToSettings(Context context, String key) {
+ StringBuilder value = new StringBuilder();
+ boolean needSemicolon = false;
+ if (sImmersiveStatusFilter != null) {
+ writeFilter(NAME_IMMERSIVE_STATUS, sImmersiveStatusFilter, value);
+ needSemicolon = true;
+ }
+ if (sImmersiveNavigationFilter != null) {
+ if (needSemicolon) {
+ value.append(":");
+ }
+ writeFilter(NAME_IMMERSIVE_NAVIGATION, sImmersiveNavigationFilter, value);
+ }
+
+ Settings.Global.putString(context.getContentResolver(), key, value.toString());
+ }
+
+ public static void saveStyleToSettings(Context context, int value) {
+ Settings.Global.putInt(context.getContentResolver(),
+ Settings.Global.POLICY_CONTROL_STYLE, value);
+ sDefaultImmersiveStyle = value;
+ }
+
+ public static void addToStatusWhiteList(String packageName) {
+ if (sImmersiveStatusFilter == null) {
+ sImmersiveStatusFilter = new Filter(new ArraySet<String>(), new ArraySet<String>());
+ }
+
+ if (!sImmersiveStatusFilter.mWhitelist.contains(packageName)) {
+ sImmersiveStatusFilter.mWhitelist.add(packageName);
+ }
+ }
+
+ public static void addToNavigationWhiteList(String packageName) {
+ if (sImmersiveNavigationFilter == null) {
+ sImmersiveNavigationFilter = new Filter(new ArraySet<String>(), new ArraySet<String>());
+ }
+
+ if (!sImmersiveNavigationFilter.mWhitelist.contains(packageName)) {
+ sImmersiveNavigationFilter.mWhitelist.add(packageName);
+ }
+ }
+
+ public static void removeFromWhiteLists(String packageName) {
+ if (sImmersiveStatusFilter != null) {
+ sImmersiveStatusFilter.mWhitelist.remove(packageName);
+ }
+ if (sImmersiveNavigationFilter != null) {
+ sImmersiveNavigationFilter.mWhitelist.remove(packageName);
+ }
+ }
+
+ public static ArraySet<String> getWhiteLists() {
+ ArraySet<String> result = new ArraySet<>();
+
+ if (sImmersiveStatusFilter != null) {
+ result.addAll(sImmersiveStatusFilter.mWhitelist);
+ }
+ if (sImmersiveNavigationFilter != null
+ && sImmersiveNavigationFilter != sImmersiveStatusFilter) {
+ result.addAll(sImmersiveNavigationFilter.mWhitelist);
+ }
+
+ return result;
+ }
+
+ private static void writeFilter(String name, Filter filter, StringBuilder stringBuilder) {
+ if (filter.mWhitelist.isEmpty() && filter.mBlacklist.isEmpty()) {
+ return;
+ }
+ stringBuilder.append(name);
+ stringBuilder.append("=");
+
+ boolean needComma = false;
+ if (!filter.mWhitelist.isEmpty()) {
+ writePackages(filter.mWhitelist, stringBuilder, false);
+ needComma = true;
+ }
+ if (!filter.mBlacklist.isEmpty()) {
+ if (needComma) {
+ stringBuilder.append(",");
+ }
+ writePackages(filter.mBlacklist, stringBuilder, true);
+ }
+ }
+
+ private static void writePackages(ArraySet<String> set, StringBuilder stringBuilder,
+ boolean isBlackList) {
+ Iterator<String> iterator = set.iterator();
+ while (iterator.hasNext()) {
+ if (isBlackList) {
+ stringBuilder.append("-");
+ }
+ String name = iterator.next();
+ stringBuilder.append(name);
+ if (iterator.hasNext()) {
+ stringBuilder.append(",");
+ }
+ }
+ }
+
+ public static boolean isImmersiveFiltersActive() {
+ return sImmersiveStatusFilter != null || sImmersiveNavigationFilter != null;
+ }
+
+ public static void dump(String prefix, PrintWriter pw) {
+ dump("sImmersiveStatusFilter", sImmersiveStatusFilter, prefix, pw);
+ dump("sImmersiveNavigationFilter", sImmersiveNavigationFilter, prefix, pw);
+ dump("sImmersivePreconfirmationsFilter", sImmersivePreconfirmationsFilter, prefix, pw);
+ }
+
+ private static void dump(String name, Filter filter, String prefix, PrintWriter pw) {
+ pw.print(prefix); pw.print("PolicyControl."); pw.print(name); pw.print('=');
+ if (filter == null) {
+ pw.println("null");
+ } else {
+ filter.dump(pw); pw.println();
+ }
+ }
+
+ private static void setFilters(String value) {
+ if (DEBUG) Slog.d(TAG, "setFilters: " + value);
+ sImmersiveStatusFilter = null;
+ sImmersiveNavigationFilter = null;
+ sImmersivePreconfirmationsFilter = null;
+ if (value != null) {
+ String[] nvps = value.split(":");
+ for (String nvp : nvps) {
+ int i = nvp.indexOf('=');
+ if (i == -1) continue;
+ String n = nvp.substring(0, i);
+ String v = nvp.substring(i + 1);
+ if (n.equals(NAME_IMMERSIVE_FULL)) {
+ Filter f = Filter.parse(v);
+ sImmersiveStatusFilter = sImmersiveNavigationFilter = f;
+ if (sImmersivePreconfirmationsFilter == null) {
+ sImmersivePreconfirmationsFilter = f;
+ }
+ } else if (n.equals(NAME_IMMERSIVE_STATUS)) {
+ Filter f = Filter.parse(v);
+ sImmersiveStatusFilter = f;
+ } else if (n.equals(NAME_IMMERSIVE_NAVIGATION)) {
+ Filter f = Filter.parse(v);
+ sImmersiveNavigationFilter = f;
+ if (sImmersivePreconfirmationsFilter == null) {
+ sImmersivePreconfirmationsFilter = f;
+ }
+ } else if (n.equals(NAME_IMMERSIVE_PRECONFIRMATIONS)) {
+ Filter f = Filter.parse(v);
+ sImmersivePreconfirmationsFilter = f;
+ }
+ }
+ }
+ if (DEBUG) {
+ Slog.d(TAG, "immersiveStatusFilter: " + sImmersiveStatusFilter);
+ Slog.d(TAG, "immersiveNavigationFilter: " + sImmersiveNavigationFilter);
+ Slog.d(TAG, "immersivePreconfirmationsFilter: " + sImmersivePreconfirmationsFilter);
+ }
+ }
+
+ private static class Filter {
+ private static final String ALL = "*";
+ private static final String APPS = "apps";
+
+ private final ArraySet<String> mWhitelist;
+ private final ArraySet<String> mBlacklist;
+
+ private Filter(ArraySet<String> whitelist, ArraySet<String> blacklist) {
+ mWhitelist = whitelist;
+ mBlacklist = blacklist;
+ }
+
+ boolean matches(LayoutParams attrs) {
+ if (attrs == null) return false;
+ boolean isApp = attrs.type >= WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW
+ && attrs.type <= WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
+ if (isApp && mBlacklist.contains(APPS)) return false;
+ if (onBlacklist(attrs.packageName)) return false;
+ if (isApp && mWhitelist.contains(APPS)) return true;
+ return onWhitelist(attrs.packageName);
+ }
+
+ boolean matches(String packageName) {
+ return !onBlacklist(packageName) && onWhitelist(packageName);
+ }
+
+ public boolean isEnabledForAll() {
+ return mWhitelist.contains(ALL);
+ }
+
+ private boolean onBlacklist(String packageName) {
+ return mBlacklist.contains(packageName) || mBlacklist.contains(ALL);
+ }
+
+ private boolean onWhitelist(String packageName) {
+ return mWhitelist.contains(ALL) || mWhitelist.contains(packageName);
+ }
+
+ void dump(PrintWriter pw) {
+ pw.print("Filter[");
+ dump("whitelist", mWhitelist, pw); pw.print(',');
+ dump("blacklist", mBlacklist, pw); pw.print(']');
+ }
+
+ private void dump(String name, ArraySet<String> set, PrintWriter pw) {
+ pw.print(name); pw.print("=(");
+ final int n = set.size();
+ for (int i = 0; i < n; i++) {
+ if (i > 0) pw.print(',');
+ pw.print(set.valueAt(i));
+ }
+ pw.print(')');
+ }
+
+ @Override
+ public String toString() {
+ StringWriter sw = new StringWriter();
+ dump(new PrintWriter(sw, true));
+ return sw.toString();
+ }
+
+ // value = comma-delimited list of tokens, where token = (package name|apps|*)
+ // e.g. "com.package1", or "apps, com.android.keyguard" or "*"
+ static Filter parse(String value) {
+ if (value == null) return null;
+ ArraySet<String> whitelist = new ArraySet<String>();
+ ArraySet<String> blacklist = new ArraySet<String>();
+ for (String token : value.split(",")) {
+ token = token.trim();
+ if (token.startsWith("-") && token.length() > 1) {
+ token = token.substring(1);
+ blacklist.add(token);
+ } else {
+ whitelist.add(token);
+ }
+ }
+ return new Filter(whitelist, blacklist);
+ }
+ }
+}
diff --git a/core/java/android/webkit/WebChromeClient.java b/core/java/android/webkit/WebChromeClient.java
index 4737e9b..01fcc1a 100644
--- a/core/java/android/webkit/WebChromeClient.java
+++ b/core/java/android/webkit/WebChromeClient.java
@@ -290,7 +290,9 @@ public class WebChromeClient {
* origin.
*/
public void onGeolocationPermissionsShowPrompt(String origin,
- GeolocationPermissions.Callback callback) {}
+ GeolocationPermissions.Callback callback) {
+ android.util.SeempLog.record(54);
+ }
/**
* Notify the host application that a request for Geolocation permissions,
diff --git a/core/java/android/webkit/WebViewFactory.java b/core/java/android/webkit/WebViewFactory.java
index 584deff..93b1e56 100644
--- a/core/java/android/webkit/WebViewFactory.java
+++ b/core/java/android/webkit/WebViewFactory.java
@@ -97,7 +97,14 @@ public final class WebViewFactory {
}
public static String getWebViewPackageName() {
- return AppGlobals.getInitialApplication().getString(
+ Application initialApp = AppGlobals.getInitialApplication();
+ String pkg = initialApp.getString(
+ com.android.internal.R.string.config_alternateWebViewPackageName);
+ /* Attempt to use alternate WebView package first */
+ if (isPackageInstalled(initialApp, pkg)) {
+ return pkg;
+ }
+ return initialApp.getString(
com.android.internal.R.string.config_webViewPackageName);
}
@@ -529,6 +536,14 @@ public final class WebViewFactory {
return IWebViewUpdateService.Stub.asInterface(ServiceManager.getService("webviewupdate"));
}
+ private static boolean isPackageInstalled(Context context, String packageName) {
+ try {
+ return context.getPackageManager().getPackageInfo(packageName, 0) != null;
+ } catch (PackageManager.NameNotFoundException e) {
+ return false;
+ }
+ }
+
private static native boolean nativeReserveAddressSpace(long addressSpaceToReserve);
private static native boolean nativeCreateRelroFile(String lib32, String lib64,
String relro32, String relro64);
diff --git a/core/java/android/widget/AbsSeekBar.java b/core/java/android/widget/AbsSeekBar.java
index a4c8d1c..31bc536 100644
--- a/core/java/android/widget/AbsSeekBar.java
+++ b/core/java/android/widget/AbsSeekBar.java
@@ -663,7 +663,14 @@ public abstract class AbsSeekBar extends ProgressBar {
progress += scale * max;
setHotspot(x, (int) event.getY());
- setProgress((int) progress, true);
+ setProgress(updateTouchProgress(getProgress(), (int) progress), true);
+ }
+
+ /**
+ * @hide
+ */
+ protected int updateTouchProgress(int lastProgress, int newProgress) {
+ return newProgress;
}
/**
diff --git a/core/java/android/widget/FastScroller.java b/core/java/android/widget/FastScroller.java
index c40289e..559181b 100644
--- a/core/java/android/widget/FastScroller.java
+++ b/core/java/android/widget/FastScroller.java
@@ -383,6 +383,7 @@ class FastScroller {
break;
}
}
+ ta.recycle();
updateAppearance();
}
diff --git a/core/java/android/widget/OverScroller.java b/core/java/android/widget/OverScroller.java
index 50569d7..9130d9a 100644
--- a/core/java/android/widget/OverScroller.java
+++ b/core/java/android/widget/OverScroller.java
@@ -18,6 +18,7 @@ package android.widget;
import android.content.Context;
import android.hardware.SensorManager;
+import android.os.PowerManager;
import android.util.Log;
import android.view.ViewConfiguration;
import android.view.animation.AnimationUtils;
@@ -599,6 +600,8 @@ public class OverScroller {
private static final int CUBIC = 1;
private static final int BALLISTIC = 2;
+ private final PowerManager mPm;
+
static {
float x_min = 0.0f;
float y_min = 0.0f;
@@ -643,6 +646,7 @@ public class OverScroller {
* 39.37f // inch/meter
* ppi
* 0.84f; // look and feel tuning
+ mPm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
}
void updateScroll(float q) {
@@ -760,6 +764,7 @@ public class OverScroller {
if (velocity != 0) {
mDuration = mSplineDuration = getSplineFlingDuration(velocity);
totalDistance = getSplineFlingDistance(velocity);
+ mPm.cpuBoost(mDuration * 1000);
}
mSplineDistance = (int) (totalDistance * Math.signum(velocity));
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 7ca3339..e9ae071 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -2729,6 +2729,12 @@ public class RemoteViews implements Parcelable, Filter {
/** @hide */
public View apply(Context context, ViewGroup parent, OnClickHandler handler) {
+ return apply(context, parent, handler, null);
+ }
+
+ /** @hide */
+ public View apply(Context context, ViewGroup parent, OnClickHandler handler,
+ String themePackageName) {
RemoteViews rvToApply = getRemoteViewsToApply(context);
View result;
@@ -2736,7 +2742,7 @@ public class RemoteViews implements Parcelable, Filter {
// user. So build a context that loads resources from that user but
// still returns the current users userId so settings like data / time formats
// are loaded without requiring cross user persmissions.
- final Context contextForResources = getContextForResources(context);
+ final Context contextForResources = getContextForResources(context, themePackageName);
Context inflationContext = new ContextWrapper(context) {
@Override
public Resources getResources() {
@@ -2806,14 +2812,14 @@ public class RemoteViews implements Parcelable, Filter {
}
}
- private Context getContextForResources(Context context) {
+ private Context getContextForResources(Context context, String themePackageName) {
if (mApplication != null) {
if (context.getUserId() == UserHandle.getUserId(mApplication.uid)
&& context.getPackageName().equals(mApplication.packageName)) {
return context;
}
try {
- return context.createApplicationContext(mApplication,
+ return context.createApplicationContext(mApplication, themePackageName,
Context.CONTEXT_RESTRICTED);
} catch (NameNotFoundException e) {
Log.e(LOG_TAG, "Package name " + mApplication.packageName + " not found");
diff --git a/core/java/android/widget/Scroller.java b/core/java/android/widget/Scroller.java
index 357c9c3..a968eae 100644
--- a/core/java/android/widget/Scroller.java
+++ b/core/java/android/widget/Scroller.java
@@ -19,6 +19,7 @@ package android.widget;
import android.content.Context;
import android.hardware.SensorManager;
import android.os.Build;
+import android.os.PowerManager;
import android.view.ViewConfiguration;
import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
@@ -108,6 +109,8 @@ public class Scroller {
private float mDeceleration;
private final float mPpi;
+ private final PowerManager mPm;
+
// A context-specific coefficient adjusted to physical values.
private float mPhysicalCoeff;
@@ -178,6 +181,8 @@ public class Scroller {
mFlywheel = flywheel;
mPhysicalCoeff = computeDeceleration(0.84f); // look and feel tuning
+
+ mPm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
}
/**
@@ -395,6 +400,8 @@ public class Scroller {
mDeltaX = dx;
mDeltaY = dy;
mDurationReciprocal = 1.0f / (float) mDuration;
+
+ mPm.cpuBoost(duration * 1000);
}
/**
diff --git a/core/java/android/widget/TextClock.java b/core/java/android/widget/TextClock.java
index bcde315..d5a3f16 100644
--- a/core/java/android/widget/TextClock.java
+++ b/core/java/android/widget/TextClock.java
@@ -548,6 +548,7 @@ public class TextClock extends TextView {
filter.addAction(Intent.ACTION_TIME_TICK);
filter.addAction(Intent.ACTION_TIME_CHANGED);
filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
+ filter.addAction(Intent.ACTION_DOZE_PULSE_STARTING);
getContext().registerReceiver(mIntentReceiver, filter, null, getHandler());
}
diff --git a/core/java/android/widget/Toast.java b/core/java/android/widget/Toast.java
index 207f675..4b31af0 100644
--- a/core/java/android/widget/Toast.java
+++ b/core/java/android/widget/Toast.java
@@ -21,9 +21,11 @@ import android.annotation.StringRes;
import android.app.INotificationManager;
import android.app.ITransientNotification;
import android.content.Context;
+import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.PixelFormat;
+import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.RemoteException;
import android.os.ServiceManager;
@@ -400,6 +402,18 @@ public class Toast {
if (context == null) {
context = mView.getContext();
}
+
+ ImageView appIcon = (ImageView) mView.findViewById(android.R.id.icon);
+ if (appIcon != null) {
+ PackageManager pm = context.getPackageManager();
+ Drawable icon = null;
+ try {
+ icon = pm.getApplicationIcon(packageName);
+ } catch (PackageManager.NameNotFoundException e) {
+ // nothing to do
+ }
+ appIcon.setImageDrawable(icon);
+ }
mWM = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
// We can resolve the Gravity here by using the Locale for getting
// the layout direction
diff --git a/core/java/com/android/internal/app/IAppOpsService.aidl b/core/java/com/android/internal/app/IAppOpsService.aidl
index 9fa2c23..aa1c265 100644
--- a/core/java/com/android/internal/app/IAppOpsService.aidl
+++ b/core/java/com/android/internal/app/IAppOpsService.aidl
@@ -46,4 +46,12 @@ interface IAppOpsService {
void setUserRestrictions(in Bundle restrictions, int userHandle);
void removeUser(int userHandle);
+ boolean isControlAllowed(int code, String packageName);
+
+ // Privacy guard methods
+ boolean getPrivacyGuardSettingForPackage(int uid, String packageName);
+ void setPrivacyGuardSettingForPackage(int uid, String packageName, boolean state);
+
+ // AppOps accounting
+ void resetCounters();
}
diff --git a/core/java/com/android/internal/app/PlatLogoActivity.java b/core/java/com/android/internal/app/PlatLogoActivity.java
index 2595fe0..efe88ff 100644
--- a/core/java/com/android/internal/app/PlatLogoActivity.java
+++ b/core/java/com/android/internal/app/PlatLogoActivity.java
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2010 The Android Open Source Project
+ * Copyright (C) 2014-2015 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.
@@ -57,10 +58,13 @@ public class PlatLogoActivity extends Activity {
int mKeyCount;
PathInterpolator mInterpolator = new PathInterpolator(0f, 0f, 0.5f, 1f);
+ private boolean mIsCM;
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ mIsCM = getIntent().hasExtra("is_cm");
mLayout = new FrameLayout(this);
setContentView(mLayout);
}
@@ -153,6 +157,7 @@ public class PlatLogoActivity extends Activity {
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_CLEAR_TASK
| Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS)
+ .putExtra("is_cm", mIsCM)
.addCategory("com.android.internal.category.PLATLOGO"));
} catch (ActivityNotFoundException ex) {
Log.e("PlatLogoActivity", "No more eggs.");
@@ -202,7 +207,9 @@ public class PlatLogoActivity extends Activity {
}
public void showMarshmallow(View im) {
- final Drawable fg = getDrawable(com.android.internal.R.drawable.platlogo);
+ final Drawable fg = getDrawable(mIsCM
+ ? com.android.internal.R.drawable.platlogo_cm
+ : com.android.internal.R.drawable.platlogo);
fg.setBounds(0, 0, im.getWidth(), im.getHeight());
fg.setAlpha(0);
im.getOverlay().add(fg);
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index 4ba678c..00e250b 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -93,6 +93,7 @@ public class ResolverActivity extends Activity {
private boolean mSafeForwardingMode;
private boolean mAlwaysUseOption;
private AbsListView mAdapterView;
+ private ViewGroup mFilteredItemContainer;
private Button mAlwaysButton;
private Button mOnceButton;
private View mProfileView;
@@ -305,6 +306,21 @@ public class ResolverActivity extends Activity {
}
if (mAdapter.hasFilteredItem()) {
+ mFilteredItemContainer = (ViewGroup) findViewById(R.id.filtered_item_container);
+ mFilteredItemContainer.setOnLongClickListener(new View.OnLongClickListener() {
+ @Override
+ public boolean onLongClick(View v) {
+ DisplayResolveInfo filteredItem = mAdapter.getFilteredItem();
+
+ if (filteredItem == null) {
+ return false;
+ }
+
+ showAppDetails(filteredItem.getResolveInfo());
+ return true;
+ }
+ });
+
setAlwaysButtonEnabled(true, mAdapter.getFilteredPosition(), false);
mOnceButton.setEnabled(true);
}
diff --git a/core/java/com/android/internal/logging/MetricsConstants.java b/core/java/com/android/internal/logging/MetricsConstants.java
index b90cb36..0e0d0bb 100644
--- a/core/java/com/android/internal/logging/MetricsConstants.java
+++ b/core/java/com/android/internal/logging/MetricsConstants.java
@@ -21,6 +21,7 @@ package com.android.internal.logging;
* @hide
*/
public interface MetricsConstants {
+ public static final int DONT_TRACK_ME_BRO = -Integer.MAX_VALUE + 1;
// These constants must match those in the analytic pipeline, do not edit.
// Add temporary values to the top of MetricsLogger instead.
public static final int VIEW_UNKNOWN = 0;
diff --git a/core/java/com/android/internal/os/DeviceKeyHandler.java b/core/java/com/android/internal/os/DeviceKeyHandler.java
new file mode 100644
index 0000000..e7d103d
--- /dev/null
+++ b/core/java/com/android/internal/os/DeviceKeyHandler.java
@@ -0,0 +1,26 @@
+/*
+ * 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 com.android.internal.os;
+
+import android.view.KeyEvent;
+
+public interface DeviceKeyHandler {
+
+ /**
+ * Invoked when an unknown key was detected by the system, letting the device handle
+ * this special keys prior to pass the key to the active app.
+ *
+ * @param event The key event to be handled
+ * @return If the event is consume
+ */
+ public boolean handleKeyEvent(KeyEvent event);
+}
diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java
index 3e86fac..6c3cb3e 100644
--- a/core/java/com/android/internal/os/ZygoteConnection.java
+++ b/core/java/com/android/internal/os/ZygoteConnection.java
@@ -22,6 +22,7 @@ import static android.system.OsConstants.STDERR_FILENO;
import static android.system.OsConstants.STDIN_FILENO;
import static android.system.OsConstants.STDOUT_FILENO;
+import android.graphics.Typeface;
import android.net.Credentials;
import android.net.LocalSocket;
import android.os.Process;
@@ -194,6 +195,10 @@ class ZygoteConnection {
Os.fcntlInt(childPipeFd, F_SETFD, 0);
}
+ if (parsedArgs.refreshTheme) {
+ Typeface.recreateDefaults();
+ }
+
/**
* In order to avoid leaking descriptors to the Zygote child,
* the native code must close the two Zygote socket descriptors
@@ -373,6 +378,9 @@ class ZygoteConnection {
*/
String appDataDir;
+ /** from --refresh_theme */
+ boolean refreshTheme;
+
/**
* Constructs instance and parses args
* @param args zygote command-line args
@@ -529,6 +537,8 @@ class ZygoteConnection {
instructionSet = arg.substring(arg.indexOf('=') + 1);
} else if (arg.startsWith("--app-data-dir=")) {
appDataDir = arg.substring(arg.indexOf('=') + 1);
+ } else if (arg.equals("--refresh_theme")) {
+ refreshTheme = true;
} else {
break;
}
diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java
index 8e8d352..fe0bc65 100644
--- a/core/java/com/android/internal/policy/PhoneWindow.java
+++ b/core/java/com/android/internal/policy/PhoneWindow.java
@@ -76,12 +76,19 @@ import com.android.internal.widget.SwipeDismissLayout;
import android.app.ActivityManager;
import android.app.KeyguardManager;
+import android.content.ComponentName;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
+import android.content.ServiceConnection;
+import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Configuration;
import android.content.res.Resources.Theme;
import android.content.res.TypedArray;
+import android.content.ActivityNotFoundException;
+import android.database.ContentObserver;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.PixelFormat;
@@ -93,10 +100,14 @@ import android.media.session.MediaSessionLegacyHelper;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.Messenger;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.provider.Settings;
import android.transition.Scene;
import android.transition.Transition;
import android.transition.TransitionInflater;
@@ -108,6 +119,8 @@ import android.util.EventLog;
import android.util.Log;
import android.util.SparseArray;
import android.util.TypedValue;
+import android.view.GestureDetector;
+import android.view.GestureDetector.SimpleOnGestureListener;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
import android.view.animation.Animation;
@@ -118,10 +131,14 @@ import android.widget.ImageView;
import android.widget.PopupWindow;
import android.widget.ProgressBar;
import android.widget.TextView;
+import android.widget.Toast;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
+import com.android.internal.statusbar.IStatusBarService;
+import com.android.internal.R;
+
/**
* Android-specific Window.
* <p>
@@ -249,7 +266,9 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
private int mTitleColor = 0;
private boolean mAlwaysReadCloseOnTouchAttr = false;
+ private boolean mEnableGestures;
+ private Context mContext;
private ContextMenuBuilder mContextMenu;
private MenuDialogHelper mContextMenuHelper;
private boolean mClosingActionMenu;
@@ -260,6 +279,36 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
private AudioManager mAudioManager;
private KeyguardManager mKeyguardManager;
+ private final class SettingsObserver extends ContentObserver {
+ SettingsObserver(Handler handler) {
+ super(handler);
+ }
+
+ void observe() {
+ ContentResolver resolver = mContext.getContentResolver();
+ resolver.registerContentObserver(Settings.System
+ .getUriFor(Settings.System.ENABLE_STYLUS_GESTURES), false,
+ this);
+ checkGestures();
+ }
+
+ void unobserve() {
+ ContentResolver resolver = mContext.getContentResolver();
+ resolver.unregisterContentObserver(this);
+ }
+
+ @Override
+ public void onChange(boolean selfChange) {
+ checkGestures();
+ }
+
+ void checkGestures() {
+ mEnableGestures = Settings.System.getInt(
+ mContext.getContentResolver(),
+ Settings.System.ENABLE_STYLUS_GESTURES, 0) == 1;
+ }
+ }
+
private int mUiOptions = 0;
private boolean mInvalidatePanelMenuPosted;
@@ -303,6 +352,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
public PhoneWindow(Context context) {
super(context);
+ mContext = context;
mLayoutInflater = LayoutInflater.from(context);
}
@@ -2224,6 +2274,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
private View mStatusGuard;
// View added at runtime to draw under the navigation bar area
private View mNavigationGuard;
+ private SettingsObserver mSettingsObserver;
private final ColorViewState mStatusColorViewState = new ColorViewState(
SYSTEM_UI_FLAG_FULLSCREEN, FLAG_TRANSLUCENT_STATUS,
@@ -2267,6 +2318,8 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
mBarEnterExitDuration = context.getResources().getInteger(
R.integer.dock_enter_exit_duration);
+
+ mSettingsObserver = new SettingsObserver(new Handler());
}
public void setBackgroundFallback(int resId) {
@@ -2358,8 +2411,211 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
return false;
}
+ private final StylusGestureFilter mStylusFilter = new StylusGestureFilter();
+
+ private class StylusGestureFilter extends SimpleOnGestureListener {
+
+ private final static int SWIPE_UP = 1;
+ private final static int SWIPE_DOWN = 2;
+ private final static int SWIPE_LEFT = 3;
+ private final static int SWIPE_RIGHT = 4;
+ private final static int PRESS_LONG = 5;
+ private final static int TAP_DOUBLE = 6;
+ private final static double SWIPE_MIN_DISTANCE = 25.0;
+ private final static double SWIPE_MIN_VELOCITY = 50.0;
+ private final static int KEY_NO_ACTION = 1000;
+ private final static int KEY_HOME = 1001;
+ private final static int KEY_BACK = 1002;
+ private final static int KEY_MENU = 1003;
+ private final static int KEY_SEARCH = 1004;
+ private final static int KEY_RECENT = 1005;
+ private final static int KEY_APP = 1006;
+ private GestureDetector mDetector;
+ private final static String TAG = "StylusGestureFilter";
+
+ public StylusGestureFilter() {
+ mDetector = new GestureDetector(this);
+ }
+
+ public boolean onTouchEvent(MotionEvent event) {
+ return mDetector.onTouchEvent(event);
+ }
+
+ @Override
+ public boolean onFling(MotionEvent e1, MotionEvent e2,
+ float velocityX, float velocityY) {
+
+ final float xDistance = Math.abs(e1.getX() - e2.getX());
+ final float yDistance = Math.abs(e1.getY() - e2.getY());
+
+ velocityX = Math.abs(velocityX);
+ velocityY = Math.abs(velocityY);
+ boolean result = false;
+
+ if (velocityX > (SWIPE_MIN_VELOCITY * getResources().getDisplayMetrics().density)
+ && xDistance > (SWIPE_MIN_DISTANCE * getResources().getDisplayMetrics().density)
+ && xDistance > yDistance) {
+ if (e1.getX() > e2.getX()) { // right to left
+ // Swipe Left
+ dispatchStylusAction(SWIPE_LEFT);
+ } else {
+ // Swipe Right
+ dispatchStylusAction(SWIPE_RIGHT);
+ }
+ result = true;
+ } else if (velocityY > (SWIPE_MIN_VELOCITY * getResources().getDisplayMetrics().density)
+ && yDistance > (SWIPE_MIN_DISTANCE * getResources().getDisplayMetrics().density)
+ && yDistance > xDistance) {
+ if (e1.getY() > e2.getY()) { // bottom to up
+ // Swipe Up
+ dispatchStylusAction(SWIPE_UP);
+ } else {
+ // Swipe Down
+ dispatchStylusAction(SWIPE_DOWN);
+ }
+ result = true;
+ }
+ return result;
+ }
+
+ @Override
+ public boolean onDoubleTap(MotionEvent arg0) {
+ dispatchStylusAction(TAP_DOUBLE);
+ return true;
+ }
+
+ public void onLongPress(MotionEvent e) {
+ dispatchStylusAction(PRESS_LONG);
+ }
+
+ }
+
+ private void menuAction() {
+ dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN,
+ KeyEvent.KEYCODE_MENU));
+ dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_UP,
+ KeyEvent.KEYCODE_MENU));
+
+ }
+
+ private void backAction() {
+ dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN,
+ KeyEvent.KEYCODE_BACK));
+ dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_UP,
+ KeyEvent.KEYCODE_BACK));
+ }
+
+ private void dispatchStylusAction(int gestureAction) {
+ final ContentResolver resolver = mContext.getContentResolver();
+ boolean isSystemUI = mContext.getPackageName().equals("com.android.systemui");
+ String setting = null;
+ int dispatchAction = -1;
+ switch (gestureAction) {
+ case StylusGestureFilter.SWIPE_LEFT:
+ setting = Settings.System.getString(resolver,
+ Settings.System.GESTURES_LEFT_SWIPE);
+ break;
+ case StylusGestureFilter.SWIPE_RIGHT:
+ setting = Settings.System.getString(resolver,
+ Settings.System.GESTURES_RIGHT_SWIPE);
+ break;
+ case StylusGestureFilter.SWIPE_UP:
+ setting = Settings.System.getString(resolver,
+ Settings.System.GESTURES_UP_SWIPE);
+ break;
+ case StylusGestureFilter.SWIPE_DOWN:
+ setting = Settings.System.getString(resolver,
+ Settings.System.GESTURES_DOWN_SWIPE);
+ break;
+ case StylusGestureFilter.TAP_DOUBLE:
+ setting = Settings.System.getString(resolver,
+ Settings.System.GESTURES_DOUBLE_TAP);
+ break;
+ case StylusGestureFilter.PRESS_LONG:
+ setting = Settings.System.getString(resolver,
+ Settings.System.GESTURES_LONG_PRESS);
+ break;
+ default:
+ return;
+ }
+
+ try {
+ int value = Integer.valueOf(setting);
+ if (value == StylusGestureFilter.KEY_NO_ACTION) {
+ return;
+ }
+ dispatchAction = value;
+ } catch (NumberFormatException e) {
+ dispatchAction = StylusGestureFilter.KEY_APP;
+ }
+
+ // Dispatching action
+ switch (dispatchAction) {
+ case StylusGestureFilter.KEY_HOME:
+ Intent homeIntent = new Intent(Intent.ACTION_MAIN);
+ homeIntent.addCategory(Intent.CATEGORY_HOME);
+ homeIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ mContext.startActivity(homeIntent);
+ break;
+ case StylusGestureFilter.KEY_BACK:
+ backAction();
+ break;
+ case StylusGestureFilter.KEY_MENU:
+ // Menu action on notificationbar / systemui will be converted
+ // to back action
+ if (isSystemUI) {
+ backAction();
+ break;
+ }
+ menuAction();
+ break;
+ case StylusGestureFilter.KEY_SEARCH:
+ // Search action on notificationbar / systemui will be converted
+ // to back action
+ if (isSystemUI) {
+ backAction();
+ break;
+ }
+ launchDefaultSearch(new KeyEvent(KeyEvent.ACTION_UP,
+ KeyEvent.KEYCODE_SEARCH));
+ break;
+ case StylusGestureFilter.KEY_RECENT:
+ IStatusBarService mStatusBarService = IStatusBarService.Stub
+ .asInterface(ServiceManager.getService("statusbar"));
+ try {
+ mStatusBarService.toggleRecentApps();
+ } catch (RemoteException e) {
+ }
+ break;
+ case StylusGestureFilter.KEY_APP:
+ // Launching app on notificationbar / systemui will be preceded
+ // with a back Action
+ if (isSystemUI) {
+ backAction();
+ }
+ try {
+ final PackageManager pm = mContext.getPackageManager();
+ Intent launchIntent = pm.getLaunchIntentForPackage(setting);
+ if (launchIntent != null) {
+ mContext.startActivity(launchIntent);
+ }
+ } catch (ActivityNotFoundException e) {
+ Toast.makeText(mContext, mContext.getString(R.string.stylus_app_not_installed, setting),
+ Toast.LENGTH_LONG).show();
+ }
+ break;
+ }
+ }
+
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
+ // Stylus events with side button pressed are filtered and other
+ // events are processed normally.
+ if (mEnableGestures
+ && MotionEvent.BUTTON_SECONDARY == ev.getButtonState()) {
+ mStylusFilter.onTouchEvent(ev);
+ return false;
+ }
final Callback cb = getCallback();
return cb != null && !isDestroyed() && mFeatureId < 0 ? cb.dispatchTouchEvent(ev)
: super.dispatchTouchEvent(ev);
@@ -3255,6 +3511,8 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
protected void onAttachedToWindow() {
super.onAttachedToWindow();
+ mSettingsObserver.observe();
+
updateWindowResizeState();
final Callback cb = getCallback();
@@ -3278,6 +3536,8 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
+ mSettingsObserver.unobserve();
+
final Callback cb = getCallback();
if (cb != null && mFeatureId < 0) {
cb.onDetachedFromWindow();
diff --git a/core/java/com/android/internal/util/cm/ActionUtils.java b/core/java/com/android/internal/util/cm/ActionUtils.java
new file mode 100644
index 0000000..7e86cd3
--- /dev/null
+++ b/core/java/com/android/internal/util/cm/ActionUtils.java
@@ -0,0 +1,149 @@
+package com.android.internal.util.cm;
+
+import android.app.ActivityManager;
+import android.app.ActivityManagerNative;
+import android.app.ActivityOptions;
+import android.app.IActivityManager;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.util.Log;
+
+import android.view.HapticFeedbackConstants;
+import android.widget.Toast;
+import com.android.internal.R;
+
+import java.util.List;
+
+public class ActionUtils {
+ private static final boolean DEBUG = false;
+ private static final String TAG = ActionUtils.class.getSimpleName();
+ private static final String SYSTEMUI_PACKAGE = "com.android.systemui";
+
+ /**
+ * Kills the top most / most recent user application, but leaves out the launcher.
+ * This is function governed by {@link CMSettings.Secure.KILL_APP_LONGPRESS_BACK}.
+ *
+ * @param context the current context, used to retrieve the package manager.
+ * @param userId the ID of the currently active user
+ * @return {@code true} when a user application was found and closed.
+ */
+ public static boolean killForegroundApp(Context context, int userId) {
+ try {
+ return killForegroundAppInternal(context, userId);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Could not kill foreground app");
+ }
+ return false;
+ }
+
+ private static boolean killForegroundAppInternal(Context context, int userId)
+ throws RemoteException {
+ try {
+ final Intent intent = new Intent(Intent.ACTION_MAIN);
+ String defaultHomePackage = "com.android.launcher";
+ intent.addCategory(Intent.CATEGORY_HOME);
+ final ResolveInfo res = context.getPackageManager().resolveActivity(intent, 0);
+
+ if (res.activityInfo != null && !res.activityInfo.packageName.equals("android")) {
+ defaultHomePackage = res.activityInfo.packageName;
+ }
+
+ IActivityManager am = ActivityManagerNative.getDefault();
+ List<ActivityManager.RunningAppProcessInfo> apps = am.getRunningAppProcesses();
+ for (ActivityManager.RunningAppProcessInfo appInfo : apps) {
+ int uid = appInfo.uid;
+ // Make sure it's a foreground user application (not system,
+ // root, phone, etc.)
+ if (uid >= Process.FIRST_APPLICATION_UID && uid <= Process.LAST_APPLICATION_UID
+ && appInfo.importance ==
+ ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {
+ if (appInfo.pkgList != null && (appInfo.pkgList.length > 0)) {
+ for (String pkg : appInfo.pkgList) {
+ if (!pkg.equals("com.android.systemui")
+ && !pkg.equals(defaultHomePackage)) {
+ am.forceStopPackage(pkg, UserHandle.USER_CURRENT);
+ return true;
+ }
+ }
+ } else {
+ Process.killProcess(appInfo.pid);
+ return true;
+ }
+ }
+ }
+ } catch (RemoteException remoteException) {
+ // Do nothing; just let it go.
+ }
+ return false;
+ }
+
+ /**
+ * Attempt to bring up the last activity in the stack before the current active one.
+ *
+ * @param context
+ * @return whether an activity was found to switch to
+ */
+ public static boolean switchToLastApp(Context context, int userId) {
+ try {
+ return switchToLastAppInternal(context, userId);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Could not switch to last app");
+ }
+ return false;
+ }
+
+ private static boolean switchToLastAppInternal(Context context, int userId)
+ throws RemoteException {
+ ActivityManager.RecentTaskInfo lastTask = getLastTask(context, userId);
+
+ if (lastTask == null || lastTask.id < 0) {
+ return false;
+ }
+
+ final String packageName = lastTask.baseIntent.getComponent().getPackageName();
+ final IActivityManager am = ActivityManagerNative.getDefault();
+ final ActivityOptions opts = ActivityOptions.makeCustomAnimation(context,
+ com.android.internal.R.anim.last_app_in,
+ com.android.internal.R.anim.last_app_out);
+
+ if (DEBUG) Log.d(TAG, "switching to " + packageName);
+ am.moveTaskToFront(lastTask.id, ActivityManager.MOVE_TASK_NO_USER_ACTION, opts.toBundle());
+
+ return true;
+ }
+
+ private static ActivityManager.RecentTaskInfo getLastTask(Context context, int userId)
+ throws RemoteException {
+ final String defaultHomePackage = resolveCurrentLauncherPackage(context, userId);
+ final IActivityManager am = ActivityManagerNative.getDefault();
+ final List<ActivityManager.RecentTaskInfo> tasks = am.getRecentTasks(5,
+ ActivityManager.RECENT_IGNORE_UNAVAILABLE, userId);
+
+ for (int i = 1; i < tasks.size(); i++) {
+ ActivityManager.RecentTaskInfo task = tasks.get(i);
+ if (task.origActivity != null) {
+ task.baseIntent.setComponent(task.origActivity);
+ }
+ String packageName = task.baseIntent.getComponent().getPackageName();
+ if (!packageName.equals(defaultHomePackage)
+ && !packageName.equals(SYSTEMUI_PACKAGE)) {
+ return tasks.get(i);
+ }
+ }
+
+ return null;
+ }
+
+ private static String resolveCurrentLauncherPackage(Context context, int userId) {
+ final Intent launcherIntent = new Intent(Intent.ACTION_MAIN)
+ .addCategory(Intent.CATEGORY_HOME);
+ final PackageManager pm = context.getPackageManager();
+ final ResolveInfo launcherInfo = pm.resolveActivityAsUser(launcherIntent, 0, userId);
+ return launcherInfo.activityInfo.packageName;
+ }
+}
diff --git a/core/java/com/android/internal/util/cm/ImageUtils.java b/core/java/com/android/internal/util/cm/ImageUtils.java
new file mode 100644
index 0000000..73189a3
--- /dev/null
+++ b/core/java/com/android/internal/util/cm/ImageUtils.java
@@ -0,0 +1,332 @@
+/*
+ * Copyright (C) 2013-2014 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 com.android.internal.util.cm;
+
+import android.app.WallpaperManager;
+import android.content.Context;
+import android.content.pm.ThemeUtils;
+import android.content.res.AssetManager;
+import android.database.Cursor;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Point;
+import android.net.Uri;
+import android.provider.ThemesContract;
+import android.provider.ThemesContract.ThemesColumns;
+import android.text.TextUtils;
+import android.util.Log;
+import android.webkit.URLUtil;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+
+import libcore.io.IoUtils;
+
+public class ImageUtils {
+ private static final String TAG = ImageUtils.class.getSimpleName();
+
+ private static final String ASSET_URI_PREFIX = "file:///android_asset/";
+ private static final int DEFAULT_IMG_QUALITY = 100;
+
+ /**
+ * Gets the Width and Height of the image
+ *
+ * @param inputStream The input stream of the image
+ *
+ * @return A point structure that holds the Width and Height (x and y)/*"
+ */
+ public static Point getImageDimension(InputStream inputStream) {
+ if (inputStream == null) {
+ throw new IllegalArgumentException("'inputStream' cannot be null!");
+ }
+ BitmapFactory.Options options = new BitmapFactory.Options();
+ options.inJustDecodeBounds = true;
+ BitmapFactory.decodeStream(inputStream, null, options);
+ Point point = new Point(options.outWidth,options.outHeight);
+ return point;
+ }
+
+ /**
+ * Crops the input image and returns a new InputStream of the cropped area
+ *
+ * @param inputStream The input stream of the image
+ * @param imageWidth Width of the input image
+ * @param imageHeight Height of the input image
+ * @param inputStream Desired Width
+ * @param inputStream Desired Width
+ *
+ * @return a new InputStream of the cropped area/*"
+ */
+ public static InputStream cropImage(InputStream inputStream, int imageWidth, int imageHeight,
+ int outWidth, int outHeight) throws IllegalArgumentException {
+ if (inputStream == null){
+ throw new IllegalArgumentException("inputStream cannot be null");
+ }
+
+ if (imageWidth <= 0 || imageHeight <= 0) {
+ throw new IllegalArgumentException(
+ String.format("imageWidth and imageHeight must be > 0: imageWidth=%d" +
+ " imageHeight=%d", imageWidth, imageHeight));
+ }
+
+ if (outWidth <= 0 || outHeight <= 0) {
+ throw new IllegalArgumentException(
+ String.format("outWidth and outHeight must be > 0: outWidth=%d" +
+ " outHeight=%d", imageWidth, outHeight));
+ }
+
+ int scaleDownSampleSize = Math.min(imageWidth / outWidth, imageHeight / outHeight);
+ if (scaleDownSampleSize > 0) {
+ imageWidth /= scaleDownSampleSize;
+ imageHeight /= scaleDownSampleSize;
+ } else {
+ float ratio = (float) outWidth / outHeight;
+ if (imageWidth < imageHeight * ratio) {
+ outWidth = imageWidth;
+ outHeight = (int) (outWidth / ratio);
+ } else {
+ outHeight = imageHeight;
+ outWidth = (int) (outHeight * ratio);
+ }
+ }
+ int left = (imageWidth - outWidth) / 2;
+ int top = (imageHeight - outHeight) / 2;
+ InputStream compressed = null;
+ try {
+ BitmapFactory.Options options = new BitmapFactory.Options();
+ if (scaleDownSampleSize > 1) {
+ options.inSampleSize = scaleDownSampleSize;
+ }
+ Bitmap bitmap = BitmapFactory.decodeStream(inputStream, null, options);
+ if (bitmap == null) {
+ return null;
+ }
+ Bitmap cropped = Bitmap.createBitmap(bitmap, left, top, outWidth, outHeight);
+ ByteArrayOutputStream tmpOut = new ByteArrayOutputStream(2048);
+ if (cropped.compress(Bitmap.CompressFormat.PNG, DEFAULT_IMG_QUALITY, tmpOut)) {
+ byte[] outByteArray = tmpOut.toByteArray();
+ compressed = new ByteArrayInputStream(outByteArray);
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "Exception " + e);
+ }
+ return compressed;
+ }
+
+ /**
+ * Crops the lock screen image and returns a new InputStream of the cropped area
+ *
+ * @param pkgName Name of the theme package
+ * @param context The context
+ *
+ * @return a new InputStream of the cropped image/*"
+ */
+ public static InputStream getCroppedKeyguardStream(String pkgName, Context context)
+ throws IllegalArgumentException {
+ if (TextUtils.isEmpty(pkgName)) {
+ throw new IllegalArgumentException("'pkgName' cannot be null or empty!");
+ }
+ if (context == null) {
+ throw new IllegalArgumentException("'context' cannot be null!");
+ }
+
+ InputStream cropped = null;
+ InputStream stream = null;
+ try {
+ stream = getOriginalKeyguardStream(pkgName, context);
+ if (stream == null) {
+ return null;
+ }
+ Point point = getImageDimension(stream);
+ IoUtils.closeQuietly(stream);
+ if (point == null || point.x == 0 || point.y == 0) {
+ return null;
+ }
+ WallpaperManager wm = WallpaperManager.getInstance(context);
+ int outWidth = wm.getDesiredMinimumWidth();
+ int outHeight = wm.getDesiredMinimumHeight();
+ stream = getOriginalKeyguardStream(pkgName, context);
+ if (stream == null) {
+ return null;
+ }
+ cropped = cropImage(stream, point.x, point.y, outWidth, outHeight);
+ } catch (Exception e) {
+ Log.e(TAG, "Exception " + e);
+ } finally {
+ IoUtils.closeQuietly(stream);
+ }
+ return cropped;
+ }
+
+ /**
+ * Crops the wallpaper image and returns a new InputStream of the cropped area
+ *
+ * @param pkgName Name of the theme package
+ * @param context The context
+ *
+ * @return a new InputStream of the cropped image/*"
+ */
+ public static InputStream getCroppedWallpaperStream(String pkgName, long wallpaperId,
+ Context context) {
+ if (TextUtils.isEmpty(pkgName)) {
+ throw new IllegalArgumentException("'pkgName' cannot be null or empty!");
+ }
+ if (context == null) {
+ throw new IllegalArgumentException("'context' cannot be null!");
+ }
+
+ InputStream cropped = null;
+ InputStream stream = null;
+ try {
+ stream = getOriginalWallpaperStream(pkgName, wallpaperId, context);
+ if (stream == null) {
+ return null;
+ }
+ Point point = getImageDimension(stream);
+ IoUtils.closeQuietly(stream);
+ if (point == null || point.x == 0 || point.y == 0) {
+ return null;
+ }
+ WallpaperManager wm = WallpaperManager.getInstance(context);
+ int outWidth = wm.getDesiredMinimumWidth();
+ int outHeight = wm.getDesiredMinimumHeight();
+ stream = getOriginalWallpaperStream(pkgName, wallpaperId, context);
+ if (stream == null) {
+ return null;
+ }
+ cropped = cropImage(stream, point.x, point.y, outWidth, outHeight);
+ } catch (Exception e) {
+ Log.e(TAG, "Exception " + e);
+ } finally {
+ IoUtils.closeQuietly(stream);
+ }
+ return cropped;
+ }
+
+ private static InputStream getOriginalKeyguardStream(String pkgName, Context context) {
+ if (TextUtils.isEmpty(pkgName) || context == null) {
+ return null;
+ }
+
+ InputStream inputStream = null;
+ try {
+ //Get input WP stream from the theme
+ Context themeCtx = context.createPackageContext(pkgName,
+ Context.CONTEXT_IGNORE_SECURITY);
+ AssetManager assetManager = themeCtx.getAssets();
+ String wpPath = ThemeUtils.getLockscreenWallpaperPath(assetManager);
+ if (wpPath == null) {
+ Log.w(TAG, "Not setting lockscreen wp because wallpaper file was not found.");
+ } else {
+ inputStream = ThemeUtils.getInputStreamFromAsset(themeCtx,
+ ASSET_URI_PREFIX + wpPath);
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "There was an error setting lockscreen wp for pkg " + pkgName, e);
+ }
+ return inputStream;
+ }
+
+ private static InputStream getOriginalWallpaperStream(String pkgName, long componentId,
+ Context context) {
+ String wpPath;
+ if (TextUtils.isEmpty(pkgName) || context == null) {
+ return null;
+ }
+
+ InputStream inputStream = null;
+ String selection = ThemesContract.ThemesColumns.PKG_NAME + "= ?";
+ String[] selectionArgs = {pkgName};
+ Cursor c = context.getContentResolver().query(ThemesColumns.CONTENT_URI,
+ null, selection,
+ selectionArgs, null);
+ if (c == null || c.getCount() < 1) {
+ if (c != null) c.close();
+ return null;
+ } else {
+ c.moveToFirst();
+ }
+
+ try {
+ Context themeContext = context.createPackageContext(pkgName,
+ Context.CONTEXT_IGNORE_SECURITY);
+ boolean isLegacyTheme = c.getInt(
+ c.getColumnIndex(ThemesColumns.IS_LEGACY_THEME)) == 1;
+ String wallpaper = c.getString(
+ c.getColumnIndex(ThemesColumns.WALLPAPER_URI));
+ if (wallpaper != null) {
+ if (URLUtil.isAssetUrl(wallpaper)) {
+ inputStream = ThemeUtils.getInputStreamFromAsset(themeContext, wallpaper);
+ } else {
+ inputStream = context.getContentResolver().openInputStream(
+ Uri.parse(wallpaper));
+ }
+ } else {
+ // try and get the wallpaper directly from the apk if the URI was null
+ Context themeCtx = context.createPackageContext(pkgName,
+ Context.CONTEXT_IGNORE_SECURITY);
+ AssetManager assetManager = themeCtx.getAssets();
+ wpPath = queryWpPathFromComponentId(context, pkgName, componentId);
+ if (wpPath == null) wpPath = ThemeUtils.getWallpaperPath(assetManager);
+ if (wpPath == null) {
+ Log.e(TAG, "Not setting wp because wallpaper file was not found.");
+ } else {
+ inputStream = ThemeUtils.getInputStreamFromAsset(themeCtx,
+ ASSET_URI_PREFIX + wpPath);
+ }
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "getWallpaperStream: " + e);
+ } finally {
+ c.close();
+ }
+
+ return inputStream;
+ }
+
+ private static String queryWpPathFromComponentId(Context context, String pkgName,
+ long componentId) {
+ String wpPath = null;
+ String[] projection = new String[] { ThemesContract.PreviewColumns.COL_VALUE };
+ String selection = ThemesColumns.PKG_NAME + "=? AND " +
+ ThemesContract.PreviewColumns.COMPONENT_ID + "=? AND " +
+ ThemesContract.PreviewColumns.COL_KEY + "=?";
+ String[] selectionArgs = new String[] {
+ pkgName,
+ Long.toString(componentId),
+ ThemesContract.PreviewColumns.WALLPAPER_FULL
+ };
+
+ Cursor c = context.getContentResolver()
+ .query(ThemesContract.PreviewColumns.COMPONENTS_URI,
+ projection, selection, selectionArgs, null);
+ if (c != null) {
+ try {
+ if (c.moveToFirst()) {
+ int valIdx = c.getColumnIndex(ThemesContract.PreviewColumns.COL_VALUE);
+ wpPath = c.getString(valIdx);
+ }
+ } catch(Exception e) {
+ Log.e(TAG, "Could not get wallpaper path", e);
+ } finally {
+ c.close();
+ }
+ }
+ return wpPath;
+ }
+}
+
diff --git a/core/java/com/android/internal/util/cm/PowerMenuConstants.java b/core/java/com/android/internal/util/cm/PowerMenuConstants.java
new file mode 100644
index 0000000..3debd09
--- /dev/null
+++ b/core/java/com/android/internal/util/cm/PowerMenuConstants.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2015 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 com.android.internal.util.cm;
+
+/* Master list of all actions for the power menu */
+public class PowerMenuConstants {
+ public static final String GLOBAL_ACTION_KEY_POWER = "power";
+ public static final String GLOBAL_ACTION_KEY_REBOOT = "reboot";
+ public static final String GLOBAL_ACTION_KEY_SCREENSHOT = "screenshot";
+ public static final String GLOBAL_ACTION_KEY_AIRPLANE = "airplane";
+ public static final String GLOBAL_ACTION_KEY_USERS = "users";
+ public static final String GLOBAL_ACTION_KEY_SETTINGS = "settings";
+ public static final String GLOBAL_ACTION_KEY_LOCKDOWN = "lockdown";
+ public static final String GLOBAL_ACTION_KEY_BUGREPORT = "bugreport";
+ public static final String GLOBAL_ACTION_KEY_SILENT = "silent";
+ public static final String GLOBAL_ACTION_KEY_VOICEASSIST = "voiceassist";
+ public static final String GLOBAL_ACTION_KEY_ASSIST = "assist";
+
+ private static String[] ALL_ACTIONS = {
+ GLOBAL_ACTION_KEY_POWER,
+ GLOBAL_ACTION_KEY_REBOOT,
+ GLOBAL_ACTION_KEY_SCREENSHOT,
+ GLOBAL_ACTION_KEY_AIRPLANE,
+ GLOBAL_ACTION_KEY_USERS,
+ GLOBAL_ACTION_KEY_SETTINGS,
+ GLOBAL_ACTION_KEY_LOCKDOWN,
+ GLOBAL_ACTION_KEY_BUGREPORT,
+ GLOBAL_ACTION_KEY_SILENT,
+ GLOBAL_ACTION_KEY_VOICEASSIST,
+ GLOBAL_ACTION_KEY_ASSIST
+ };
+
+ public static String[] getAllActions() {
+ return ALL_ACTIONS;
+ }
+}
diff --git a/core/java/com/android/internal/util/cm/SpamFilter.java b/core/java/com/android/internal/util/cm/SpamFilter.java
new file mode 100644
index 0000000..9de4489
--- /dev/null
+++ b/core/java/com/android/internal/util/cm/SpamFilter.java
@@ -0,0 +1,65 @@
+package com.android.internal.util.cm;
+
+import android.app.Notification;
+import android.content.ContentResolver;
+import android.net.Uri;
+import android.os.Bundle;
+import android.text.TextUtils;
+
+public class SpamFilter {
+
+ public static final String AUTHORITY = "com.cyanogenmod.spam";
+ public static final String MESSAGE_PATH = "message";
+ public static final Uri NOTIFICATION_URI = new Uri.Builder()
+ .scheme(ContentResolver.SCHEME_CONTENT)
+ .authority(AUTHORITY)
+ .appendEncodedPath(MESSAGE_PATH)
+ .build();
+
+ public static final class SpamContract {
+
+ public static final class PackageTable {
+ public static final String TABLE_NAME = "packages";
+ public static final String ID = "_id";
+ public static final String PACKAGE_NAME = "package_name";
+ }
+
+ public static final class NotificationTable {
+ public static final String TABLE_NAME = "notifications";
+ public static final String ID = "_id";
+ public static final String PACKAGE_ID = "package_id";
+ public static final String MESSAGE_TEXT = "message_text";
+ public static final String COUNT = "count";
+ public static final String LAST_BLOCKED = "last_blocked";
+ public static final String NORMALIZED_TEXT = "normalized_text";
+ }
+
+ }
+
+ public static String getNormalizedContent(String msg) {
+ return msg.toLowerCase().replaceAll("[^\\p{L}\\p{Nd}]+", "");
+ }
+
+ public static String getNormalizedNotificationContent(Notification notification) {
+ String content = getNotificationContent(notification);
+ return getNormalizedContent(content);
+ }
+
+ public static String getNotificationContent(Notification notification) {
+ Bundle extras = notification.extras;
+ String titleExtra = extras.containsKey(Notification.EXTRA_TITLE_BIG)
+ ? Notification.EXTRA_TITLE_BIG : Notification.EXTRA_TITLE;
+ CharSequence notificationTitle = extras.getCharSequence(titleExtra);
+ CharSequence notificationMessage = extras.getCharSequence(Notification.EXTRA_TEXT);
+
+ if (TextUtils.isEmpty(notificationMessage)) {
+ CharSequence[] inboxLines = extras.getCharSequenceArray(Notification.EXTRA_TEXT_LINES);
+ if (inboxLines == null || inboxLines.length == 0) {
+ notificationMessage = "";
+ } else {
+ notificationMessage = TextUtils.join("\n", inboxLines);
+ }
+ }
+ return notificationTitle + "\n" + notificationMessage;
+ }
+}
diff --git a/core/java/com/android/internal/util/cm/palette/ColorCutQuantizer.java b/core/java/com/android/internal/util/cm/palette/ColorCutQuantizer.java
new file mode 100644
index 0000000..ab5aef7
--- /dev/null
+++ b/core/java/com/android/internal/util/cm/palette/ColorCutQuantizer.java
@@ -0,0 +1,449 @@
+/*
+ * Copyright 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.util.cm.palette;
+
+import android.graphics.Bitmap;
+import android.graphics.Color;
+import android.util.SparseIntArray;
+
+import com.android.internal.util.cm.palette.Palette.Swatch;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.List;
+import java.util.PriorityQueue;
+
+/**
+ * An color quantizer based on the Median-cut algorithm, but optimized for picking out distinct
+ * colors rather than representation colors.
+ *
+ * The color space is represented as a 3-dimensional cube with each dimension being an RGB
+ * component. The cube is then repeatedly divided until we have reduced the color space to the
+ * requested number of colors. An average color is then generated from each cube.
+ *
+ * What makes this different to median-cut is that median-cut divided cubes so that all of the cubes
+ * have roughly the same population, where this quantizer divides boxes based on their color volume.
+ * This means that the color space is divided into distinct colors, rather than representative
+ * colors.
+ *
+ * @hide
+ */
+final class ColorCutQuantizer {
+
+ private static final String LOG_TAG = ColorCutQuantizer.class.getSimpleName();
+
+ private final float[] mTempHsl = new float[3];
+
+ private static final float BLACK_MAX_LIGHTNESS = 0.05f;
+ private static final float WHITE_MIN_LIGHTNESS = 0.95f;
+
+ private static final int COMPONENT_RED = -3;
+ private static final int COMPONENT_GREEN = -2;
+ private static final int COMPONENT_BLUE = -1;
+
+ private final int[] mColors;
+ private final SparseIntArray mColorPopulations;
+
+ private final List<Swatch> mQuantizedColors;
+
+ /**
+ * Factory-method to generate a {@link ColorCutQuantizer} from a {@link Bitmap} object.
+ *
+ * @param bitmap Bitmap to extract the pixel data from
+ * @param maxColors The maximum number of colors that should be in the result palette.
+ */
+ static ColorCutQuantizer fromBitmap(Bitmap bitmap, int maxColors) {
+ final int width = bitmap.getWidth();
+ final int height = bitmap.getHeight();
+
+ final int[] pixels = new int[width * height];
+ bitmap.getPixels(pixels, 0, width, 0, 0, width, height);
+
+ return new ColorCutQuantizer(new com.android.internal.util.cm.palette.ColorHistogram(pixels), maxColors);
+ }
+
+ /**
+ * Private constructor.
+ *
+ * @param colorHistogram histogram representing an image's pixel data
+ * @param maxColors The maximum number of colors that should be in the result palette.
+ */
+ private ColorCutQuantizer(com.android.internal.util.cm.palette.ColorHistogram colorHistogram, int maxColors) {
+ final int rawColorCount = colorHistogram.getNumberOfColors();
+ final int[] rawColors = colorHistogram.getColors();
+ final int[] rawColorCounts = colorHistogram.getColorCounts();
+
+ // First, lets pack the populations into a SparseIntArray so that they can be easily
+ // retrieved without knowing a color's index
+ mColorPopulations = new SparseIntArray(rawColorCount);
+ for (int i = 0; i < rawColors.length; i++) {
+ mColorPopulations.append(rawColors[i], rawColorCounts[i]);
+ }
+
+ // Now go through all of the colors and keep those which we do not want to ignore
+ mColors = new int[rawColorCount];
+ int validColorCount = 0;
+ for (int color : rawColors) {
+ if (!shouldIgnoreColor(color)) {
+ mColors[validColorCount++] = color;
+ }
+ }
+
+ if (validColorCount <= maxColors) {
+ // The image has fewer colors than the maximum requested, so just return the colors
+ mQuantizedColors = new ArrayList<Swatch>();
+ for (final int color : mColors) {
+ mQuantizedColors.add(new Swatch(color, mColorPopulations.get(color)));
+ }
+ } else {
+ // We need use quantization to reduce the number of colors
+ mQuantizedColors = quantizePixels(validColorCount - 1, maxColors);
+ }
+ }
+
+ /**
+ * @return the list of quantized colors
+ */
+ List<Swatch> getQuantizedColors() {
+ return mQuantizedColors;
+ }
+
+ private List<Swatch> quantizePixels(int maxColorIndex, int maxColors) {
+ // Create the priority queue which is sorted by volume descending. This means we always
+ // split the largest box in the queue
+ final PriorityQueue<Vbox> pq = new PriorityQueue<Vbox>(maxColors, VBOX_COMPARATOR_VOLUME);
+
+ // To start, offer a box which contains all of the colors
+ pq.offer(new Vbox(0, maxColorIndex));
+
+ // Now go through the boxes, splitting them until we have reached maxColors or there are no
+ // more boxes to split
+ splitBoxes(pq, maxColors);
+
+ // Finally, return the average colors of the color boxes
+ return generateAverageColors(pq);
+ }
+
+ /**
+ * Iterate through the {@link java.util.Queue}, popping
+ * {@link ColorCutQuantizer.Vbox} objects from the queue
+ * and splitting them. Once split, the new box and the remaining box are offered back to the
+ * queue.
+ *
+ * @param queue {@link PriorityQueue} to poll for boxes
+ * @param maxSize Maximum amount of boxes to split
+ */
+ private void splitBoxes(final PriorityQueue<Vbox> queue, final int maxSize) {
+ while (queue.size() < maxSize) {
+ final Vbox vbox = queue.poll();
+
+ if (vbox != null && vbox.canSplit()) {
+ // First split the box, and offer the result
+ queue.offer(vbox.splitBox());
+ // Then offer the box back
+ queue.offer(vbox);
+ } else {
+ // If we get here then there are no more boxes to split, so return
+ return;
+ }
+ }
+ }
+
+ private List<Swatch> generateAverageColors(Collection<Vbox> vboxes) {
+ ArrayList<Swatch> colors = new ArrayList<Swatch>(vboxes.size());
+ for (Vbox vbox : vboxes) {
+ Swatch color = vbox.getAverageColor();
+ if (!shouldIgnoreColor(color)) {
+ // As we're averaging a color box, we can still get colors which we do not want, so
+ // we check again here
+ colors.add(color);
+ }
+ }
+ return colors;
+ }
+
+ /**
+ * Represents a tightly fitting box around a color space.
+ */
+ private class Vbox {
+ // lower and upper index are inclusive
+ private int mLowerIndex;
+ private int mUpperIndex;
+
+ private int mMinRed, mMaxRed;
+ private int mMinGreen, mMaxGreen;
+ private int mMinBlue, mMaxBlue;
+
+ Vbox(int lowerIndex, int upperIndex) {
+ mLowerIndex = lowerIndex;
+ mUpperIndex = upperIndex;
+ fitBox();
+ }
+
+ int getVolume() {
+ return (mMaxRed - mMinRed + 1) * (mMaxGreen - mMinGreen + 1) *
+ (mMaxBlue - mMinBlue + 1);
+ }
+
+ boolean canSplit() {
+ return getColorCount() > 1;
+ }
+
+ int getColorCount() {
+ return mUpperIndex - mLowerIndex + 1;
+ }
+
+ /**
+ * Recomputes the boundaries of this box to tightly fit the colors within the box.
+ */
+ void fitBox() {
+ // Reset the min and max to opposite values
+ mMinRed = mMinGreen = mMinBlue = 0xFF;
+ mMaxRed = mMaxGreen = mMaxBlue = 0x0;
+
+ for (int i = mLowerIndex; i <= mUpperIndex; i++) {
+ final int color = mColors[i];
+ final int r = Color.red(color);
+ final int g = Color.green(color);
+ final int b = Color.blue(color);
+ if (r > mMaxRed) {
+ mMaxRed = r;
+ }
+ if (r < mMinRed) {
+ mMinRed = r;
+ }
+ if (g > mMaxGreen) {
+ mMaxGreen = g;
+ }
+ if (g < mMinGreen) {
+ mMinGreen = g;
+ }
+ if (b > mMaxBlue) {
+ mMaxBlue = b;
+ }
+ if (b < mMinBlue) {
+ mMinBlue = b;
+ }
+ }
+ }
+
+ /**
+ * Split this color box at the mid-point along it's longest dimension
+ *
+ * @return the new ColorBox
+ */
+ Vbox splitBox() {
+ if (!canSplit()) {
+ throw new IllegalStateException("Can not split a box with only 1 color");
+ }
+
+ // find median along the longest dimension
+ final int splitPoint = findSplitPoint();
+
+ Vbox newBox = new Vbox(splitPoint + 1, mUpperIndex);
+
+ // Now change this box's upperIndex and recompute the color boundaries
+ mUpperIndex = splitPoint;
+ fitBox();
+
+ return newBox;
+ }
+
+ /**
+ * @return the dimension which this box is largest in
+ */
+ int getLongestColorDimension() {
+ final int redLength = mMaxRed - mMinRed;
+ final int greenLength = mMaxGreen - mMinGreen;
+ final int blueLength = mMaxBlue - mMinBlue;
+
+ if (redLength >= greenLength && redLength >= blueLength) {
+ return COMPONENT_RED;
+ } else if (greenLength >= redLength && greenLength >= blueLength) {
+ return COMPONENT_GREEN;
+ } else {
+ return COMPONENT_BLUE;
+ }
+ }
+
+ /**
+ * Finds the point within this box's lowerIndex and upperIndex index of where to split.
+ *
+ * This is calculated by finding the longest color dimension, and then sorting the
+ * sub-array based on that dimension value in each color. The colors are then iterated over
+ * until a color is found with at least the midpoint of the whole box's dimension midpoint.
+ *
+ * @return the index of the colors array to split from
+ */
+ int findSplitPoint() {
+ final int longestDimension = getLongestColorDimension();
+
+ // We need to sort the colors in this box based on the longest color dimension.
+ // As we can't use a Comparator to define the sort logic, we modify each color so that
+ // it's most significant is the desired dimension
+ modifySignificantOctet(longestDimension, mLowerIndex, mUpperIndex);
+
+ // Now sort... Arrays.sort uses a exclusive toIndex so we need to add 1
+ Arrays.sort(mColors, mLowerIndex, mUpperIndex + 1);
+
+ // Now revert all of the colors so that they are packed as RGB again
+ modifySignificantOctet(longestDimension, mLowerIndex, mUpperIndex);
+
+ final int dimensionMidPoint = midPoint(longestDimension);
+
+ for (int i = mLowerIndex; i <= mUpperIndex; i++) {
+ final int color = mColors[i];
+
+ switch (longestDimension) {
+ case COMPONENT_RED:
+ if (Color.red(color) >= dimensionMidPoint) {
+ return i;
+ }
+ break;
+ case COMPONENT_GREEN:
+ if (Color.green(color) >= dimensionMidPoint) {
+ return i;
+ }
+ break;
+ case COMPONENT_BLUE:
+ if (Color.blue(color) > dimensionMidPoint) {
+ return i;
+ }
+ break;
+ }
+ }
+
+ return mLowerIndex;
+ }
+
+ /**
+ * @return the average color of this box.
+ */
+ Swatch getAverageColor() {
+ int redSum = 0;
+ int greenSum = 0;
+ int blueSum = 0;
+ int totalPopulation = 0;
+
+ for (int i = mLowerIndex; i <= mUpperIndex; i++) {
+ final int color = mColors[i];
+ final int colorPopulation = mColorPopulations.get(color);
+
+ totalPopulation += colorPopulation;
+ redSum += colorPopulation * Color.red(color);
+ greenSum += colorPopulation * Color.green(color);
+ blueSum += colorPopulation * Color.blue(color);
+ }
+
+ final int redAverage = Math.round(redSum / (float) totalPopulation);
+ final int greenAverage = Math.round(greenSum / (float) totalPopulation);
+ final int blueAverage = Math.round(blueSum / (float) totalPopulation);
+
+ return new Swatch(redAverage, greenAverage, blueAverage, totalPopulation);
+ }
+
+ /**
+ * @return the midpoint of this box in the given {@code dimension}
+ */
+ int midPoint(int dimension) {
+ switch (dimension) {
+ case COMPONENT_RED:
+ default:
+ return (mMinRed + mMaxRed) / 2;
+ case COMPONENT_GREEN:
+ return (mMinGreen + mMaxGreen) / 2;
+ case COMPONENT_BLUE:
+ return (mMinBlue + mMaxBlue) / 2;
+ }
+ }
+ }
+
+ /**
+ * Modify the significant octet in a packed color int. Allows sorting based on the value of a
+ * single color component.
+ *
+ * @see Vbox#findSplitPoint()
+ */
+ private void modifySignificantOctet(final int dimension, int lowerIndex, int upperIndex) {
+ switch (dimension) {
+ case COMPONENT_RED:
+ // Already in RGB, no need to do anything
+ break;
+ case COMPONENT_GREEN:
+ // We need to do a RGB to GRB swap, or vice-versa
+ for (int i = lowerIndex; i <= upperIndex; i++) {
+ final int color = mColors[i];
+ mColors[i] = Color.rgb((color >> 8) & 0xFF, (color >> 16) & 0xFF, color & 0xFF);
+ }
+ break;
+ case COMPONENT_BLUE:
+ // We need to do a RGB to BGR swap, or vice-versa
+ for (int i = lowerIndex; i <= upperIndex; i++) {
+ final int color = mColors[i];
+ mColors[i] = Color.rgb(color & 0xFF, (color >> 8) & 0xFF, (color >> 16) & 0xFF);
+ }
+ break;
+ }
+ }
+
+ private boolean shouldIgnoreColor(int color) {
+ com.android.internal.util.cm.palette.ColorUtils.RGBtoHSL(Color.red(color), Color.green(color), Color.blue(color), mTempHsl);
+ return shouldIgnoreColor(mTempHsl);
+ }
+
+ private static boolean shouldIgnoreColor(Swatch color) {
+ return shouldIgnoreColor(color.getHsl());
+ }
+
+ private static boolean shouldIgnoreColor(float[] hslColor) {
+ return isWhite(hslColor) || isBlack(hslColor) || isNearRedILine(hslColor);
+ }
+
+ /**
+ * @return true if the color represents a color which is close to black.
+ */
+ private static boolean isBlack(float[] hslColor) {
+ return hslColor[2] <= BLACK_MAX_LIGHTNESS;
+ }
+
+ /**
+ * @return true if the color represents a color which is close to white.
+ */
+ private static boolean isWhite(float[] hslColor) {
+ return hslColor[2] >= WHITE_MIN_LIGHTNESS;
+ }
+
+ /**
+ * @return true if the color lies close to the red side of the I line.
+ */
+ private static boolean isNearRedILine(float[] hslColor) {
+ return hslColor[0] >= 10f && hslColor[0] <= 37f && hslColor[1] <= 0.82f;
+ }
+
+ /**
+ * Comparator which sorts {@link Vbox} instances based on their volume, in descending order
+ */
+ private static final Comparator<Vbox> VBOX_COMPARATOR_VOLUME = new Comparator<Vbox>() {
+ @Override
+ public int compare(Vbox lhs, Vbox rhs) {
+ return rhs.getVolume() - lhs.getVolume();
+ }
+ };
+
+}
diff --git a/core/java/com/android/internal/util/cm/palette/ColorHistogram.java b/core/java/com/android/internal/util/cm/palette/ColorHistogram.java
new file mode 100644
index 0000000..741982d
--- /dev/null
+++ b/core/java/com/android/internal/util/cm/palette/ColorHistogram.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.util.cm.palette;
+
+import java.util.Arrays;
+
+/**
+ * Class which provides a histogram for RGB values.
+ *
+ * @hide
+ */
+final class ColorHistogram {
+
+ private final int[] mColors;
+ private final int[] mColorCounts;
+ private final int mNumberColors;
+
+ /**
+ * A new {@link ColorHistogram} instance.
+ *
+ * @param pixels array of image contents
+ */
+ ColorHistogram(final int[] pixels) {
+ // Sort the pixels to enable counting below
+ Arrays.sort(pixels);
+
+ // Count number of distinct colors
+ mNumberColors = countDistinctColors(pixels);
+
+ // Create arrays
+ mColors = new int[mNumberColors];
+ mColorCounts = new int[mNumberColors];
+
+ // Finally count the frequency of each color
+ countFrequencies(pixels);
+ }
+
+ /**
+ * @return number of distinct colors in the image.
+ */
+ int getNumberOfColors() {
+ return mNumberColors;
+ }
+
+ /**
+ * @return an array containing all of the distinct colors in the image.
+ */
+ int[] getColors() {
+ return mColors;
+ }
+
+ /**
+ * @return an array containing the frequency of a distinct colors within the image.
+ */
+ int[] getColorCounts() {
+ return mColorCounts;
+ }
+
+ private static int countDistinctColors(final int[] pixels) {
+ if (pixels.length < 2) {
+ // If we have less than 2 pixels we can stop here
+ return pixels.length;
+ }
+
+ // If we have at least 2 pixels, we have a minimum of 1 color...
+ int colorCount = 1;
+ int currentColor = pixels[0];
+
+ // Now iterate from the second pixel to the end, counting distinct colors
+ for (int i = 1; i < pixels.length; i++) {
+ // If we encounter a new color, increase the population
+ if (pixels[i] != currentColor) {
+ currentColor = pixels[i];
+ colorCount++;
+ }
+ }
+
+ return colorCount;
+ }
+
+ private void countFrequencies(final int[] pixels) {
+ if (pixels.length == 0) {
+ return;
+ }
+
+ int currentColorIndex = 0;
+ int currentColor = pixels[0];
+
+ mColors[currentColorIndex] = currentColor;
+ mColorCounts[currentColorIndex] = 1;
+
+ if (pixels.length == 1) {
+ // If we only have one pixel, we can stop here
+ return;
+ }
+
+ // Now iterate from the second pixel to the end, population distinct colors
+ for (int i = 1; i < pixels.length; i++) {
+ if (pixels[i] == currentColor) {
+ // We've hit the same color as before, increase population
+ mColorCounts[currentColorIndex]++;
+ } else {
+ // We've hit a new color, increase index
+ currentColor = pixels[i];
+
+ currentColorIndex++;
+ mColors[currentColorIndex] = currentColor;
+ mColorCounts[currentColorIndex] = 1;
+ }
+ }
+ }
+
+}
diff --git a/core/java/com/android/internal/util/cm/palette/ColorUtils.java b/core/java/com/android/internal/util/cm/palette/ColorUtils.java
new file mode 100644
index 0000000..c081cf6
--- /dev/null
+++ b/core/java/com/android/internal/util/cm/palette/ColorUtils.java
@@ -0,0 +1,232 @@
+/*
+ * Copyright 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.util.cm.palette;
+
+import android.graphics.Color;
+
+/** @hide */
+final class ColorUtils {
+
+ private static final int MIN_ALPHA_SEARCH_MAX_ITERATIONS = 10;
+ private static final int MIN_ALPHA_SEARCH_PRECISION = 10;
+
+ private ColorUtils() {}
+
+ /**
+ * Composite two potentially translucent colors over each other and returns the result.
+ */
+ private static int compositeColors(int fg, int bg) {
+ final float alpha1 = Color.alpha(fg) / 255f;
+ final float alpha2 = Color.alpha(bg) / 255f;
+
+ float a = (alpha1 + alpha2) * (1f - alpha1);
+ float r = (Color.red(fg) * alpha1) + (Color.red(bg) * alpha2 * (1f - alpha1));
+ float g = (Color.green(fg) * alpha1) + (Color.green(bg) * alpha2 * (1f - alpha1));
+ float b = (Color.blue(fg) * alpha1) + (Color.blue(bg) * alpha2 * (1f - alpha1));
+
+ return Color.argb((int) a, (int) r, (int) g, (int) b);
+ }
+
+ /**
+ * Returns the luminance of a color.
+ *
+ * Formula defined here: http://www.w3.org/TR/2008/REC-WCAG20-20081211/#relativeluminancedef
+ */
+ private static double calculateLuminance(int color) {
+ double red = Color.red(color) / 255d;
+ red = red < 0.03928 ? red / 12.92 : Math.pow((red + 0.055) / 1.055, 2.4);
+
+ double green = Color.green(color) / 255d;
+ green = green < 0.03928 ? green / 12.92 : Math.pow((green + 0.055) / 1.055, 2.4);
+
+ double blue = Color.blue(color) / 255d;
+ blue = blue < 0.03928 ? blue / 12.92 : Math.pow((blue + 0.055) / 1.055, 2.4);
+
+ return (0.2126 * red) + (0.7152 * green) + (0.0722 * blue);
+ }
+
+ /**
+ * Returns the contrast ratio between two colors.
+ *
+ * Formula defined here: http://www.w3.org/TR/2008/REC-WCAG20-20081211/#contrast-ratiodef
+ */
+ private static double calculateContrast(int foreground, int background) {
+ if (Color.alpha(background) != 255) {
+ throw new IllegalArgumentException("background can not be translucent");
+ }
+ if (Color.alpha(foreground) < 255) {
+ // If the foreground is translucent, composite the foreground over the background
+ foreground = compositeColors(foreground, background);
+ }
+
+ final double luminance1 = calculateLuminance(foreground) + 0.05;
+ final double luminance2 = calculateLuminance(background) + 0.05;
+
+ // Now return the lighter luminance divided by the darker luminance
+ return Math.max(luminance1, luminance2) / Math.min(luminance1, luminance2);
+ }
+
+ /**
+ * Finds the minimum alpha value which can be applied to {@code foreground} so that is has a
+ * contrast value of at least {@code minContrastRatio} when compared to background.
+ *
+ * @return the alpha value in the range 0-255.
+ */
+ private static int findMinimumAlpha(int foreground, int background, double minContrastRatio) {
+ if (Color.alpha(background) != 255) {
+ throw new IllegalArgumentException("background can not be translucent");
+ }
+
+ // First lets check that a fully opaque foreground has sufficient contrast
+ int testForeground = modifyAlpha(foreground, 255);
+ double testRatio = calculateContrast(testForeground, background);
+ if (testRatio < minContrastRatio) {
+ // Fully opaque foreground does not have sufficient contrast, return error
+ return -1;
+ }
+
+ // Binary search to find a value with the minimum value which provides sufficient contrast
+ int numIterations = 0;
+ int minAlpha = 0;
+ int maxAlpha = 255;
+
+ while (numIterations <= MIN_ALPHA_SEARCH_MAX_ITERATIONS &&
+ (maxAlpha - minAlpha) > MIN_ALPHA_SEARCH_PRECISION) {
+ final int testAlpha = (minAlpha + maxAlpha) / 2;
+
+ testForeground = modifyAlpha(foreground, testAlpha);
+ testRatio = calculateContrast(testForeground, background);
+
+ if (testRatio < minContrastRatio) {
+ minAlpha = testAlpha;
+ } else {
+ maxAlpha = testAlpha;
+ }
+
+ numIterations++;
+ }
+
+ // Conservatively return the max of the range of possible alphas, which is known to pass.
+ return maxAlpha;
+ }
+
+ static int getTextColorForBackground(int backgroundColor, int textColor, float minContrastRatio) {
+ final int minAlpha = ColorUtils
+ .findMinimumAlpha(textColor, backgroundColor, minContrastRatio);
+
+ if (minAlpha >= 0) {
+ return ColorUtils.modifyAlpha(textColor, minAlpha);
+ }
+
+ // Didn't find an opacity which provided enough contrast
+ return -1;
+ }
+
+ static void RGBtoHSL(int r, int g, int b, float[] hsl) {
+ final float rf = r / 255f;
+ final float gf = g / 255f;
+ final float bf = b / 255f;
+
+ final float max = Math.max(rf, Math.max(gf, bf));
+ final float min = Math.min(rf, Math.min(gf, bf));
+ final float deltaMaxMin = max - min;
+
+ float h, s;
+ float l = (max + min) / 2f;
+
+ if (max == min) {
+ // Monochromatic
+ h = s = 0f;
+ } else {
+ if (max == rf) {
+ h = ((gf - bf) / deltaMaxMin) % 6f;
+ } else if (max == gf) {
+ h = ((bf - rf) / deltaMaxMin) + 2f;
+ } else {
+ h = ((rf - gf) / deltaMaxMin) + 4f;
+ }
+
+ s = deltaMaxMin / (1f - Math.abs(2f * l - 1f));
+ }
+
+ hsl[0] = (h * 60f) % 360f;
+ hsl[1] = s;
+ hsl[2] = l;
+ }
+
+ static int HSLtoRGB (float[] hsl) {
+ final float h = hsl[0];
+ final float s = hsl[1];
+ final float l = hsl[2];
+
+ final float c = (1f - Math.abs(2 * l - 1f)) * s;
+ final float m = l - 0.5f * c;
+ final float x = c * (1f - Math.abs((h / 60f % 2f) - 1f));
+
+ final int hueSegment = (int) h / 60;
+
+ int r = 0, g = 0, b = 0;
+
+ switch (hueSegment) {
+ case 0:
+ r = Math.round(255 * (c + m));
+ g = Math.round(255 * (x + m));
+ b = Math.round(255 * m);
+ break;
+ case 1:
+ r = Math.round(255 * (x + m));
+ g = Math.round(255 * (c + m));
+ b = Math.round(255 * m);
+ break;
+ case 2:
+ r = Math.round(255 * m);
+ g = Math.round(255 * (c + m));
+ b = Math.round(255 * (x + m));
+ break;
+ case 3:
+ r = Math.round(255 * m);
+ g = Math.round(255 * (x + m));
+ b = Math.round(255 * (c + m));
+ break;
+ case 4:
+ r = Math.round(255 * (x + m));
+ g = Math.round(255 * m);
+ b = Math.round(255 * (c + m));
+ break;
+ case 5:
+ case 6:
+ r = Math.round(255 * (c + m));
+ g = Math.round(255 * m);
+ b = Math.round(255 * (x + m));
+ break;
+ }
+
+ r = Math.max(0, Math.min(255, r));
+ g = Math.max(0, Math.min(255, g));
+ b = Math.max(0, Math.min(255, b));
+
+ return Color.rgb(r, g, b);
+ }
+
+ /**
+ * Set the alpha component of {@code color} to be {@code alpha}.
+ */
+ static int modifyAlpha(int color, int alpha) {
+ return (color & 0x00ffffff) | (alpha << 24);
+ }
+
+}
diff --git a/core/java/com/android/internal/util/cm/palette/Palette.java b/core/java/com/android/internal/util/cm/palette/Palette.java
new file mode 100644
index 0000000..d0a62f0
--- /dev/null
+++ b/core/java/com/android/internal/util/cm/palette/Palette.java
@@ -0,0 +1,688 @@
+/*
+ * Copyright 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.util.cm.palette;
+
+import android.graphics.Bitmap;
+import android.graphics.Color;
+import android.os.AsyncTask;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * A helper class to extract prominent colors from an image.
+ * <p>
+ * A number of colors with different profiles are extracted from the image:
+ * <ul>
+ * <li>Vibrant</li>
+ * <li>Vibrant Dark</li>
+ * <li>Vibrant Light</li>
+ * <li>Muted</li>
+ * <li>Muted Dark</li>
+ * <li>Muted Light</li>
+ * </ul>
+ * These can be retrieved from the appropriate getter method.
+ *
+ * <p>
+ * Instances can be created with the synchronous factory methods {@link #generate(Bitmap)} and
+ * {@link #generate(Bitmap, int)}.
+ * <p>
+ * These should be called on a background thread, ideally the one in
+ * which you load your images on. Sometimes that is not possible, so asynchronous factory methods
+ * have also been provided: {@link #generateAsync(Bitmap, PaletteAsyncListener)} and
+ * {@link #generateAsync(Bitmap, int, PaletteAsyncListener)}. These can be used as so:
+ *
+ * <pre>
+ * Palette.generateAsync(bitmap, new Palette.PaletteAsyncListener() {
+ * public void onGenerated(Palette palette) {
+ * // Do something with colors...
+ * }
+ * });
+ * </pre>
+ *
+ * @hide
+ */
+public final class Palette {
+
+ /**
+ * Listener to be used with {@link #generateAsync(Bitmap, PaletteAsyncListener)} or
+ * {@link #generateAsync(Bitmap, int, PaletteAsyncListener)}
+ */
+ public interface PaletteAsyncListener {
+
+ /**
+ * Called when the {@link Palette} has been generated.
+ */
+ void onGenerated(Palette palette);
+ }
+
+ private static final int CALCULATE_BITMAP_MIN_DIMENSION = 100;
+ private static final int DEFAULT_CALCULATE_NUMBER_COLORS = 16;
+
+ private static final float TARGET_DARK_LUMA = 0.26f;
+ private static final float MAX_DARK_LUMA = 0.45f;
+
+ private static final float MIN_LIGHT_LUMA = 0.55f;
+ private static final float TARGET_LIGHT_LUMA = 0.74f;
+
+ private static final float MIN_NORMAL_LUMA = 0.3f;
+ private static final float TARGET_NORMAL_LUMA = 0.5f;
+ private static final float MAX_NORMAL_LUMA = 0.7f;
+
+ private static final float TARGET_MUTED_SATURATION = 0.3f;
+ private static final float MAX_MUTED_SATURATION = 0.4f;
+
+ private static final float TARGET_VIBRANT_SATURATION = 1f;
+ private static final float MIN_VIBRANT_SATURATION = 0.35f;
+
+ private static final float WEIGHT_SATURATION = 3f;
+ private static final float WEIGHT_LUMA = 6f;
+ private static final float WEIGHT_POPULATION = 1f;
+
+ private static final float MIN_CONTRAST_TITLE_TEXT = 3.0f;
+ private static final float MIN_CONTRAST_BODY_TEXT = 4.5f;
+
+ private final List<Swatch> mSwatches;
+ private final int mHighestPopulation;
+
+ private Swatch mVibrantSwatch;
+ private Swatch mMutedSwatch;
+
+ private Swatch mDarkVibrantSwatch;
+ private Swatch mDarkMutedSwatch;
+
+ private Swatch mLightVibrantSwatch;
+ private Swatch mLightMutedColor;
+
+ /**
+ * Generate a {@link Palette} from a {@link Bitmap} using the default number of colors.
+ */
+ public static Palette generate(Bitmap bitmap) {
+ return generate(bitmap, DEFAULT_CALCULATE_NUMBER_COLORS);
+ }
+
+ /**
+ * Generate a {@link Palette} from a {@link Bitmap} using the specified {@code numColors}.
+ * Good values for {@code numColors} depend on the source image type.
+ * For landscapes, a good values are in the range 12-16. For images which are largely made up
+ * of people's faces then this value should be increased to 24-32.
+ *
+ * @param numColors The maximum number of colors in the generated palette. Increasing this
+ * number will increase the time needed to compute the values.
+ */
+ public static Palette generate(Bitmap bitmap, int numColors) {
+ checkBitmapParam(bitmap);
+ checkNumberColorsParam(numColors);
+
+ // First we'll scale down the bitmap so it's shortest dimension is 100px
+ final Bitmap scaledBitmap = scaleBitmapDown(bitmap);
+
+ // Now generate a quantizer from the Bitmap
+ ColorCutQuantizer quantizer = ColorCutQuantizer.fromBitmap(scaledBitmap, numColors);
+
+ // If created a new bitmap, recycle it
+ if (scaledBitmap != bitmap) {
+ scaledBitmap.recycle();
+ }
+
+ // Now return a ColorExtractor instance
+ return new Palette(quantizer.getQuantizedColors());
+ }
+
+ /**
+ * Generate a {@link Palette} asynchronously. {@link PaletteAsyncListener#onGenerated(Palette)}
+ * will be called with the created instance. The resulting {@link Palette} is the same as
+ * what would be created by calling {@link #generate(Bitmap)}.
+ *
+ * @param listener Listener to be invoked when the {@link Palette} has been generated.
+ *
+ * @return the {@link AsyncTask} used to asynchronously generate the instance.
+ */
+ public static AsyncTask<Bitmap, Void, Palette> generateAsync(
+ Bitmap bitmap, PaletteAsyncListener listener) {
+ return generateAsync(bitmap, DEFAULT_CALCULATE_NUMBER_COLORS, listener);
+ }
+
+ /**
+ * Generate a {@link Palette} asynchronously. {@link PaletteAsyncListener#onGenerated(Palette)}
+ * will be called with the created instance. The resulting {@link Palette} is the same as what
+ * would be created by calling {@link #generate(Bitmap, int)}.
+ *
+ * @param listener Listener to be invoked when the {@link Palette} has been generated.
+ *
+ * @return the {@link AsyncTask} used to asynchronously generate the instance.
+ */
+ public static AsyncTask<Bitmap, Void, Palette> generateAsync(
+ final Bitmap bitmap, final int numColors, final PaletteAsyncListener listener) {
+ checkBitmapParam(bitmap);
+ checkNumberColorsParam(numColors);
+ checkAsyncListenerParam(listener);
+
+ AsyncTask<Bitmap, Void, Palette> task = new AsyncTask<Bitmap, Void, Palette>() {
+ @Override
+ protected Palette doInBackground(Bitmap... params) {
+ return generate(params[0], numColors);
+ }
+
+ @Override
+ protected void onPostExecute(Palette colorExtractor) {
+ listener.onGenerated(colorExtractor);
+ }
+ };
+ task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, bitmap);
+
+ return task;
+ }
+
+ /**
+ * Generate a {@link Palette} from the pre-generated list of {@link Palette.Swatch} swatches.
+ * This is useful for testing, or if you want to resurrect a {@link Palette} instance from a
+ * list of swatches. Will return null if the {@code swatches} is null.
+ */
+ public static Palette from(List<Swatch> swatches) {
+ if (swatches == null) {
+ return null;
+ }
+ return new Palette(swatches);
+ }
+
+ private Palette(List<Swatch> swatches) {
+ mSwatches = swatches;
+ mHighestPopulation = findMaxPopulation();
+
+ mVibrantSwatch = findColor(TARGET_NORMAL_LUMA, MIN_NORMAL_LUMA, MAX_NORMAL_LUMA,
+ TARGET_VIBRANT_SATURATION, MIN_VIBRANT_SATURATION, 1f);
+
+ mLightVibrantSwatch = findColor(TARGET_LIGHT_LUMA, MIN_LIGHT_LUMA, 1f,
+ TARGET_VIBRANT_SATURATION, MIN_VIBRANT_SATURATION, 1f);
+
+ mDarkVibrantSwatch = findColor(TARGET_DARK_LUMA, 0f, MAX_DARK_LUMA,
+ TARGET_VIBRANT_SATURATION, MIN_VIBRANT_SATURATION, 1f);
+
+ mMutedSwatch = findColor(TARGET_NORMAL_LUMA, MIN_NORMAL_LUMA, MAX_NORMAL_LUMA,
+ TARGET_MUTED_SATURATION, 0f, MAX_MUTED_SATURATION);
+
+ mLightMutedColor = findColor(TARGET_LIGHT_LUMA, MIN_LIGHT_LUMA, 1f,
+ TARGET_MUTED_SATURATION, 0f, MAX_MUTED_SATURATION);
+
+ mDarkMutedSwatch = findColor(TARGET_DARK_LUMA, 0f, MAX_DARK_LUMA,
+ TARGET_MUTED_SATURATION, 0f, MAX_MUTED_SATURATION);
+
+ // Now try and generate any missing colors
+ generateEmptySwatches();
+ }
+
+ /**
+ * Returns all of the swatches which make up the palette.
+ */
+ public List<Swatch> getSwatches() {
+ return Collections.unmodifiableList(mSwatches);
+ }
+
+ /**
+ * Returns the most vibrant swatch in the palette. Might be null.
+ */
+ public Swatch getVibrantSwatch() {
+ return mVibrantSwatch;
+ }
+
+ /**
+ * Returns a light and vibrant swatch from the palette. Might be null.
+ */
+ public Swatch getLightVibrantSwatch() {
+ return mLightVibrantSwatch;
+ }
+
+ /**
+ * Returns a dark and vibrant swatch from the palette. Might be null.
+ */
+ public Swatch getDarkVibrantSwatch() {
+ return mDarkVibrantSwatch;
+ }
+
+ /**
+ * Returns a muted swatch from the palette. Might be null.
+ */
+ public Swatch getMutedSwatch() {
+ return mMutedSwatch;
+ }
+
+ /**
+ * Returns a muted and light swatch from the palette. Might be null.
+ */
+ public Swatch getLightMutedSwatch() {
+ return mLightMutedColor;
+ }
+
+ /**
+ * Returns a muted and dark swatch from the palette. Might be null.
+ */
+ public Swatch getDarkMutedSwatch() {
+ return mDarkMutedSwatch;
+ }
+
+ /**
+ * Returns the most vibrant color in the palette as an RGB packed int.
+ *
+ * @param defaultColor value to return if the swatch isn't available
+ */
+ public int getVibrantColor(int defaultColor) {
+ return mVibrantSwatch != null ? mVibrantSwatch.getRgb() : defaultColor;
+ }
+
+ /**
+ * Returns a light and vibrant color from the palette as an RGB packed int.
+ *
+ * @param defaultColor value to return if the swatch isn't available
+ */
+ public int getLightVibrantColor(int defaultColor) {
+ return mLightVibrantSwatch != null ? mLightVibrantSwatch.getRgb() : defaultColor;
+ }
+
+ /**
+ * Returns a dark and vibrant color from the palette as an RGB packed int.
+ *
+ * @param defaultColor value to return if the swatch isn't available
+ */
+ public int getDarkVibrantColor(int defaultColor) {
+ return mDarkVibrantSwatch != null ? mDarkVibrantSwatch.getRgb() : defaultColor;
+ }
+
+ /**
+ * Returns a muted color from the palette as an RGB packed int.
+ *
+ * @param defaultColor value to return if the swatch isn't available
+ */
+ public int getMutedColor(int defaultColor) {
+ return mMutedSwatch != null ? mMutedSwatch.getRgb() : defaultColor;
+ }
+
+ /**
+ * Returns a muted and light color from the palette as an RGB packed int.
+ *
+ * @param defaultColor value to return if the swatch isn't available
+ */
+ public int getLightMutedColor(int defaultColor) {
+ return mLightMutedColor != null ? mLightMutedColor.getRgb() : defaultColor;
+ }
+
+ /**
+ * Returns a muted and dark color from the palette as an RGB packed int.
+ *
+ * @param defaultColor value to return if the swatch isn't available
+ */
+ public int getDarkMutedColor(int defaultColor) {
+ return mDarkMutedSwatch != null ? mDarkMutedSwatch.getRgb() : defaultColor;
+ }
+
+ /**
+ * @return true if we have already selected {@code swatch}
+ */
+ private boolean isAlreadySelected(Swatch swatch) {
+ return mVibrantSwatch == swatch || mDarkVibrantSwatch == swatch ||
+ mLightVibrantSwatch == swatch || mMutedSwatch == swatch ||
+ mDarkMutedSwatch == swatch || mLightMutedColor == swatch;
+ }
+
+ private Swatch findColor(float targetLuma, float minLuma, float maxLuma,
+ float targetSaturation, float minSaturation, float maxSaturation) {
+ Swatch max = null;
+ float maxValue = 0f;
+
+ for (Swatch swatch : mSwatches) {
+ final float sat = swatch.getHsl()[1];
+ final float luma = swatch.getHsl()[2];
+
+ if (sat >= minSaturation && sat <= maxSaturation &&
+ luma >= minLuma && luma <= maxLuma &&
+ !isAlreadySelected(swatch)) {
+ float thisValue = createComparisonValue(sat, targetSaturation, luma, targetLuma,
+ swatch.getPopulation(), mHighestPopulation);
+ if (max == null || thisValue > maxValue) {
+ max = swatch;
+ maxValue = thisValue;
+ }
+ }
+ }
+
+ return max;
+ }
+
+ /**
+ * Try and generate any missing swatches from the swatches we did find.
+ */
+ private void generateEmptySwatches() {
+ if (mVibrantSwatch == null) {
+ // If we do not have a vibrant color...
+ if (mDarkVibrantSwatch != null) {
+ // ...but we do have a dark vibrant, generate the value by modifying the luma
+ final float[] newHsl = copyHslValues(mDarkVibrantSwatch);
+ newHsl[2] = TARGET_NORMAL_LUMA;
+ mVibrantSwatch = new Swatch(ColorUtils.HSLtoRGB(newHsl), 0);
+ }
+ }
+
+ if (mDarkVibrantSwatch == null) {
+ // If we do not have a dark vibrant color...
+ if (mVibrantSwatch != null) {
+ // ...but we do have a vibrant, generate the value by modifying the luma
+ final float[] newHsl = copyHslValues(mVibrantSwatch);
+ newHsl[2] = TARGET_DARK_LUMA;
+ mDarkVibrantSwatch = new Swatch(ColorUtils.HSLtoRGB(newHsl), 0);
+ }
+ }
+ }
+
+ /**
+ * Find the {@link Swatch} with the highest population value and return the population.
+ */
+ private int findMaxPopulation() {
+ int population = 0;
+ for (Swatch swatch : mSwatches) {
+ population = Math.max(population, swatch.getPopulation());
+ }
+ return population;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ Palette palette = (Palette) o;
+
+ if (mSwatches != null ? !mSwatches.equals(palette.mSwatches) : palette.mSwatches != null) {
+ return false;
+ }
+ if (mDarkMutedSwatch != null ? !mDarkMutedSwatch.equals(palette.mDarkMutedSwatch)
+ : palette.mDarkMutedSwatch != null) {
+ return false;
+ }
+ if (mDarkVibrantSwatch != null ? !mDarkVibrantSwatch.equals(palette.mDarkVibrantSwatch)
+ : palette.mDarkVibrantSwatch != null) {
+ return false;
+ }
+ if (mLightMutedColor != null ? !mLightMutedColor.equals(palette.mLightMutedColor)
+ : palette.mLightMutedColor != null) {
+ return false;
+ }
+ if (mLightVibrantSwatch != null ? !mLightVibrantSwatch.equals(palette.mLightVibrantSwatch)
+ : palette.mLightVibrantSwatch != null) {
+ return false;
+ }
+ if (mMutedSwatch != null ? !mMutedSwatch.equals(palette.mMutedSwatch)
+ : palette.mMutedSwatch != null) {
+ return false;
+ }
+ if (mVibrantSwatch != null ? !mVibrantSwatch.equals(palette.mVibrantSwatch)
+ : palette.mVibrantSwatch != null) {
+ return false;
+ }
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = mSwatches != null ? mSwatches.hashCode() : 0;
+ result = 31 * result + (mVibrantSwatch != null ? mVibrantSwatch.hashCode() : 0);
+ result = 31 * result + (mMutedSwatch != null ? mMutedSwatch.hashCode() : 0);
+ result = 31 * result + (mDarkVibrantSwatch != null ? mDarkVibrantSwatch.hashCode() : 0);
+ result = 31 * result + (mDarkMutedSwatch != null ? mDarkMutedSwatch.hashCode() : 0);
+ result = 31 * result + (mLightVibrantSwatch != null ? mLightVibrantSwatch.hashCode() : 0);
+ result = 31 * result + (mLightMutedColor != null ? mLightMutedColor.hashCode() : 0);
+ return result;
+ }
+
+ /**
+ * Scale the bitmap down so that it's smallest dimension is
+ * {@value #CALCULATE_BITMAP_MIN_DIMENSION}px. If {@code bitmap} is smaller than this, than it
+ * is returned.
+ */
+ private static Bitmap scaleBitmapDown(Bitmap bitmap) {
+ final int minDimension = Math.min(bitmap.getWidth(), bitmap.getHeight());
+
+ if (minDimension <= CALCULATE_BITMAP_MIN_DIMENSION) {
+ // If the bitmap is small enough already, just return it
+ return bitmap;
+ }
+
+ final float scaleRatio = CALCULATE_BITMAP_MIN_DIMENSION / (float) minDimension;
+ return Bitmap.createScaledBitmap(bitmap,
+ Math.round(bitmap.getWidth() * scaleRatio),
+ Math.round(bitmap.getHeight() * scaleRatio),
+ false);
+ }
+
+ private static float createComparisonValue(float saturation, float targetSaturation,
+ float luma, float targetLuma,
+ int population, int highestPopulation) {
+ return weightedMean(
+ invertDiff(saturation, targetSaturation), WEIGHT_SATURATION,
+ invertDiff(luma, targetLuma), WEIGHT_LUMA,
+ population / (float) highestPopulation, WEIGHT_POPULATION
+ );
+ }
+
+ /**
+ * Copy a {@link Swatch}'s HSL values into a new float[].
+ */
+ private static float[] copyHslValues(Swatch color) {
+ final float[] newHsl = new float[3];
+ System.arraycopy(color.getHsl(), 0, newHsl, 0, 3);
+ return newHsl;
+ }
+
+ /**
+ * Returns a value in the range 0-1. 1 is returned when {@code value} equals the
+ * {@code targetValue} and then decreases as the absolute difference between {@code value} and
+ * {@code targetValue} increases.
+ *
+ * @param value the item's value
+ * @param targetValue the value which we desire
+ */
+ private static float invertDiff(float value, float targetValue) {
+ return 1f - Math.abs(value - targetValue);
+ }
+
+ private static float weightedMean(float... values) {
+ float sum = 0f;
+ float sumWeight = 0f;
+
+ for (int i = 0; i < values.length; i += 2) {
+ float value = values[i];
+ float weight = values[i + 1];
+
+ sum += (value * weight);
+ sumWeight += weight;
+ }
+
+ return sum / sumWeight;
+ }
+
+ private static void checkBitmapParam(Bitmap bitmap) {
+ if (bitmap == null) {
+ throw new IllegalArgumentException("bitmap can not be null");
+ }
+ if (bitmap.isRecycled()) {
+ throw new IllegalArgumentException("bitmap can not be recycled");
+ }
+ }
+
+ private static void checkNumberColorsParam(int numColors) {
+ if (numColors < 1) {
+ throw new IllegalArgumentException("numColors must be 1 of greater");
+ }
+ }
+
+ private static void checkAsyncListenerParam(PaletteAsyncListener listener) {
+ if (listener == null) {
+ throw new IllegalArgumentException("listener can not be null");
+ }
+ }
+
+ /**
+ * Represents a color swatch generated from an image's palette. The RGB color can be retrieved
+ * by calling {@link #getRgb()}.
+ */
+ public static final class Swatch {
+ private final int mRed, mGreen, mBlue;
+ private final int mRgb;
+ private final int mPopulation;
+
+ private boolean mGeneratedTextColors;
+ private int mTitleTextColor;
+ private int mBodyTextColor;
+
+ private float[] mHsl;
+
+ public Swatch(int color, int population) {
+ mRed = Color.red(color);
+ mGreen = Color.green(color);
+ mBlue = Color.blue(color);
+ mRgb = color;
+ mPopulation = population;
+ }
+
+ Swatch(int red, int green, int blue, int population) {
+ mRed = red;
+ mGreen = green;
+ mBlue = blue;
+ mRgb = Color.rgb(red, green, blue);
+ mPopulation = population;
+ }
+
+ /**
+ * @return this swatch's RGB color value
+ */
+ public int getRgb() {
+ return mRgb;
+ }
+
+ /**
+ * Return this swatch's HSL values.
+ * hsv[0] is Hue [0 .. 360)
+ * hsv[1] is Saturation [0...1]
+ * hsv[2] is Lightness [0...1]
+ */
+ public float[] getHsl() {
+ if (mHsl == null) {
+ // Lazily generate HSL values from RGB
+ mHsl = new float[3];
+ ColorUtils.RGBtoHSL(mRed, mGreen, mBlue, mHsl);
+ }
+ return mHsl;
+ }
+
+ /**
+ * @return the number of pixels represented by this swatch
+ */
+ public int getPopulation() {
+ return mPopulation;
+ }
+
+ /**
+ * Returns an appropriate color to use for any 'title' text which is displayed over this
+ * {@link Swatch}'s color. This color is guaranteed to have sufficient contrast.
+ */
+ public int getTitleTextColor() {
+ ensureTextColorsGenerated();
+ return mTitleTextColor;
+ }
+
+ /**
+ * Returns an appropriate color to use for any 'body' text which is displayed over this
+ * {@link Swatch}'s color. This color is guaranteed to have sufficient contrast.
+ */
+ public int getBodyTextColor() {
+ ensureTextColorsGenerated();
+ return mBodyTextColor;
+ }
+
+ private void ensureTextColorsGenerated() {
+ if (!mGeneratedTextColors) {
+ // First check white, as most colors will be dark
+ final int lightBody = ColorUtils.getTextColorForBackground(
+ mRgb, Color.WHITE, MIN_CONTRAST_BODY_TEXT);
+ final int lightTitle = ColorUtils.getTextColorForBackground(
+ mRgb, Color.WHITE, MIN_CONTRAST_TITLE_TEXT);
+
+ if (lightBody != -1 && lightTitle != -1) {
+ // If we found valid light values, use them and return
+ mBodyTextColor = lightBody;
+ mTitleTextColor = lightTitle;
+ mGeneratedTextColors = true;
+ return;
+ }
+
+ final int darkBody = ColorUtils.getTextColorForBackground(
+ mRgb, Color.BLACK, MIN_CONTRAST_BODY_TEXT);
+ final int darkTitle = ColorUtils.getTextColorForBackground(
+ mRgb, Color.BLACK, MIN_CONTRAST_TITLE_TEXT);
+
+ if (darkBody != -1 && darkBody != -1) {
+ // If we found valid dark values, use them and return
+ mBodyTextColor = darkBody;
+ mTitleTextColor = darkTitle;
+ mGeneratedTextColors = true;
+ return;
+ }
+
+ // If we reach here then we can not find title and body values which use the same
+ // lightness, we need to use mismatched values
+ mBodyTextColor = lightBody != -1 ? lightBody : darkBody;
+ mTitleTextColor = lightTitle != -1 ? lightTitle : darkTitle;
+ mGeneratedTextColors = true;
+ }
+ }
+
+ @Override
+ public String toString() {
+ return new StringBuilder(getClass().getSimpleName())
+ .append(" [RGB: #").append(Integer.toHexString(getRgb())).append(']')
+ .append(" [HSL: ").append(Arrays.toString(getHsl())).append(']')
+ .append(" [Population: ").append(mPopulation).append(']')
+ .append(" [Title Text: #").append(Integer.toHexString(mTitleTextColor)).append(']')
+ .append(" [Body Text: #").append(Integer.toHexString(mBodyTextColor)).append(']')
+ .toString();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ Swatch swatch = (Swatch) o;
+ return mPopulation == swatch.mPopulation && mRgb == swatch.mRgb;
+ }
+
+ @Override
+ public int hashCode() {
+ return 31 * mRgb + mPopulation;
+ }
+ }
+
+}
diff --git a/core/java/com/android/internal/util/gesture/EdgeGesturePosition.java b/core/java/com/android/internal/util/gesture/EdgeGesturePosition.java
new file mode 100644
index 0000000..01cfdea
--- /dev/null
+++ b/core/java/com/android/internal/util/gesture/EdgeGesturePosition.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2013 The CyanogenMod Project (Jens Doll)
+ *
+ * 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.gesture;
+
+/**
+ * Defines the positions in which gestures may be recognized by the
+ * edge gesture service.
+ * This defines an index and an flag for each position.
+ */
+public enum EdgeGesturePosition {
+ LEFT(0, 0),
+ BOTTOM(1, 1),
+ RIGHT(2, 1),
+ TOP(3, 0);
+
+ EdgeGesturePosition(int index, int factor) {
+ INDEX = index;
+ FLAG = (0x01<<index);
+ FACTOR = factor;
+ }
+
+ public final int INDEX;
+ public final int FLAG;
+ /**
+ * This is 1 when the position is not at the axis (like {@link EdgeGesturePosition.RIGHT} is
+ * at {@code Layout.getWidth()} not at {@code 0}).
+ */
+ public final int FACTOR;
+}
diff --git a/core/java/com/android/internal/util/gesture/EdgeServiceConstants.java b/core/java/com/android/internal/util/gesture/EdgeServiceConstants.java
new file mode 100644
index 0000000..4360086
--- /dev/null
+++ b/core/java/com/android/internal/util/gesture/EdgeServiceConstants.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2013 The CyanogenMod Project (Jens Doll)
+ *
+ * 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.gesture;
+
+/**
+ * Constants needed for the edge gesture service.
+ *
+ * @see com.android.internal.util.gesture.EdgeGesturePosition
+ */
+public final class EdgeServiceConstants {
+
+ private EdgeServiceConstants() {
+ // no object allowed
+ }
+
+ /**
+ * Mask for coding positions within the flags of
+ * {@code updateEdgeGestureActivationListener()}.
+ * <p>
+ * Positions are specified by {@code EdgeGesturePosition.FLAG}.
+ */
+ public static final int POSITION_MASK = 0x0000001f;
+
+ /**
+ * Mask for coding sensitivity within the flags of
+ * {@code updateEdgeGestureActivationListener()}.
+ * <p>
+ * Sensitivity influences the speed of the swipe, the trigger area, and trigger distance that
+ * is needed to activate the edge gesture.
+ */
+ public static final int SENSITIVITY_MASK = 0x70000000;
+
+ /**
+ * Number of bits to shift left, to get a integer within the {@link #SENSITIVITY_MASK}.
+ */
+ public static final int SENSITIVITY_SHIFT = 28;
+
+ /**
+ * No sensitivity specified at all, the service may choose a sensitivity level on its own.
+ */
+ public static final int SENSITIVITY_NONE = 0;
+
+ /**
+ * Default sensitivity, picked by the edge gesture service automatically.
+ */
+ public static final int SENSITIVITY_DEFAULT = 2;
+
+ /**
+ * Lowest valid sensitivity value.
+ */
+ public static final int SENSITIVITY_LOWEST = 1;
+
+ /**
+ * Highest sensitivity value.
+ */
+ public static final int SENSITIVITY_HIGHEST = 4;
+
+ /**
+ * Do not cut 10% area on th edges
+ */
+ public static final int UNRESTRICTED = 0x10;
+
+ /**
+ * This listener does not likes enabling/disabling filter
+ * because it interrupt in motion events.
+ */
+ public static final int LONG_LIVING = 0x20;
+
+}
diff --git a/core/java/com/android/internal/view/RotationPolicy.java b/core/java/com/android/internal/view/RotationPolicy.java
index b479cb1..9b4910e 100644
--- a/core/java/com/android/internal/view/RotationPolicy.java
+++ b/core/java/com/android/internal/view/RotationPolicy.java
@@ -25,6 +25,7 @@ import android.net.Uri;
import android.os.AsyncTask;
import android.os.Handler;
import android.os.RemoteException;
+import android.os.SystemProperties;
import android.os.UserHandle;
import android.provider.Settings;
import android.util.Log;
@@ -41,7 +42,8 @@ import com.android.internal.R;
public final class RotationPolicy {
private static final String TAG = "RotationPolicy";
private static final int CURRENT_ROTATION = -1;
- private static final int NATURAL_ROTATION = Surface.ROTATION_0;
+ private static final int NATURAL_ROTATION =
+ SystemProperties.getInt("persist.panel.orientation", Surface.ROTATION_0) / 90;
private RotationPolicy() {
}
@@ -72,7 +74,7 @@ public final class RotationPolicy {
* otherwise Configuration.ORIENTATION_UNDEFINED if any orientation is lockable.
*/
public static int getRotationLockOrientation(Context context) {
- if (!areAllRotationsAllowed(context)) {
+ if (!isCurrentRotationAllowed(context)) {
final Point size = new Point();
final IWindowManager wm = WindowManagerGlobal.getWindowManagerService();
try {
@@ -112,7 +114,8 @@ public final class RotationPolicy {
Settings.System.HIDE_ROTATION_LOCK_TOGGLE_FOR_ACCESSIBILITY, 0,
UserHandle.USER_CURRENT);
- final int rotation = areAllRotationsAllowed(context) ? CURRENT_ROTATION : NATURAL_ROTATION;
+ final int rotation = isCurrentRotationAllowed(context)
+ ? CURRENT_ROTATION : NATURAL_ROTATION;
setRotationLock(enabled, rotation);
}
@@ -129,8 +132,39 @@ public final class RotationPolicy {
setRotationLock(enabled, NATURAL_ROTATION);
}
- private static boolean areAllRotationsAllowed(Context context) {
- return context.getResources().getBoolean(R.bool.config_allowAllRotations);
+ public static boolean isRotationAllowed(int rotation,
+ int userRotationAngles, boolean allowAllRotations) {
+ if (userRotationAngles < 0) {
+ // Not set by user so use these defaults
+ userRotationAngles = allowAllRotations ?
+ (1 | 2 | 4 | 8) : // All angles
+ (1 | 2 | 8); // All except 180
+ }
+ switch (rotation) {
+ case Surface.ROTATION_0:
+ return (userRotationAngles & 1) != 0;
+ case Surface.ROTATION_90:
+ return (userRotationAngles & 2) != 0;
+ case Surface.ROTATION_180:
+ return (userRotationAngles & 4) != 0;
+ case Surface.ROTATION_270:
+ return (userRotationAngles & 8) != 0;
+ }
+ return false;
+ }
+
+ private static boolean isCurrentRotationAllowed(Context context) {
+ int userRotationAngles = Settings.System.getInt(context.getContentResolver(),
+ Settings.System.ACCELEROMETER_ROTATION_ANGLES, -1);
+ boolean allowAllRotations = context.getResources().getBoolean(
+ com.android.internal.R.bool.config_allowAllRotations);
+ final IWindowManager wm = WindowManagerGlobal.getWindowManagerService();
+ try {
+ return isRotationAllowed(wm.getRotation(), userRotationAngles, allowAllRotations);
+ } catch (RemoteException exc) {
+ Log.w(TAG, "Unable to getWindowManagerService.getRotation()");
+ }
+ return false;
}
private static void setRotationLock(final boolean enabled, final int rotation) {
@@ -194,4 +228,4 @@ public final class RotationPolicy {
public abstract void onChange();
}
-} \ No newline at end of file
+}
diff --git a/core/java/com/android/internal/widget/ILockSettings.aidl b/core/java/com/android/internal/widget/ILockSettings.aidl
index 4e4552d..00e41bd 100644
--- a/core/java/com/android/internal/widget/ILockSettings.aidl
+++ b/core/java/com/android/internal/widget/ILockSettings.aidl
@@ -39,4 +39,5 @@ interface ILockSettings {
void registerStrongAuthTracker(in IStrongAuthTracker tracker);
void unregisterStrongAuthTracker(in IStrongAuthTracker tracker);
void requireStrongAuth(int strongAuthReason, int userId);
+ void sanitizePassword();
}
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index 60380fb..345b99f 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -533,6 +533,17 @@ public class LockPatternUtils {
}
}
+ /**
+ * clears stored password.
+ */
+ public void sanitizePassword() {
+ try {
+ getLockSettings().sanitizePassword();
+ } catch (RemoteException re) {
+ Log.e(TAG, "Couldn't sanitize password" + re);
+ }
+ }
+
private void updateCryptoUserInfo(int userId) {
if (userId != UserHandle.USER_OWNER) {
return;
diff --git a/core/java/com/android/server/net/BaseNetworkObserver.java b/core/java/com/android/server/net/BaseNetworkObserver.java
index 3d9fb5c..c3dcd40 100644
--- a/core/java/com/android/server/net/BaseNetworkObserver.java
+++ b/core/java/com/android/server/net/BaseNetworkObserver.java
@@ -63,6 +63,11 @@ public class BaseNetworkObserver extends INetworkManagementEventObserver.Stub {
}
@Override
+ public void interfaceMessageRecevied(String message) {
+ // default no-op
+ }
+
+ @Override
public void limitReached(String limitName, String iface) {
// default no-op
}
diff --git a/core/java/org/codeaurora/camera/Android.mk b/core/java/org/codeaurora/camera/Android.mk
new file mode 100644
index 0000000..2e005f7
--- /dev/null
+++ b/core/java/org/codeaurora/camera/Android.mk
@@ -0,0 +1,30 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_MODULE:= org.codeaurora.camera
+
+# This will install the file in /system/framework
+LOCAL_MODULE_PATH := $(TARGET_OUT_JAVA_LIBRARIES)
+
+include $(BUILD_JAVA_LIBRARY)
+
+# ==== permissions ========================
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := org.codeaurora.camera.xml
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_MODULE_CLASS := ETC
+
+# This will install the file in /system/etc/permissions
+LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/permissions
+
+LOCAL_SRC_FILES := $(LOCAL_MODULE)
+
+include $(BUILD_PREBUILT)
diff --git a/core/java/org/codeaurora/camera/ExtendedFace.java b/core/java/org/codeaurora/camera/ExtendedFace.java
new file mode 100644
index 0000000..afda0b6
--- /dev/null
+++ b/core/java/org/codeaurora/camera/ExtendedFace.java
@@ -0,0 +1,211 @@
+/* Copyright (c) 2015, The Linux Foundataion. All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are
+* met:
+* * Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+* * Redistributions in binary form must reproduce the above
+* copyright notice, this list of conditions and the following
+* disclaimer in the documentation and/or other materials provided
+* with the distribution.
+* * Neither the name of The Linux Foundation nor the names of its
+* contributors may be used to endorse or promote products derived
+* from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*
+*/
+
+package org.codeaurora.camera;
+
+import android.hardware.Camera;
+
+import java.util.ArrayList;
+
+import android.os.Bundle;
+
+import android.os.SystemProperties;
+
+/**
+ * {@hide} Information about a face identified through Extended camera face
+ *
+ * <p>
+ * When face detection is used with a camera, the {@link FaceDetectionListener}
+ * returns a list of face objects for use in focusing and metering.
+ * </p>
+ *
+ * @see FaceDetectionListener
+ */
+public class ExtendedFace extends android.hardware.Camera.Face {
+ public ExtendedFace() {
+ super();
+ }
+
+ private int smileDegree = 0;
+ private int smileScore = 0;
+ private int blinkDetected = 0;
+ private int faceRecognized = 0;
+ private int gazeAngle = 0;
+ private int updownDir = 0;
+ private int leftrightDir = 0;
+ private int rollDir = 0;
+ private int leyeBlink = 0;
+ private int reyeBlink = 0;
+ private int leftrightGaze = 0;
+ private int topbottomGaze = 0;
+
+ private static final String STR_TRUE = "true";
+ private static final String STR_FALSE = "false";
+
+ /**
+ * The smilie degree for the detection of the face.
+ *
+ * @see #startFaceDetection()
+ */
+ public int getSmileDegree() {
+ return smileDegree;
+ }
+
+ /**
+ * The smilie score for the detection of the face.
+ *
+ * @see #startFaceDetection()
+ */
+ public int getSmileScore() {
+ return smileScore;
+ }
+
+ /**
+ * The smilie degree for the detection of the face.
+ *
+ * @see #startFaceDetection()
+ */
+ public int getBlinkDetected() {
+ return blinkDetected;
+ }
+
+ /**
+ * If face is recognized.
+ *
+ * @see #startFaceDetection()
+ */
+ public int getFaceRecognized() {
+ return faceRecognized;
+ }
+
+ /**
+ * The gaze angle for the detected face.
+ *
+ * @see #startFaceDetection()
+ */
+ public int getGazeAngle() {
+ return gazeAngle;
+ }
+
+ /**
+ * The up down direction for the detected face.
+ *
+ * @see #startFaceDetection()
+ */
+ public int getUpDownDirection() {
+ return updownDir;
+ }
+
+ /**
+ * The left right direction for the detected face.
+ *
+ * @see #startFaceDetection()
+ */
+ public int getLeftRightDirection() {
+ return leftrightDir;
+ }
+
+ /**
+ * The roll direction for the detected face.
+ *
+ * @see #startFaceDetection()
+ */
+ public int getRollDirection() {
+ return rollDir;
+ }
+
+ /**
+ * The degree of left eye blink for the detected face.
+ *
+ * @see #startFaceDetection()
+ */
+ public int getLeftEyeBlinkDegree() {
+ return leyeBlink;
+ }
+
+ /**
+ * The degree of right eye blink for the detected face.
+ *
+ * @see #startFaceDetection()
+ */
+ public int getRightEyeBlinkDegree() {
+ return reyeBlink;
+ }
+
+ /**
+ * The gaze degree of left-right direction for the detected face.
+ *
+ * @see #startFaceDetection()
+ */
+ public int getLeftRightGazeDegree() {
+ return leftrightGaze;
+ }
+
+ /**
+ * The gaze degree of up-down direction for the detected face.
+ *
+ * @see #startFaceDetection()
+ */
+ public int getTopBottomGazeDegree() {
+ return topbottomGaze;
+ }
+
+ private static final String BUNDLE_KEY_SMILE_SCORE = "smileScore";
+ private static final String BUNDLE_KEY_SMILE_VALUE = "smileValue";
+ private static final String BUNDLE_KEY_BLINK_DETECTED = "blinkDetected";
+ private static final String BUNDLE_KEY_LEFT_EYE_CLOSED_VALUE = "leftEyeClosedValue";
+ private static final String BUNDLE_KEY_RIGHT_EYE_CLOSED_VALUE = "rightEyeClosedValue";
+ private static final String BUNDLE_KEY_FACE_PITCH_DEGREE = "facePitchDegree";
+ private static final String BUNDLE_KEY_FACE_YAW_DEGREE = "faceYawDegree";
+ private static final String BUNDLE_KEY_FACE_ROLL_DEGREE = "faceRollDegree";
+ private static final String BUNDLE_KEY_GAZE_UP_DOWN_DEGREE = "gazeUpDownDegree";
+ private static final String BUNDLE_KEY_GAZE_LEFT_RIGHT_DEGREE = "gazeLeftRightDegree";
+ private static final String BUNDLE_KEY_FACE_RECOGNIZED = "faceRecognized";
+
+ public Bundle getExtendedFaceInfo() {
+ Bundle faceInfo = new Bundle();
+ faceInfo.putInt(BUNDLE_KEY_SMILE_VALUE, this.smileDegree);
+
+ faceInfo.putInt(BUNDLE_KEY_LEFT_EYE_CLOSED_VALUE, this.leyeBlink);
+ faceInfo.putInt(BUNDLE_KEY_RIGHT_EYE_CLOSED_VALUE, this.reyeBlink);
+
+ faceInfo.putInt(BUNDLE_KEY_FACE_PITCH_DEGREE, this.updownDir);
+ faceInfo.putInt(BUNDLE_KEY_FACE_YAW_DEGREE, this.leftrightDir);
+ faceInfo.putInt(BUNDLE_KEY_FACE_ROLL_DEGREE, this.rollDir);
+ faceInfo.putInt(BUNDLE_KEY_GAZE_UP_DOWN_DEGREE, this.topbottomGaze);
+ faceInfo.putInt(BUNDLE_KEY_GAZE_LEFT_RIGHT_DEGREE, this.leftrightGaze);
+
+ faceInfo.putInt(BUNDLE_KEY_BLINK_DETECTED, this.blinkDetected);
+ faceInfo.putInt(BUNDLE_KEY_SMILE_SCORE, this.smileScore);
+ faceInfo.putInt(BUNDLE_KEY_FACE_RECOGNIZED, this.faceRecognized);
+
+ return faceInfo;
+ }
+
+}
diff --git a/core/java/org/codeaurora/camera/org.codeaurora.camera.xml b/core/java/org/codeaurora/camera/org.codeaurora.camera.xml
new file mode 100644
index 0000000..20b2aa0
--- /dev/null
+++ b/core/java/org/codeaurora/camera/org.codeaurora.camera.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (c) 2015, The Linux Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+-->
+
+<!-- This is the library that allows devices to use Camera QFace APIs. -->
+<permissions>
+ <library name="org.codeaurora.camera"
+ file="/system/framework/org.codeaurora.camera.jar" />
+</permissions>
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index fc15b964..ad52bd6 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -29,6 +29,7 @@ LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
LOCAL_CFLAGS += -DU_USING_ICU_NAMESPACE=0
LOCAL_SRC_FILES:= \
+ android_util_SeempLog.cpp \
AndroidRuntime.cpp \
com_android_internal_content_NativeLibraryHelper.cpp \
com_google_android_gles_jni_EGLImpl.cpp \
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 2fad2f6..a715c5f 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -100,6 +100,7 @@ extern int register_android_media_JetPlayer(JNIEnv *env);
extern int register_android_media_ToneGenerator(JNIEnv *env);
namespace android {
+extern int register_android_util_SeempLog(JNIEnv* env);
/*
* JNI-based registration functions. Note these are properly contained in
@@ -1294,6 +1295,7 @@ static int register_jni_procs(const RegJNIRec array[], size_t count, JNIEnv* env
}
static const RegJNIRec gRegJNI[] = {
+ REG_JNI(register_android_util_SeempLog),
REG_JNI(register_com_android_internal_os_RuntimeInit),
REG_JNI(register_android_os_SystemClock),
REG_JNI(register_android_util_EventLog),
diff --git a/core/jni/android/opengl/util.cpp b/core/jni/android/opengl/util.cpp
index 40029bb..1bf861a 100644
--- a/core/jni/android/opengl/util.cpp
+++ b/core/jni/android/opengl/util.cpp
@@ -1088,8 +1088,8 @@ static jint etc1_getHeight(JNIEnv *env, jclass clazz,
*/
static JNINativeMethod gMatrixMethods[] = {
- { "multiplyMM", "([FI[FI[FI)V", (void*)util_multiplyMM },
- { "multiplyMV", "([FI[FI[FI)V", (void*)util_multiplyMV },
+ { "multiplyMM", "!([FI[FI[FI)V", (void*)util_multiplyMM },
+ { "multiplyMV", "!([FI[FI[FI)V", (void*)util_multiplyMV },
};
static JNINativeMethod gVisibilityMethods[] = {
diff --git a/core/jni/android_hardware_Camera.cpp b/core/jni/android_hardware_Camera.cpp
index 4f44c26..4cf317e 100644
--- a/core/jni/android_hardware_Camera.cpp
+++ b/core/jni/android_hardware_Camera.cpp
@@ -62,6 +62,18 @@ struct fields_t {
jmethodID rect_constructor;
jmethodID face_constructor;
jmethodID point_constructor;
+ jfieldID face_sm_degree;
+ jfieldID face_sm_score;
+ jfieldID face_blink_detected;
+ jfieldID face_gaze_angle;
+ jfieldID face_updown_dir;
+ jfieldID face_leftright_dir;
+ jfieldID face_roll_dir;
+ jfieldID face_leye_blink;
+ jfieldID face_reye_blink;
+ jfieldID face_left_right_gaze;
+ jfieldID face_top_bottom_gaze;
+ jfieldID face_recognised;
};
static fields_t fields;
@@ -96,6 +108,7 @@ private:
jclass mFaceClass; // strong reference to Face class
jclass mRectClass; // strong reference to Rect class
jclass mPointClass; // strong reference to Point class
+ bool mIsExtendedFace;
Mutex mLock;
/*
@@ -147,8 +160,16 @@ JNICameraContext::JNICameraContext(JNIEnv* env, jobject weak_this, jclass clazz,
mCameraJClass = (jclass)env->NewGlobalRef(clazz);
mCamera = camera;
- jclass faceClazz = env->FindClass("android/hardware/Camera$Face");
- mFaceClass = (jclass) env->NewGlobalRef(faceClazz);
+ jclass extendedfaceClazz = env->FindClass("org/codeaurora/camera/ExtendedFace");
+ if (NULL != extendedfaceClazz) {
+ mFaceClass = (jclass) env->NewGlobalRef(extendedfaceClazz);
+ mIsExtendedFace = true;
+ } else {
+ env->ExceptionClear();
+ jclass faceClazz = env->FindClass("android/hardware/Camera$Face");
+ mFaceClass = (jclass) env->NewGlobalRef(faceClazz);
+ mIsExtendedFace = false;
+ }
jclass rectClazz = env->FindClass("android/graphics/Rect");
mRectClass = (jclass) env->NewGlobalRef(rectClazz);
@@ -368,7 +389,6 @@ void JNICameraContext::postMetadata(JNIEnv *env, int32_t msgType, camera_frame_m
env->SetIntField(rect, fields.rect_top, metadata->faces[i].rect[1]);
env->SetIntField(rect, fields.rect_right, metadata->faces[i].rect[2]);
env->SetIntField(rect, fields.rect_bottom, metadata->faces[i].rect[3]);
-
env->SetObjectField(face, fields.face_rect, rect);
env->SetIntField(face, fields.face_score, metadata->faces[i].score);
@@ -397,6 +417,21 @@ void JNICameraContext::postMetadata(JNIEnv *env, int32_t msgType, camera_frame_m
env->SetIntField(mouth, fields.point_y, metadata->faces[i].mouth[1]);
env->SetObjectField(face, fields.face_mouth, mouth);
env->DeleteLocalRef(mouth);
+
+ if (mIsExtendedFace) {
+ env->SetIntField(face, fields.face_sm_degree, metadata->faces[i].smile_degree);
+ env->SetIntField(face, fields.face_sm_score, metadata->faces[i].smile_score);
+ env->SetIntField(face, fields.face_blink_detected, metadata->faces[i].blink_detected);
+ env->SetIntField(face, fields.face_recognised, metadata->faces[i].face_recognised);
+ env->SetIntField(face, fields.face_gaze_angle, metadata->faces[i].gaze_angle);
+ env->SetIntField(face, fields.face_updown_dir, metadata->faces[i].updown_dir);
+ env->SetIntField(face, fields.face_leftright_dir, metadata->faces[i].leftright_dir);
+ env->SetIntField(face, fields.face_roll_dir, metadata->faces[i].roll_dir);
+ env->SetIntField(face, fields.face_leye_blink, metadata->faces[i].leye_blink);
+ env->SetIntField(face, fields.face_reye_blink, metadata->faces[i].reye_blink);
+ env->SetIntField(face, fields.face_left_right_gaze, metadata->faces[i].left_right_gaze);
+ env->SetIntField(face, fields.face_top_bottom_gaze, metadata->faces[i].top_bottom_gaze);
+ }
}
env->DeleteLocalRef(face);
@@ -434,6 +469,71 @@ void JNICameraContext::setCallbackMode(JNIEnv *env, bool installed, bool manualM
}
}
+static void android_hardware_Camera_setLongshot(JNIEnv *env, jobject thiz, jboolean enable)
+{
+ ALOGV("setLongshot");
+ JNICameraContext* context;
+ status_t rc;
+ sp<Camera> camera = get_native_camera(env, thiz, &context);
+ if (camera == 0) return;
+
+ if ( enable ) {
+ rc = camera->sendCommand(CAMERA_CMD_LONGSHOT_ON, 0, 0);
+ } else {
+ rc = camera->sendCommand(CAMERA_CMD_LONGSHOT_OFF, 0, 0);
+ }
+
+ if (rc != NO_ERROR) {
+ jniThrowException(env, "java/lang/RuntimeException", "enabling longshot mode failed");
+ }
+}
+
+static void android_hardware_Camera_stopLongshot(JNIEnv *env, jobject thiz)
+{
+ ALOGV("stopLongshot");
+ JNICameraContext* context;
+ status_t rc;
+ sp<Camera> camera = get_native_camera(env, thiz, &context);
+ if (camera == 0) return;
+
+ rc = camera->sendCommand(CAMERA_CMD_STOP_LONGSHOT, 0, 0);
+
+ if (rc != NO_ERROR) {
+ jniThrowException(env, "java/lang/RuntimeException", "enabling longshot mode failed");
+ }
+}
+
+static void android_hardware_Camera_sendHistogramData(JNIEnv *env, jobject thiz)
+ {
+ ALOGV("sendHistogramData" );
+ JNICameraContext* context;
+ status_t rc;
+ sp<Camera> camera = get_native_camera(env, thiz, &context);
+ if (camera == 0) return;
+
+ rc = camera->sendCommand(CAMERA_CMD_HISTOGRAM_SEND_DATA, 0, 0);
+
+ if (rc != NO_ERROR) {
+ jniThrowException(env, "java/lang/RuntimeException", "send histogram data failed");
+ }
+ }
+ static void android_hardware_Camera_setHistogramMode(JNIEnv *env, jobject thiz, jboolean mode)
+ {
+ ALOGV("setHistogramMode: mode:%d", (int)mode);
+ JNICameraContext* context;
+ status_t rc;
+ sp<Camera> camera = get_native_camera(env, thiz, &context);
+ if (camera == 0) return;
+
+ if(mode == true)
+ rc = camera->sendCommand(CAMERA_CMD_HISTOGRAM_ON, 0, 0);
+ else
+ rc = camera->sendCommand(CAMERA_CMD_HISTOGRAM_OFF, 0, 0);
+
+ if (rc != NO_ERROR) {
+ jniThrowException(env, "java/lang/RuntimeException", "set histogram mode failed");
+ }
+ }
void JNICameraContext::addCallbackBuffer(
JNIEnv *env, jbyteArray cbb, int msgType)
{
@@ -717,7 +817,25 @@ static void android_hardware_Camera_setHasPreviewCallback(JNIEnv *env, jobject t
context->setCallbackMode(env, installed, manualBuffer);
}
-static void android_hardware_Camera_addCallbackBuffer(JNIEnv *env, jobject thiz, jbyteArray bytes, jint msgType) {
+static void android_hardware_Camera_setMetadataCb(JNIEnv *env, jobject thiz, jboolean mode)
+{
+ ALOGV("setMetadataCb: mode:%d", (int)mode);
+ JNICameraContext* context;
+ status_t rc;
+ sp<Camera> camera = get_native_camera(env, thiz, &context);
+ if (camera == 0) return;
+
+ if(mode == true)
+ rc = camera->sendCommand(CAMERA_CMD_METADATA_ON, 0, 0);
+ else
+ rc = camera->sendCommand(CAMERA_CMD_METADATA_OFF, 0, 0);
+
+ if (rc != NO_ERROR) {
+ jniThrowException(env, "java/lang/RuntimeException", "set metadata mode failed");
+ }
+}
+
+static void android_hardware_Camera_addCallbackBuffer(JNIEnv *env, jobject thiz, jbyteArray bytes, int msgType) {
ALOGV("addCallbackBuffer: 0x%x", msgType);
JNICameraContext* context = reinterpret_cast<JNICameraContext*>(env->GetLongField(thiz, fields.context));
@@ -947,6 +1065,18 @@ static void android_hardware_Camera_enableFocusMoveCallback(JNIEnv *env, jobject
}
}
+static void android_hardware_Camera_sendVendorCommand(JNIEnv *env, jobject thiz,
+ jint cmd, jint arg1, jint arg2)
+{
+ ALOGV("sendVendorCommand");
+ sp<Camera> camera = get_native_camera(env, thiz, NULL);
+ if (camera == 0) return;
+
+ if (camera->sendCommand(cmd, arg1, arg2) != NO_ERROR) {
+ jniThrowRuntimeException(env, "sending vendor command failed");
+ }
+}
+
//-------------------------------------------------
static JNINativeMethod camMethods[] = {
@@ -995,6 +1125,21 @@ static JNINativeMethod camMethods[] = {
{ "native_takePicture",
"(I)V",
(void *)android_hardware_Camera_takePicture },
+ { "native_setHistogramMode",
+ "(Z)V",
+ (void *)android_hardware_Camera_setHistogramMode },
+ { "native_setMetadataCb",
+ "(Z)V",
+ (void *)android_hardware_Camera_setMetadataCb },
+ { "native_sendHistogramData",
+ "()V",
+ (void *)android_hardware_Camera_sendHistogramData },
+ { "native_setLongshot",
+ "(Z)V",
+ (void *)android_hardware_Camera_setLongshot },
+ { "native_stopLongshot",
+ "()V",
+ (void *)android_hardware_Camera_stopLongshot },
{ "native_setParameters",
"(Ljava/lang/String;)V",
(void *)android_hardware_Camera_setParameters },
@@ -1031,6 +1176,9 @@ static JNINativeMethod camMethods[] = {
{ "enableFocusMoveCallback",
"(I)V",
(void *)android_hardware_Camera_enableFocusMoveCallback},
+ { "_sendVendorCommand",
+ "(III)V",
+ (void *)android_hardware_Camera_sendVendorCommand },
};
struct field {
@@ -1073,6 +1221,27 @@ int register_android_hardware_Camera(JNIEnv *env)
{ "android/graphics/Point", "y", "I", &fields.point_y},
};
+ field extendedfacefields_to_find[] = {
+ { "org/codeaurora/camera/ExtendedFace", "rect", "Landroid/graphics/Rect;", &fields.face_rect },
+ { "org/codeaurora/camera/ExtendedFace", "score", "I", &fields.face_score },
+ { "org/codeaurora/camera/ExtendedFace", "id", "I", &fields.face_id },
+ { "org/codeaurora/camera/ExtendedFace", "leftEye", "Landroid/graphics/Point;", &fields.face_left_eye },
+ { "org/codeaurora/camera/ExtendedFace", "rightEye", "Landroid/graphics/Point;", &fields.face_right_eye },
+ { "org/codeaurora/camera/ExtendedFace", "mouth", "Landroid/graphics/Point;", &fields.face_mouth },
+ { "org/codeaurora/camera/ExtendedFace", "smileDegree", "I", &fields.face_sm_degree },
+ { "org/codeaurora/camera/ExtendedFace", "smileScore", "I", &fields.face_sm_score },
+ { "org/codeaurora/camera/ExtendedFace", "blinkDetected", "I", &fields.face_blink_detected },
+ { "org/codeaurora/camera/ExtendedFace", "faceRecognized", "I", &fields.face_recognised },
+ { "org/codeaurora/camera/ExtendedFace", "gazeAngle", "I", &fields.face_gaze_angle },
+ { "org/codeaurora/camera/ExtendedFace", "updownDir", "I", &fields.face_updown_dir },
+ { "org/codeaurora/camera/ExtendedFace", "leftrightDir", "I", &fields.face_leftright_dir },
+ { "org/codeaurora/camera/ExtendedFace", "rollDir", "I", &fields.face_roll_dir },
+ { "org/codeaurora/camera/ExtendedFace", "leyeBlink", "I", &fields.face_leye_blink },
+ { "org/codeaurora/camera/ExtendedFace", "reyeBlink", "I", &fields.face_reye_blink },
+ { "org/codeaurora/camera/ExtendedFace", "leftrightGaze", "I", &fields.face_left_right_gaze },
+ { "org/codeaurora/camera/ExtendedFace", "topbottomGaze", "I", &fields.face_top_bottom_gaze },
+ };
+
find_fields(env, fields_to_find, NELEM(fields_to_find));
jclass clazz = FindClassOrDie(env, "android/hardware/Camera");
@@ -1092,6 +1261,12 @@ int register_android_hardware_Camera(JNIEnv *env)
return -1;
}
+ clazz = env->FindClass("org/codeaurora/camera/ExtendedFace");
+ if (NULL != clazz) {
+ fields.face_constructor = env->GetMethodID(clazz, "<init>", "()V");
+ find_fields(env, extendedfacefields_to_find, NELEM(extendedfacefields_to_find));
+ }
+
// Register native functions
return RegisterMethodsOrDie(env, "android/hardware/Camera", camMethods, NELEM(camMethods));
}
diff --git a/core/jni/android_media_AudioFormat.h b/core/jni/android_media_AudioFormat.h
index bb13c35..211b4f0 100644
--- a/core/jni/android_media_AudioFormat.h
+++ b/core/jni/android_media_AudioFormat.h
@@ -31,6 +31,14 @@
#define ENCODING_AAC_LC 10
#define ENCODING_AAC_HE_V1 11
#define ENCODING_AAC_HE_V2 12
+
+#define ENCODING_AMR_NB 100
+#define ENCODING_AMR_WB 101
+#define ENCODING_EVRC 102
+#define ENCODING_EVRC_B 103
+#define ENCODING_EVRC_WB 104
+#define ENCODING_EVRC_NW 105
+
#define ENCODING_INVALID 0
#define ENCODING_DEFAULT 1
@@ -64,6 +72,18 @@ static inline audio_format_t audioFormatToNative(int audioFormat)
return AUDIO_FORMAT_AAC_HE_V1;
case ENCODING_AAC_HE_V2:
return AUDIO_FORMAT_AAC_HE_V2;
+ case ENCODING_AMR_NB:
+ return AUDIO_FORMAT_AMR_NB;
+ case ENCODING_AMR_WB:
+ return AUDIO_FORMAT_AMR_WB;
+ case ENCODING_EVRC:
+ return AUDIO_FORMAT_EVRC;
+ case ENCODING_EVRC_B:
+ return AUDIO_FORMAT_EVRCB;
+ case ENCODING_EVRC_WB:
+ return AUDIO_FORMAT_EVRCWB;
+ case ENCODING_EVRC_NW:
+ return AUDIO_FORMAT_EVRCNW;
case ENCODING_DEFAULT:
return AUDIO_FORMAT_DEFAULT;
default:
@@ -103,6 +123,18 @@ static inline int audioFormatFromNative(audio_format_t nativeFormat)
return ENCODING_AAC_HE_V1;
case AUDIO_FORMAT_AAC_HE_V2:
return ENCODING_AAC_HE_V2;
+ case AUDIO_FORMAT_AMR_NB:
+ return ENCODING_AMR_NB;
+ case AUDIO_FORMAT_AMR_WB:
+ return ENCODING_AMR_WB;
+ case AUDIO_FORMAT_EVRC:
+ return ENCODING_EVRC;
+ case AUDIO_FORMAT_EVRCB:
+ return ENCODING_EVRC_B;
+ case AUDIO_FORMAT_EVRCWB:
+ return ENCODING_EVRC_WB;
+ case AUDIO_FORMAT_EVRCNW:
+ return ENCODING_EVRC_NW;
case AUDIO_FORMAT_DEFAULT:
return ENCODING_DEFAULT;
default:
diff --git a/core/jni/android_opengl_GLES20.cpp b/core/jni/android_opengl_GLES20.cpp
index f9a0dfe..65331b0 100644
--- a/core/jni/android_opengl_GLES20.cpp
+++ b/core/jni/android_opengl_GLES20.cpp
@@ -6154,14 +6154,14 @@ static const char *classPathName = "android/opengl/GLES20";
static JNINativeMethod methods[] = {
{"_nativeClassInit", "()V", (void*)nativeClassInit },
-{"glActiveTexture", "(I)V", (void *) android_glActiveTexture__I },
+{"glActiveTexture", "!(I)V", (void *) android_glActiveTexture__I },
{"glAttachShader", "(II)V", (void *) android_glAttachShader__II },
{"glBindAttribLocation", "(IILjava/lang/String;)V", (void *) android_glBindAttribLocation__IILjava_lang_String_2 },
-{"glBindBuffer", "(II)V", (void *) android_glBindBuffer__II },
+{"glBindBuffer", "!(II)V", (void *) android_glBindBuffer__II },
{"glBindFramebuffer", "(II)V", (void *) android_glBindFramebuffer__II },
{"glBindRenderbuffer", "(II)V", (void *) android_glBindRenderbuffer__II },
-{"glBindTexture", "(II)V", (void *) android_glBindTexture__II },
-{"glBlendColor", "(FFFF)V", (void *) android_glBlendColor__FFFF },
+{"glBindTexture", "!(II)V", (void *) android_glBindTexture__II },
+{"glBlendColor", "!(FFFF)V", (void *) android_glBlendColor__FFFF },
{"glBlendEquation", "(I)V", (void *) android_glBlendEquation__I },
{"glBlendEquationSeparate", "(II)V", (void *) android_glBlendEquationSeparate__II },
{"glBlendFunc", "(II)V", (void *) android_glBlendFunc__II },
@@ -6171,9 +6171,9 @@ static JNINativeMethod methods[] = {
{"glCheckFramebufferStatus", "(I)I", (void *) android_glCheckFramebufferStatus__I },
{"glClear", "(I)V", (void *) android_glClear__I },
{"glClearColor", "(FFFF)V", (void *) android_glClearColor__FFFF },
-{"glClearDepthf", "(F)V", (void *) android_glClearDepthf__F },
-{"glClearStencil", "(I)V", (void *) android_glClearStencil__I },
-{"glColorMask", "(ZZZZ)V", (void *) android_glColorMask__ZZZZ },
+{"glClearDepthf", "!(F)V", (void *) android_glClearDepthf__F },
+{"glClearStencil", "!(I)V", (void *) android_glClearStencil__I },
+{"glColorMask", "!(ZZZZ)V", (void *) android_glColorMask__ZZZZ },
{"glCompileShader", "(I)V", (void *) android_glCompileShader__I },
{"glCompressedTexImage2D", "(IIIIIIILjava/nio/Buffer;)V", (void *) android_glCompressedTexImage2D__IIIIIIILjava_nio_Buffer_2 },
{"glCompressedTexSubImage2D", "(IIIIIIIILjava/nio/Buffer;)V", (void *) android_glCompressedTexSubImage2D__IIIIIIIILjava_nio_Buffer_2 },
@@ -6181,7 +6181,7 @@ static JNINativeMethod methods[] = {
{"glCopyTexSubImage2D", "(IIIIIIII)V", (void *) android_glCopyTexSubImage2D__IIIIIIII },
{"glCreateProgram", "()I", (void *) android_glCreateProgram__ },
{"glCreateShader", "(I)I", (void *) android_glCreateShader__I },
-{"glCullFace", "(I)V", (void *) android_glCullFace__I },
+{"glCullFace", "!(I)V", (void *) android_glCullFace__I },
{"glDeleteBuffers", "(I[II)V", (void *) android_glDeleteBuffers__I_3II },
{"glDeleteBuffers", "(ILjava/nio/IntBuffer;)V", (void *) android_glDeleteBuffers__ILjava_nio_IntBuffer_2 },
{"glDeleteFramebuffers", "(I[II)V", (void *) android_glDeleteFramebuffers__I_3II },
@@ -6192,22 +6192,22 @@ static JNINativeMethod methods[] = {
{"glDeleteShader", "(I)V", (void *) android_glDeleteShader__I },
{"glDeleteTextures", "(I[II)V", (void *) android_glDeleteTextures__I_3II },
{"glDeleteTextures", "(ILjava/nio/IntBuffer;)V", (void *) android_glDeleteTextures__ILjava_nio_IntBuffer_2 },
-{"glDepthFunc", "(I)V", (void *) android_glDepthFunc__I },
-{"glDepthMask", "(Z)V", (void *) android_glDepthMask__Z },
+{"glDepthFunc", "!(I)V", (void *) android_glDepthFunc__I },
+{"glDepthMask", "!(Z)V", (void *) android_glDepthMask__Z },
{"glDepthRangef", "(FF)V", (void *) android_glDepthRangef__FF },
{"glDetachShader", "(II)V", (void *) android_glDetachShader__II },
-{"glDisable", "(I)V", (void *) android_glDisable__I },
-{"glDisableVertexAttribArray", "(I)V", (void *) android_glDisableVertexAttribArray__I },
-{"glDrawArrays", "(III)V", (void *) android_glDrawArrays__III },
-{"glDrawElements", "(IIII)V", (void *) android_glDrawElements__IIII },
-{"glDrawElements", "(IIILjava/nio/Buffer;)V", (void *) android_glDrawElements__IIILjava_nio_Buffer_2 },
-{"glEnable", "(I)V", (void *) android_glEnable__I },
-{"glEnableVertexAttribArray", "(I)V", (void *) android_glEnableVertexAttribArray__I },
+{"glDisable", "!(I)V", (void *) android_glDisable__I },
+{"glDisableVertexAttribArray", "!(I)V", (void *) android_glDisableVertexAttribArray__I },
+{"glDrawArrays", "!(III)V", (void *) android_glDrawArrays__III },
+{"glDrawElements", "!(IIII)V", (void *) android_glDrawElements__IIII },
+{"glDrawElements", "!(IIILjava/nio/Buffer;)V", (void *) android_glDrawElements__IIILjava_nio_Buffer_2 },
+{"glEnable", "!(I)V", (void *) android_glEnable__I },
+{"glEnableVertexAttribArray", "!(I)V", (void *) android_glEnableVertexAttribArray__I },
{"glFinish", "()V", (void *) android_glFinish__ },
{"glFlush", "()V", (void *) android_glFlush__ },
{"glFramebufferRenderbuffer", "(IIII)V", (void *) android_glFramebufferRenderbuffer__IIII },
{"glFramebufferTexture2D", "(IIIII)V", (void *) android_glFramebufferTexture2D__IIIII },
-{"glFrontFace", "(I)V", (void *) android_glFrontFace__I },
+{"glFrontFace", "!(I)V", (void *) android_glFrontFace__I },
{"glGenBuffers", "(I[II)V", (void *) android_glGenBuffers__I_3II },
{"glGenBuffers", "(ILjava/nio/IntBuffer;)V", (void *) android_glGenBuffers__ILjava_nio_IntBuffer_2 },
{"glGenerateMipmap", "(I)V", (void *) android_glGenerateMipmap__I },
@@ -6232,12 +6232,12 @@ static JNINativeMethod methods[] = {
{"glGetBooleanv", "(ILjava/nio/IntBuffer;)V", (void *) android_glGetBooleanv__ILjava_nio_IntBuffer_2 },
{"glGetBufferParameteriv", "(II[II)V", (void *) android_glGetBufferParameteriv__II_3II },
{"glGetBufferParameteriv", "(IILjava/nio/IntBuffer;)V", (void *) android_glGetBufferParameteriv__IILjava_nio_IntBuffer_2 },
-{"glGetError", "()I", (void *) android_glGetError__ },
-{"glGetFloatv", "(I[FI)V", (void *) android_glGetFloatv__I_3FI },
+{"glGetError", "!()I", (void *) android_glGetError__ },
+{"glGetFloatv", "!(I[FI)V", (void *) android_glGetFloatv__I_3FI },
{"glGetFloatv", "(ILjava/nio/FloatBuffer;)V", (void *) android_glGetFloatv__ILjava_nio_FloatBuffer_2 },
{"glGetFramebufferAttachmentParameteriv", "(III[II)V", (void *) android_glGetFramebufferAttachmentParameteriv__III_3II },
{"glGetFramebufferAttachmentParameteriv", "(IIILjava/nio/IntBuffer;)V", (void *) android_glGetFramebufferAttachmentParameteriv__IIILjava_nio_IntBuffer_2 },
-{"glGetIntegerv", "(I[II)V", (void *) android_glGetIntegerv__I_3II },
+{"glGetIntegerv", "!(I[II)V", (void *) android_glGetIntegerv__I_3II },
{"glGetIntegerv", "(ILjava/nio/IntBuffer;)V", (void *) android_glGetIntegerv__ILjava_nio_IntBuffer_2 },
{"glGetProgramiv", "(II[II)V", (void *) android_glGetProgramiv__II_3II },
{"glGetProgramiv", "(IILjava/nio/IntBuffer;)V", (void *) android_glGetProgramiv__IILjava_nio_IntBuffer_2 },
@@ -6282,16 +6282,16 @@ static JNINativeMethod methods[] = {
{"glReleaseShaderCompiler", "()V", (void *) android_glReleaseShaderCompiler__ },
{"glRenderbufferStorage", "(IIII)V", (void *) android_glRenderbufferStorage__IIII },
{"glSampleCoverage", "(FZ)V", (void *) android_glSampleCoverage__FZ },
-{"glScissor", "(IIII)V", (void *) android_glScissor__IIII },
+{"glScissor", "!(IIII)V", (void *) android_glScissor__IIII },
{"glShaderBinary", "(I[IIILjava/nio/Buffer;I)V", (void *) android_glShaderBinary__I_3IIILjava_nio_Buffer_2I },
{"glShaderBinary", "(ILjava/nio/IntBuffer;ILjava/nio/Buffer;I)V", (void *) android_glShaderBinary__ILjava_nio_IntBuffer_2ILjava_nio_Buffer_2I },
{"glShaderSource", "(ILjava/lang/String;)V", (void *) android_glShaderSource },
-{"glStencilFunc", "(III)V", (void *) android_glStencilFunc__III },
-{"glStencilFuncSeparate", "(IIII)V", (void *) android_glStencilFuncSeparate__IIII },
-{"glStencilMask", "(I)V", (void *) android_glStencilMask__I },
-{"glStencilMaskSeparate", "(II)V", (void *) android_glStencilMaskSeparate__II },
-{"glStencilOp", "(III)V", (void *) android_glStencilOp__III },
-{"glStencilOpSeparate", "(IIII)V", (void *) android_glStencilOpSeparate__IIII },
+{"glStencilFunc", "!(III)V", (void *) android_glStencilFunc__III },
+{"glStencilFuncSeparate", "!(IIII)V", (void *) android_glStencilFuncSeparate__IIII },
+{"glStencilMask", "!(I)V", (void *) android_glStencilMask__I },
+{"glStencilMaskSeparate", "!(II)V", (void *) android_glStencilMaskSeparate__II },
+{"glStencilOp", "!(III)V", (void *) android_glStencilOp__III },
+{"glStencilOpSeparate", "!(IIII)V", (void *) android_glStencilOpSeparate__IIII },
{"glTexImage2D", "(IIIIIIIILjava/nio/Buffer;)V", (void *) android_glTexImage2D__IIIIIIIILjava_nio_Buffer_2 },
{"glTexParameterf", "(IIF)V", (void *) android_glTexParameterf__IIF },
{"glTexParameterfv", "(II[FI)V", (void *) android_glTexParameterfv__II_3FI },
@@ -6300,53 +6300,53 @@ static JNINativeMethod methods[] = {
{"glTexParameteriv", "(II[II)V", (void *) android_glTexParameteriv__II_3II },
{"glTexParameteriv", "(IILjava/nio/IntBuffer;)V", (void *) android_glTexParameteriv__IILjava_nio_IntBuffer_2 },
{"glTexSubImage2D", "(IIIIIIIILjava/nio/Buffer;)V", (void *) android_glTexSubImage2D__IIIIIIIILjava_nio_Buffer_2 },
-{"glUniform1f", "(IF)V", (void *) android_glUniform1f__IF },
-{"glUniform1fv", "(II[FI)V", (void *) android_glUniform1fv__II_3FI },
-{"glUniform1fv", "(IILjava/nio/FloatBuffer;)V", (void *) android_glUniform1fv__IILjava_nio_FloatBuffer_2 },
-{"glUniform1i", "(II)V", (void *) android_glUniform1i__II },
-{"glUniform1iv", "(II[II)V", (void *) android_glUniform1iv__II_3II },
-{"glUniform1iv", "(IILjava/nio/IntBuffer;)V", (void *) android_glUniform1iv__IILjava_nio_IntBuffer_2 },
-{"glUniform2f", "(IFF)V", (void *) android_glUniform2f__IFF },
-{"glUniform2fv", "(II[FI)V", (void *) android_glUniform2fv__II_3FI },
-{"glUniform2fv", "(IILjava/nio/FloatBuffer;)V", (void *) android_glUniform2fv__IILjava_nio_FloatBuffer_2 },
-{"glUniform2i", "(III)V", (void *) android_glUniform2i__III },
-{"glUniform2iv", "(II[II)V", (void *) android_glUniform2iv__II_3II },
-{"glUniform2iv", "(IILjava/nio/IntBuffer;)V", (void *) android_glUniform2iv__IILjava_nio_IntBuffer_2 },
-{"glUniform3f", "(IFFF)V", (void *) android_glUniform3f__IFFF },
-{"glUniform3fv", "(II[FI)V", (void *) android_glUniform3fv__II_3FI },
-{"glUniform3fv", "(IILjava/nio/FloatBuffer;)V", (void *) android_glUniform3fv__IILjava_nio_FloatBuffer_2 },
-{"glUniform3i", "(IIII)V", (void *) android_glUniform3i__IIII },
-{"glUniform3iv", "(II[II)V", (void *) android_glUniform3iv__II_3II },
-{"glUniform3iv", "(IILjava/nio/IntBuffer;)V", (void *) android_glUniform3iv__IILjava_nio_IntBuffer_2 },
-{"glUniform4f", "(IFFFF)V", (void *) android_glUniform4f__IFFFF },
-{"glUniform4fv", "(II[FI)V", (void *) android_glUniform4fv__II_3FI },
-{"glUniform4fv", "(IILjava/nio/FloatBuffer;)V", (void *) android_glUniform4fv__IILjava_nio_FloatBuffer_2 },
-{"glUniform4i", "(IIIII)V", (void *) android_glUniform4i__IIIII },
-{"glUniform4iv", "(II[II)V", (void *) android_glUniform4iv__II_3II },
-{"glUniform4iv", "(IILjava/nio/IntBuffer;)V", (void *) android_glUniform4iv__IILjava_nio_IntBuffer_2 },
-{"glUniformMatrix2fv", "(IIZ[FI)V", (void *) android_glUniformMatrix2fv__IIZ_3FI },
-{"glUniformMatrix2fv", "(IIZLjava/nio/FloatBuffer;)V", (void *) android_glUniformMatrix2fv__IIZLjava_nio_FloatBuffer_2 },
-{"glUniformMatrix3fv", "(IIZ[FI)V", (void *) android_glUniformMatrix3fv__IIZ_3FI },
-{"glUniformMatrix3fv", "(IIZLjava/nio/FloatBuffer;)V", (void *) android_glUniformMatrix3fv__IIZLjava_nio_FloatBuffer_2 },
-{"glUniformMatrix4fv", "(IIZ[FI)V", (void *) android_glUniformMatrix4fv__IIZ_3FI },
-{"glUniformMatrix4fv", "(IIZLjava/nio/FloatBuffer;)V", (void *) android_glUniformMatrix4fv__IIZLjava_nio_FloatBuffer_2 },
-{"glUseProgram", "(I)V", (void *) android_glUseProgram__I },
+{"glUniform1f", "!(IF)V", (void *) android_glUniform1f__IF },
+{"glUniform1fv", "!(II[FI)V", (void *) android_glUniform1fv__II_3FI },
+{"glUniform1fv", "!(IILjava/nio/FloatBuffer;)V", (void *) android_glUniform1fv__IILjava_nio_FloatBuffer_2 },
+{"glUniform1i", "!(II)V", (void *) android_glUniform1i__II },
+{"glUniform1iv", "!(II[II)V", (void *) android_glUniform1iv__II_3II },
+{"glUniform1iv", "!(IILjava/nio/IntBuffer;)V", (void *) android_glUniform1iv__IILjava_nio_IntBuffer_2 },
+{"glUniform2f", "!(IFF)V", (void *) android_glUniform2f__IFF },
+{"glUniform2fv", "!(II[FI)V", (void *) android_glUniform2fv__II_3FI },
+{"glUniform2fv", "!(IILjava/nio/FloatBuffer;)V", (void *) android_glUniform2fv__IILjava_nio_FloatBuffer_2 },
+{"glUniform2i", "!(III)V", (void *) android_glUniform2i__III },
+{"glUniform2iv", "!(II[II)V", (void *) android_glUniform2iv__II_3II },
+{"glUniform2iv", "!(IILjava/nio/IntBuffer;)V", (void *) android_glUniform2iv__IILjava_nio_IntBuffer_2 },
+{"glUniform3f", "!(IFFF)V", (void *) android_glUniform3f__IFFF },
+{"glUniform3fv", "!(II[FI)V", (void *) android_glUniform3fv__II_3FI },
+{"glUniform3fv", "!(IILjava/nio/FloatBuffer;)V", (void *) android_glUniform3fv__IILjava_nio_FloatBuffer_2 },
+{"glUniform3i", "!(IIII)V", (void *) android_glUniform3i__IIII },
+{"glUniform3iv", "!(II[II)V", (void *) android_glUniform3iv__II_3II },
+{"glUniform3iv", "!(IILjava/nio/IntBuffer;)V", (void *) android_glUniform3iv__IILjava_nio_IntBuffer_2 },
+{"glUniform4f", "!(IFFFF)V", (void *) android_glUniform4f__IFFFF },
+{"glUniform4fv", "!(II[FI)V", (void *) android_glUniform4fv__II_3FI },
+{"glUniform4fv", "!(IILjava/nio/FloatBuffer;)V", (void *) android_glUniform4fv__IILjava_nio_FloatBuffer_2 },
+{"glUniform4i", "!(IIIII)V", (void *) android_glUniform4i__IIIII },
+{"glUniform4iv", "!(II[II)V", (void *) android_glUniform4iv__II_3II },
+{"glUniform4iv", "!(IILjava/nio/IntBuffer;)V", (void *) android_glUniform4iv__IILjava_nio_IntBuffer_2 },
+{"glUniformMatrix2fv", "!(IIZ[FI)V", (void *) android_glUniformMatrix2fv__IIZ_3FI },
+{"glUniformMatrix2fv", "!(IIZLjava/nio/FloatBuffer;)V", (void *) android_glUniformMatrix2fv__IIZLjava_nio_FloatBuffer_2 },
+{"glUniformMatrix3fv", "!(IIZ[FI)V", (void *) android_glUniformMatrix3fv__IIZ_3FI },
+{"glUniformMatrix3fv", "!(IIZLjava/nio/FloatBuffer;)V", (void *) android_glUniformMatrix3fv__IIZLjava_nio_FloatBuffer_2 },
+{"glUniformMatrix4fv", "!(IIZ[FI)V", (void *) android_glUniformMatrix4fv__IIZ_3FI },
+{"glUniformMatrix4fv", "!(IIZLjava/nio/FloatBuffer;)V", (void *) android_glUniformMatrix4fv__IIZLjava_nio_FloatBuffer_2 },
+{"glUseProgram", "!(I)V", (void *) android_glUseProgram__I },
{"glValidateProgram", "(I)V", (void *) android_glValidateProgram__I },
-{"glVertexAttrib1f", "(IF)V", (void *) android_glVertexAttrib1f__IF },
-{"glVertexAttrib1fv", "(I[FI)V", (void *) android_glVertexAttrib1fv__I_3FI },
-{"glVertexAttrib1fv", "(ILjava/nio/FloatBuffer;)V", (void *) android_glVertexAttrib1fv__ILjava_nio_FloatBuffer_2 },
-{"glVertexAttrib2f", "(IFF)V", (void *) android_glVertexAttrib2f__IFF },
-{"glVertexAttrib2fv", "(I[FI)V", (void *) android_glVertexAttrib2fv__I_3FI },
-{"glVertexAttrib2fv", "(ILjava/nio/FloatBuffer;)V", (void *) android_glVertexAttrib2fv__ILjava_nio_FloatBuffer_2 },
-{"glVertexAttrib3f", "(IFFF)V", (void *) android_glVertexAttrib3f__IFFF },
-{"glVertexAttrib3fv", "(I[FI)V", (void *) android_glVertexAttrib3fv__I_3FI },
-{"glVertexAttrib3fv", "(ILjava/nio/FloatBuffer;)V", (void *) android_glVertexAttrib3fv__ILjava_nio_FloatBuffer_2 },
-{"glVertexAttrib4f", "(IFFFF)V", (void *) android_glVertexAttrib4f__IFFFF },
-{"glVertexAttrib4fv", "(I[FI)V", (void *) android_glVertexAttrib4fv__I_3FI },
-{"glVertexAttrib4fv", "(ILjava/nio/FloatBuffer;)V", (void *) android_glVertexAttrib4fv__ILjava_nio_FloatBuffer_2 },
-{"glVertexAttribPointer", "(IIIZII)V", (void *) android_glVertexAttribPointer__IIIZII },
-{"glVertexAttribPointerBounds", "(IIIZILjava/nio/Buffer;I)V", (void *) android_glVertexAttribPointerBounds__IIIZILjava_nio_Buffer_2I },
-{"glViewport", "(IIII)V", (void *) android_glViewport__IIII },
+{"glVertexAttrib1f", "!(IF)V", (void *) android_glVertexAttrib1f__IF },
+{"glVertexAttrib1fv", "!(I[FI)V", (void *) android_glVertexAttrib1fv__I_3FI },
+{"glVertexAttrib1fv", "!(ILjava/nio/FloatBuffer;)V", (void *) android_glVertexAttrib1fv__ILjava_nio_FloatBuffer_2 },
+{"glVertexAttrib2f", "!(IFF)V", (void *) android_glVertexAttrib2f__IFF },
+{"glVertexAttrib2fv", "!(I[FI)V", (void *) android_glVertexAttrib2fv__I_3FI },
+{"glVertexAttrib2fv", "!(ILjava/nio/FloatBuffer;)V", (void *) android_glVertexAttrib2fv__ILjava_nio_FloatBuffer_2 },
+{"glVertexAttrib3f", "!(IFFF)V", (void *) android_glVertexAttrib3f__IFFF },
+{"glVertexAttrib3fv", "!(I[FI)V", (void *) android_glVertexAttrib3fv__I_3FI },
+{"glVertexAttrib3fv", "!(ILjava/nio/FloatBuffer;)V", (void *) android_glVertexAttrib3fv__ILjava_nio_FloatBuffer_2 },
+{"glVertexAttrib4f", "!(IFFFF)V", (void *) android_glVertexAttrib4f__IFFFF },
+{"glVertexAttrib4fv", "!(I[FI)V", (void *) android_glVertexAttrib4fv__I_3FI },
+{"glVertexAttrib4fv", "!(ILjava/nio/FloatBuffer;)V", (void *) android_glVertexAttrib4fv__ILjava_nio_FloatBuffer_2 },
+{"glVertexAttribPointer", "!(IIIZII)V", (void *) android_glVertexAttribPointer__IIIZII },
+{"glVertexAttribPointerBounds", "!(IIIZILjava/nio/Buffer;I)V", (void *) android_glVertexAttribPointerBounds__IIIZILjava_nio_Buffer_2I },
+{"glViewport", "!(IIII)V", (void *) android_glViewport__IIII },
};
int register_android_opengl_jni_GLES20(JNIEnv *_env)
diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp
index dca04f5..6257265 100644
--- a/core/jni/android_util_AssetManager.cpp
+++ b/core/jni/android_util_AssetManager.cpp
@@ -520,24 +520,143 @@ static jint android_content_AssetManager_addAssetPath(JNIEnv* env, jobject clazz
}
static jint android_content_AssetManager_addOverlayPath(JNIEnv* env, jobject clazz,
- jstring idmapPath)
+ jstring idmapPath,
+ jstring packagePath,
+ jstring resApkPath, jstring targetPkgPath,
+ jstring prefixPath)
{
ScopedUtfChars idmapPath8(env, idmapPath);
if (idmapPath8.c_str() == NULL) {
return 0;
}
+ ScopedUtfChars packagePath8(env, packagePath);
+ if (packagePath8.c_str() == NULL) {
+ return 0;
+ }
+
+ ScopedUtfChars resApkPath8(env, resApkPath);
+ if (resApkPath8.c_str() == NULL) {
+ return 0;
+ }
+
+ ScopedUtfChars prefixPath8(env, prefixPath);
+ if (prefixPath8.c_str() == NULL) {
+ return 0;
+ }
+
+ ScopedUtfChars targetPkgPath8(env, targetPkgPath);
+ if (targetPkgPath8.c_str() == NULL) {
+ return 0;
+ }
+
+ AssetManager* am = assetManagerForJavaObject(env, clazz);
+ if (am == NULL) {
+ return 0;
+ }
+
+ int32_t cookie;
+ bool res = am->addOverlayPath(
+ String8(idmapPath8.c_str()),
+ String8(packagePath8.c_str()),
+ &cookie,
+ String8(resApkPath8.c_str()),
+ String8(targetPkgPath8.c_str()),
+ String8(prefixPath8.c_str()));
+
+ return (res) ? (jint)cookie : 0;
+}
+
+static jint android_content_AssetManager_addCommonOverlayPath(JNIEnv* env, jobject clazz,
+ jstring packagePath,
+ jstring resApkPath, jstring prefixPath)
+{
+ ScopedUtfChars packagePath8(env, packagePath);
+ if (packagePath8.c_str() == NULL) {
+ return 0;
+ }
+
+ ScopedUtfChars resApkPath8(env, resApkPath);
+ if (resApkPath8.c_str() == NULL) {
+ return 0;
+ }
+
+ ScopedUtfChars prefixPath8(env, prefixPath);
+ if (prefixPath8.c_str() == NULL) {
+ return 0;
+ }
+
+ if (!access(packagePath8.c_str(), R_OK) == 0 ||
+ !access(resApkPath8.c_str(), R_OK) == 0) {
+ return 0;
+ }
+
AssetManager* am = assetManagerForJavaObject(env, clazz);
if (am == NULL) {
return 0;
}
int32_t cookie;
- bool res = am->addOverlayPath(String8(idmapPath8.c_str()), &cookie);
+ bool res = am->addCommonOverlayPath(String8(packagePath8.c_str()), &cookie,
+ String8(resApkPath8.c_str()),
+ String8(prefixPath8.c_str()));
return (res) ? (jint)cookie : 0;
}
+static jint android_content_AssetManager_addIconPath(JNIEnv* env, jobject clazz,
+ jstring packagePath,
+ jstring resApkPath, jstring prefixPath,
+ jint pkgIdOverride)
+{
+ ScopedUtfChars packagePath8(env, packagePath);
+ if (packagePath8.c_str() == NULL) {
+ return 0;
+ }
+
+ ScopedUtfChars resApkPath8(env, resApkPath);
+ if (resApkPath8.c_str() == NULL) {
+ return 0;
+ }
+
+ ScopedUtfChars prefixPath8(env, prefixPath);
+ if (prefixPath8.c_str() == NULL) {
+ return 0;
+ }
+
+ AssetManager* am = assetManagerForJavaObject(env, clazz);
+ if (am == NULL) {
+ return 0;
+ }
+
+ int32_t cookie;
+ bool res = am->addIconPath(String8(packagePath8.c_str()), &cookie,
+ String8(resApkPath8.c_str()),
+ String8(prefixPath8.c_str()), pkgIdOverride);
+
+ return (res) ? (jint)cookie : 0;
+}
+
+static jboolean android_content_AssetManager_removeOverlayPath(JNIEnv* env, jobject clazz,
+ jstring packageName, jint cookie)
+{
+ if (packageName == NULL) {
+ jniThrowException(env, "java/lang/NullPointerException", "packageName");
+ return JNI_FALSE;
+ }
+
+ AssetManager* am = assetManagerForJavaObject(env, clazz);
+ if (am == NULL) {
+ return JNI_FALSE;
+ }
+
+ const char* name8 = env->GetStringUTFChars(packageName, NULL);
+ bool res = am->removeOverlayPath(String8(name8), cookie);
+ env->ReleaseStringUTFChars(packageName, name8);
+
+ return res;
+}
+
static jboolean android_content_AssetManager_isUpToDate(JNIEnv* env, jobject clazz)
{
AssetManager* am = assetManagerForJavaObject(env, clazz);
@@ -1139,7 +1258,7 @@ static jboolean android_content_AssetManager_resolveAttrs(JNIEnv* env, jobject c
const ResTable::bag_entry* defStyleStart = NULL;
uint32_t defStyleTypeSetFlags = 0;
ssize_t bagOff = defStyleRes != 0
- ? res.getBagLocked(defStyleRes, &defStyleStart, &defStyleTypeSetFlags) : -1;
+ ? res.getBagLocked(defStyleRes, &defStyleStart, &defStyleTypeSetFlags, true) : -1;
defStyleTypeSetFlags |= defStyleBagTypeSetFlags;
const ResTable::bag_entry* const defStyleEnd = defStyleStart + (bagOff >= 0 ? bagOff : 0);
BagAttributeFinder defStyleAttrFinder(defStyleStart, defStyleEnd);
@@ -1358,7 +1477,7 @@ static jboolean android_content_AssetManager_applyStyle(JNIEnv* env, jobject cla
const ResTable::bag_entry* defStyleAttrStart = NULL;
uint32_t defStyleTypeSetFlags = 0;
ssize_t bagOff = defStyleRes != 0
- ? res.getBagLocked(defStyleRes, &defStyleAttrStart, &defStyleTypeSetFlags) : -1;
+ ? res.getBagLocked(defStyleRes, &defStyleAttrStart, &defStyleTypeSetFlags, true) : -1;
defStyleTypeSetFlags |= defStyleBagTypeSetFlags;
const ResTable::bag_entry* const defStyleAttrEnd = defStyleAttrStart + (bagOff >= 0 ? bagOff : 0);
BagAttributeFinder defStyleAttrFinder(defStyleAttrStart, defStyleAttrEnd);
@@ -1366,7 +1485,7 @@ static jboolean android_content_AssetManager_applyStyle(JNIEnv* env, jobject cla
// Retrieve the style class bag, if requested.
const ResTable::bag_entry* styleAttrStart = NULL;
uint32_t styleTypeSetFlags = 0;
- bagOff = style != 0 ? res.getBagLocked(style, &styleAttrStart, &styleTypeSetFlags) : -1;
+ bagOff = style != 0 ? res.getBagLocked(style, &styleAttrStart, &styleTypeSetFlags, true) : -1;
styleTypeSetFlags |= styleBagTypeSetFlags;
const ResTable::bag_entry* const styleAttrEnd = styleAttrStart + (bagOff >= 0 ? bagOff : 0);
BagAttributeFinder styleAttrFinder(styleAttrStart, styleAttrEnd);
@@ -1710,7 +1829,7 @@ static jint android_content_AssetManager_retrieveArray(JNIEnv* env, jobject claz
const ResTable::bag_entry* arrayEnt = NULL;
uint32_t arrayTypeSetFlags = 0;
- ssize_t bagOff = res.getBagLocked(id, &arrayEnt, &arrayTypeSetFlags);
+ ssize_t bagOff = res.getBagLocked(id, &arrayEnt, &arrayTypeSetFlags, true);
const ResTable::bag_entry* endArrayEnt = arrayEnt +
(bagOff >= 0 ? bagOff : 0);
@@ -2048,6 +2167,50 @@ static jint android_content_AssetManager_getGlobalAssetManagerCount(JNIEnv* env,
return AssetManager::getGlobalCount();
}
+static jint android_content_AssetManager_getBasePackageCount(JNIEnv* env, jobject clazz)
+{
+ AssetManager* am = assetManagerForJavaObject(env, clazz);
+ if (am == NULL) {
+ return JNI_FALSE;
+ }
+
+ return am->getResources().getBasePackageCount();
+}
+
+static jstring android_content_AssetManager_getBasePackageName(JNIEnv* env, jobject clazz,
+ jint index)
+{
+ AssetManager* am = assetManagerForJavaObject(env, clazz);
+ if (am == NULL) {
+ return JNI_FALSE;
+ }
+
+ String16 packageName(am->getBasePackageName(index));
+ return env->NewString((const jchar*)packageName.string(), packageName.size());
+}
+
+static jstring android_content_AssetManager_getBaseResourcePackageName(JNIEnv* env, jobject clazz,
+ jint index)
+{
+ AssetManager* am = assetManagerForJavaObject(env, clazz);
+ if (am == NULL) {
+ return JNI_FALSE;
+ }
+
+ String16 packageName(am->getResources().getBasePackageName(index));
+ return env->NewString((const jchar*)packageName.string(), packageName.size());
+}
+
+static jint android_content_AssetManager_getBasePackageId(JNIEnv* env, jobject clazz, jint index)
+{
+ AssetManager* am = assetManagerForJavaObject(env, clazz);
+ if (am == NULL) {
+ return JNI_FALSE;
+ }
+
+ return am->getResources().getBasePackageId(index);
+}
+
// ----------------------------------------------------------------------------
/*
@@ -2081,8 +2244,22 @@ static JNINativeMethod gAssetManagerMethods[] = {
(void*) android_content_AssetManager_getAssetRemainingLength },
{ "addAssetPathNative", "(Ljava/lang/String;)I",
(void*) android_content_AssetManager_addAssetPath },
- { "addOverlayPathNative", "(Ljava/lang/String;)I",
+ { "addOverlayPathNative", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)I",
(void*) android_content_AssetManager_addOverlayPath },
+ { "addCommonOverlayPathNative", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)I",
+ (void*) android_content_AssetManager_addCommonOverlayPath },
+ { "addIconPathNative", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;I)I",
+ (void*) android_content_AssetManager_addIconPath },
+ { "removeOverlayPathNative", "(Ljava/lang/String;I)Z",
+ (void*) android_content_AssetManager_removeOverlayPath },
+ { "getBasePackageCount", "()I",
+ (void*) android_content_AssetManager_getBasePackageCount },
+ { "getBasePackageName", "(I)Ljava/lang/String;",
+ (void*) android_content_AssetManager_getBasePackageName },
+ { "getBaseResourcePackageName", "(I)Ljava/lang/String;",
+ (void*) android_content_AssetManager_getBaseResourcePackageName },
+ { "getBasePackageId", "(I)I",
+ (void*) android_content_AssetManager_getBasePackageId },
{ "isUpToDate", "()Z",
(void*) android_content_AssetManager_isUpToDate },
diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp
index c139cd7..9718fd7 100644
--- a/core/jni/android_util_Binder.cpp
+++ b/core/jni/android_util_Binder.cpp
@@ -144,7 +144,7 @@ static volatile int32_t gNumDeathRefs = 0;
static void incRefsCreated(JNIEnv* env)
{
int old = android_atomic_inc(&gNumRefsCreated);
- if (old == 200) {
+ if (old == 2000) {
android_atomic_and(0, &gNumRefsCreated);
env->CallStaticVoidMethod(gBinderInternalOffsets.mClass,
gBinderInternalOffsets.mForceGc);
diff --git a/core/jni/android_util_Process.cpp b/core/jni/android_util_Process.cpp
index ee8fb19..8967cf2 100644
--- a/core/jni/android_util_Process.cpp
+++ b/core/jni/android_util_Process.cpp
@@ -370,27 +370,40 @@ jint android_os_Process_getThreadPriority(JNIEnv* env, jobject clazz,
return pri;
}
+static bool memcgSupported = false;
+static int memcgTasksFd = -1;
+static int memcgSwapTasksFd = -1;
+static pthread_once_t memcgInitOnce = PTHREAD_ONCE_INIT;
+
+static void memcgInit(void) {
+ if (!access("/sys/fs/cgroup/memory/tasks", F_OK)) {
+ memcgTasksFd = open("/sys/fs/cgroup/memory/tasks", O_WRONLY);
+ if (memcgTasksFd < 0) {
+ return;
+ }
+ memcgSwapTasksFd = open("/sys/fs/cgroup/memory/sw/tasks", O_WRONLY);
+ if (memcgSwapTasksFd < 0) {
+ close(memcgTasksFd);
+ return;
+ }
+ memcgSupported = true;
+ }
+}
+
jboolean android_os_Process_setSwappiness(JNIEnv *env, jobject clazz,
jint pid, jboolean is_increased)
{
- char text[64];
-
- if (is_increased) {
- strcpy(text, "/sys/fs/cgroup/memory/sw/tasks");
- } else {
- strcpy(text, "/sys/fs/cgroup/memory/tasks");
- }
-
- struct stat st;
- if (stat(text, &st) || !S_ISREG(st.st_mode)) {
+ pthread_once(&memcgInitOnce, memcgInit);
+ if (!memcgSupported) {
return false;
}
- int fd = open(text, O_WRONLY);
+ int fd = is_increased ? memcgSwapTasksFd : memcgTasksFd;
+ char text[64];
+
if (fd >= 0) {
sprintf(text, "%" PRId32, pid);
write(fd, text, strlen(text));
- close(fd);
}
return true;
diff --git a/core/jni/android_util_SeempLog.cpp b/core/jni/android_util_SeempLog.cpp
new file mode 100644
index 0000000..734490a
--- /dev/null
+++ b/core/jni/android_util_SeempLog.cpp
@@ -0,0 +1,210 @@
+/*
+ * Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ *
+ * Copyright (C) 2007-2014 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.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <unistd.h>
+#include <assert.h>
+#include <cutils/properties.h>
+#include <utils/String8.h>
+#include <android_runtime/Log.h>
+#include <utils/Log.h>
+#ifdef __BIONIC__
+#include <android/set_abort_message.h>
+#endif
+#include <utils/Log.h>
+
+#include "jni.h"
+#include "JNIHelp.h"
+#include "utils/misc.h"
+#include "android_runtime/AndroidRuntime.h"
+
+#define LOG_BUF_SIZE 1024
+#define SEEMP_SOCK_NAME "/dev/socket/seempdw"
+#ifndef __unused
+#define __unused __attribute__((__unused__))
+#endif
+
+static int __write_to_log_init(struct iovec *vec, size_t nr);
+static int (*write_to_log)(struct iovec *vec, size_t nr) = __write_to_log_init;
+static int logd_fd = -1;
+
+/* give up, resources too limited */
+static int __write_to_log_null(struct iovec *vec __unused,
+ size_t nr __unused)
+{
+ return -1;
+}
+
+/* log_init_lock assumed */
+static int __write_to_log_initialize()
+{
+ int i, ret = 0;
+ if (logd_fd >= 0) {
+ i = logd_fd;
+ logd_fd = -1;
+ close(i);
+ }
+
+ i = socket(PF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0);
+ if (i < 0) {
+ ret = -errno;
+ write_to_log = __write_to_log_null;
+ } else if (fcntl(i, F_SETFL, O_NONBLOCK) < 0) {
+ ret = -errno;
+ close(i);
+ i = -1;
+ write_to_log = __write_to_log_null;
+ } else {
+ struct sockaddr_un un;
+ memset(&un, 0, sizeof(struct sockaddr_un));
+ un.sun_family = AF_UNIX;
+ strlcpy(un.sun_path, SEEMP_SOCK_NAME, sizeof(un.sun_path));
+ if (connect(i, (struct sockaddr *)&un, sizeof(struct sockaddr_un)) < 0) {
+ ret = -errno;
+ close(i);
+ i = -1;
+ }
+ }
+ logd_fd = i;
+ return ret;
+}
+
+static int __write_to_log_socket(struct iovec *vec, size_t nr)
+{
+ ssize_t ret;
+ if (logd_fd < 0) {
+ return -EBADF;
+ }
+
+ /*
+ * The write below could be lost, but will never block.
+ *
+ * ENOTCONN occurs if logd dies.
+ * EAGAIN occurs if logd is overloaded.
+ */
+ ret = writev(logd_fd, vec, nr);
+ if (ret < 0) {
+ ret = -errno;
+ if (ret == -ENOTCONN) {
+ ret = __write_to_log_initialize();
+ if (ret < 0) {
+ return ret;
+ }
+
+ ret = writev(logd_fd, vec, nr);
+ if (ret < 0) {
+ ret = -errno;
+ }
+ }
+ }
+
+ return ret;
+}
+
+static int __write_to_log_init(struct iovec *vec, size_t nr)
+{
+ if (write_to_log == __write_to_log_init) {
+ int ret;
+
+ ret = __write_to_log_initialize();
+ if (ret < 0) {
+ return ret;
+ }
+
+ write_to_log = __write_to_log_socket;
+ }
+ return write_to_log(vec, nr);
+}
+
+int __android_seemp_socket_write(int len, const char *msg)
+{
+ struct iovec vec;
+ vec.iov_base = (void *) msg;
+ vec.iov_len = len;
+
+ return write_to_log(&vec, 1);
+}
+
+namespace android {
+
+/*
+ * In class android.util.Log:
+ * public static native int println_native(int buffer, int priority, String tag, String msg)
+ */
+static jint android_util_SeempLog_println_native(JNIEnv* env, jobject clazz,
+ jint api, jstring msgObj)
+{
+ if (msgObj == NULL) {
+ jniThrowNullPointerException(env, "seemp_println needs a message");
+ return -1;
+ }
+
+ int apiId = (int)api;
+ int apiIdLen = sizeof(apiId);
+ int utf8MsgLen = env->GetStringUTFLength(msgObj);
+ int len = apiIdLen + 1 + utf8MsgLen + 1;
+ char *msg = (char*)malloc(len);
+ if ( NULL == msg )
+ {
+ return -1;
+ }
+ char *params = msg + apiIdLen + 1; // api_id + encoding byte + params
+
+ *((int*)msg) = apiId; // copy api id
+ // // skip encoding byte
+ env->GetStringUTFRegion(msgObj, 0, env->GetStringLength(msgObj), params); // copy message
+ msg[len - 1] = 0; // copy terminating zero
+
+ int res = __android_seemp_socket_write(len, msg); // send message
+
+ free(msg);
+
+ return res;
+}
+
+/*
+ * JNI registration.
+ */
+static JNINativeMethod gMethods[] = {
+ /* name, signature, funcPtr */
+ { "seemp_println_native", "(ILjava/lang/String;)I",
+ (void*) android_util_SeempLog_println_native },
+};
+
+int register_android_util_SeempLog(JNIEnv* env)
+{
+ jclass clazz = env->FindClass("android/util/SeempLog");
+ if (clazz == NULL) {
+ return -1;
+ }
+
+ return AndroidRuntime::registerNativeMethods(env, "android/util/SeempLog", gMethods,
+ NELEM(gMethods));
+}
+
+}; // namespace android
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index 20352eb..7156c0f 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -316,6 +316,39 @@ static void nativeSetLayerStack(JNIEnv* env, jclass clazz, jlong nativeObject, j
}
}
+static void nativeSetBlur(JNIEnv* env, jclass clazz, jlong nativeObject, jfloat blur) {
+ SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
+ status_t err = ctrl->setBlur(blur);
+ if (err < 0 && err != NO_INIT) {
+ doThrowIAE(env);
+ }
+}
+
+static void nativeSetBlurMaskSurface(JNIEnv* env, jclass clazz, jlong nativeObject, jlong maskLayerNativeObject) {
+ SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
+ SurfaceControl* const maskLayer = reinterpret_cast<SurfaceControl *>(maskLayerNativeObject);
+ status_t err = ctrl->setBlurMaskSurface(maskLayer);
+ if (err < 0 && err != NO_INIT) {
+ doThrowIAE(env);
+ }
+}
+
+static void nativeSetBlurMaskSampling(JNIEnv* env, jclass clazz, jlong nativeObject, jint blurMaskSampling) {
+ SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
+ status_t err = ctrl->setBlurMaskSampling(blurMaskSampling);
+ if (err < 0 && err != NO_INIT) {
+ doThrowIAE(env);
+ }
+}
+
+static void nativeSetBlurMaskAlphaThreshold(JNIEnv* env, jclass clazz, jlong nativeObject, jfloat alpha) {
+ SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
+ status_t err = ctrl->setBlurMaskAlphaThreshold(alpha);
+ if (err < 0 && err != NO_INIT) {
+ doThrowIAE(env);
+ }
+}
+
static jobject nativeGetBuiltInDisplay(JNIEnv* env, jclass clazz, jint id) {
sp<IBinder> token(SurfaceComposerClient::getBuiltInDisplay(id));
return javaObjectForIBinder(env, token);
@@ -614,6 +647,14 @@ static JNINativeMethod sSurfaceControlMethods[] = {
(void*)nativeSetWindowCrop },
{"nativeSetLayerStack", "(JI)V",
(void*)nativeSetLayerStack },
+ {"nativeSetBlur", "(JF)V",
+ (void*)nativeSetBlur },
+ {"nativeSetBlurMaskSurface", "(JJ)V",
+ (void*)nativeSetBlurMaskSurface },
+ {"nativeSetBlurMaskSampling", "(JI)V",
+ (void*)nativeSetBlurMaskSampling },
+ {"nativeSetBlurMaskAlphaThreshold", "(JF)V",
+ (void*)nativeSetBlurMaskAlphaThreshold },
{"nativeGetBuiltInDisplay", "(I)Landroid/os/IBinder;",
(void*)nativeGetBuiltInDisplay },
{"nativeCreateDisplay", "(Ljava/lang/String;Z)Landroid/os/IBinder;",
diff --git a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
index daa6f82..c830ffd 100644
--- a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
+++ b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
@@ -36,7 +36,7 @@
#include <inttypes.h>
#include <sys/stat.h>
#include <sys/types.h>
-
+#include <dlfcn.h>
#define APK_LIB "lib/"
#define APK_LIB_LEN (sizeof(APK_LIB) - 1)
@@ -55,6 +55,10 @@
#define TMP_FILE_PATTERN "/tmp.XXXXXX"
#define TMP_FILE_PATTERN_LEN (sizeof(TMP_FILE_PATTERN) - 1)
+#define LIB_UNINIT 0
+#define LIB_INITED_AND_FAIL -1
+#define LIB_INITED_AND_SUCCESS 1
+
namespace android {
// These match PackageManager.java install codes
@@ -70,6 +74,24 @@ enum install_status_t {
typedef install_status_t (*iterFunc)(JNIEnv*, void*, ZipFileRO*, ZipEntryRO, const char*);
+typedef int (*PGetAssetsStatusFunc) (ZipFileRO*, Vector<ScopedUtfChars*>, const int);
+static PGetAssetsStatusFunc GetAssetsStatusFunc = NULL;
+static int g_assetLibInit = LIB_UNINIT;
+
+static int initAssetsVerifierLib() {
+ if (g_assetLibInit != LIB_UNINIT) return g_assetLibInit;
+ void* handle = dlopen("libassetsverifier.so", RTLD_NOW);
+ if (handle != NULL) {
+ GetAssetsStatusFunc = (PGetAssetsStatusFunc)dlsym(handle, "getAssetsStatus");
+ if (GetAssetsStatusFunc != NULL) {
+ g_assetLibInit = LIB_INITED_AND_SUCCESS;
+ } else {
+ g_assetLibInit = LIB_INITED_AND_FAIL;
+ }
+ }
+ return g_assetLibInit;
+}
+
// Equivalent to android.os.FileUtils.isFilenameSafe
static bool
isFilenameSafe(const char* filename)
@@ -478,6 +500,29 @@ static int findSupportedAbi(JNIEnv *env, jlong apkHandle, jobjectArray supported
}
}
+ if(status <= 0) {
+ // Scan the 'assets' folder only if
+ // the abi (after scanning the lib folder)
+ // is not already set to 32-bit (i.e '1' or '2').
+
+ int asset_status = NO_NATIVE_LIBRARIES;
+ int rc = initAssetsVerifierLib();
+
+ if (rc == LIB_INITED_AND_SUCCESS) {
+ asset_status = GetAssetsStatusFunc(zipFile, supportedAbis, numAbis);
+ } else {
+ ALOGV("Failed to load assets verifier: %d", rc);
+ }
+ if(asset_status >= 0) {
+ // Override the ABI only if
+ // 'asset_status' is a valid ABI (64-bit or 32-bit).
+ // This is to prevent cases where 'lib' folder
+ // has native libraries, but
+ // 'assets' folder has none.
+ status = asset_status;
+ }
+ }
+
for (int i = 0; i < numAbis; ++i) {
delete supportedAbis[i];
}
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index b431a3f..aef70be 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -368,8 +368,8 @@ static void DetachDescriptors(JNIEnv* env, jintArray fdsToClose) {
return;
}
jsize count = env->GetArrayLength(fdsToClose);
- jint *ar = env->GetIntArrayElements(fdsToClose, 0);
- if (!ar) {
+ ScopedIntArrayRO ar(env, fdsToClose);
+ if (ar.get() == NULL) {
ALOGE("Bad fd array");
RuntimeAbort(env);
}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 08bccc1..881b283 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -18,6 +18,7 @@
*/
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
package="android" coreApp="true" android:sharedUserId="android.uid.system"
android:sharedUserLabel="@string/android_system_label">
@@ -76,6 +77,7 @@
<protected-broadcast android:name="android.intent.action.USER_FOREGROUND" />
<protected-broadcast android:name="android.intent.action.USER_SWITCHED" />
<protected-broadcast android:name="android.intent.action.INTENT_FILTER_NEEDS_VERIFICATION" />
+ <protected-broadcast android:name="android.intent.action.SU_SESSION_CHANGED" />
<protected-broadcast android:name="android.os.action.POWER_SAVE_MODE_CHANGED" />
<protected-broadcast android:name="android.os.action.POWER_SAVE_MODE_CHANGING" />
@@ -236,6 +238,7 @@
<protected-broadcast android:name="android.intent.action.PROXY_CHANGE" />
<protected-broadcast android:name="android.os.UpdateLock.UPDATE_LOCK_CHANGED" />
+ <protected-broadcast android:name="android.intent.action.NAVBAR_EDIT" />
<protected-broadcast android:name="android.intent.action.DREAMING_STARTED" />
<protected-broadcast android:name="android.intent.action.DREAMING_STOPPED" />
@@ -320,6 +323,8 @@
<protected-broadcast android:name="android.internal.policy.action.BURN_IN_PROTECTION" />
<protected-broadcast android:name="android.app.action.SYSTEM_UPDATE_POLICY_CHANGED" />
<protected-broadcast android:name="android.app.action.DEVICE_OWNER_CHANGED" />
+ <protected-broadcast android:name="org.cyanogenmod.intent.action.THEME_CHANGED" />
+ <protected-broadcast android:name="android.intent.action.THEME_RESOURCES_CACHED" />
<!-- ====================================================================== -->
<!-- RUNTIME PERMISSIONS -->
<!-- ====================================================================== -->
@@ -1225,6 +1230,12 @@
<permission android:name="android.permission.NOTIFY_PENDING_SYSTEM_UPDATE"
android:protectionLevel="signature|privileged" />
+ <!-- Allows an application to override the power key action
+ @hide <p>Not for use by third-party applications.
+ -->
+ <permission android:name="android.permission.PREVENT_POWER_KEY"
+ android:protectionLevel="signature|privileged" />
+
<!-- =========================================== -->
<!-- Permissions associated with camera and image capture -->
<!-- =========================================== -->
@@ -1322,14 +1333,15 @@
<!-- @SystemApi Allows an application to write to internal media storage
@hide -->
<permission android:name="android.permission.WRITE_MEDIA_STORAGE"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged"
+ androidprv:allowViaWhitelist="true" />
<!-- Allows an application to manage access to documents, usually as part
of a document picker.
<p>Protection level: signature
-->
<permission android:name="android.permission.MANAGE_DOCUMENTS"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature|system" />
<!-- ================================== -->
<!-- Permissions for screenlock -->
@@ -1384,7 +1396,8 @@
that removes restrictions on where broadcasts can be sent and allows other
types of interactions. -->
<permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL"
- android:protectionLevel="signature|installer" />
+ android:protectionLevel="signature|installer"
+ androidprv:allowViaWhitelist="true" />
<!-- @SystemApi @hide Allows an application to call APIs that allow it to query and manage
users on the device. This permission is not available to
@@ -1484,6 +1497,14 @@
android:description="@string/permdesc_setWallpaperHints"
android:protectionLevel="normal" />
+ <!-- Allows applications to set the keyguard wallpaper
+ @hide -->
+ <permission android:name="android.permission.SET_KEYGUARD_WALLPAPER"
+ android:permissionGroup="android.permission-group.WALLPAPER"
+ android:protectionLevel="normal"
+ android:label="@string/permlab_setKeyguardWallpaper"
+ android:description="@string/permdesc_setKeyguardWallpaper" />
+
<!-- ============================================ -->
<!-- Permissions for changing the system clock -->
<!-- ============================================ -->
@@ -1627,7 +1648,8 @@
{@link android.content.pm.PackageManager#addPackageToPreferred}
for details. -->
<permission android:name="android.permission.SET_PREFERRED_APPLICATIONS"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature"
+ androidprv:allowViaWhitelist="true" />
<!-- Allows an application to receive the
{@link android.content.Intent#ACTION_BOOT_COMPLETED} that is
@@ -1728,7 +1750,8 @@
interacting with the recovery (system update) system.
@hide -->
<permission android:name="android.permission.RECOVERY"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged"
+ androidprv:allowViaWhitelist="true" />
<!-- Allows the system to bind to an application's task services
@hide -->
@@ -1752,7 +1775,8 @@
<!-- @SystemApi Allows an application to read or write the secure system settings.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.WRITE_SECURE_SETTINGS"
- android:protectionLevel="signature|privileged|development" />
+ android:protectionLevel="signature|privileged|development"
+ androidprv:allowViaWhitelist="true" />
<!-- @SystemApi Allows an application to retrieve state dump information from system services.
<p>Not for use by third-party applications. -->
@@ -1888,7 +1912,8 @@
@hide
-->
<permission android:name="android.permission.SET_ACTIVITY_WATCHER"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature"
+ androidprv:allowViaWhitelist="true" />
<!-- @SystemApi Allows an application to call the activity manager shutdown() API
to put the higher-level system there into a shutdown state.
@@ -2142,7 +2167,8 @@
get access to the frame buffer data.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.READ_FRAME_BUFFER"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged"
+ androidprv:allowViaWhitelist="true" />
<!-- Allows an application to use InputFlinger's low level features.
@hide -->
@@ -2184,7 +2210,8 @@
<p>Not for use by third-party applications.</p>
@hide -->
<permission android:name="android.permission.CAPTURE_AUDIO_HOTWORD"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged"
+ androidprv:allowViaWhitelist="true" />
<!-- @SystemApi Allows an application to modify audio routing and override policy decisions.
<p>Not for use by third-party applications.</p>
@@ -2195,12 +2222,14 @@
<!-- @SystemApi Allows an application to capture video output.
<p>Not for use by third-party applications.</p> -->
<permission android:name="android.permission.CAPTURE_VIDEO_OUTPUT"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged"
+ androidprv:allowViaWhitelist="true" />
<!-- @SystemApi Allows an application to capture secure video output.
<p>Not for use by third-party applications.</p> -->
<permission android:name="android.permission.CAPTURE_SECURE_VIDEO_OUTPUT"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged"
+ androidprv:allowViaWhitelist="true" />
<!-- @SystemApi Allows an application to know what content is playing and control its playback.
<p>Not for use by third-party applications due to privacy of media consumption</p> -->
@@ -2217,7 +2246,8 @@
<!-- @SystemApi Required to be able to reboot the device.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.REBOOT"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged"
+ androidprv:allowViaWhitelist="true" />
<!-- @SystemApi Allows low-level access to power management.
<p>Not for use by third-party applications.
@@ -2249,6 +2279,24 @@
<permission android:name="android.permission.BROADCAST_PACKAGE_REMOVED"
android:protectionLevel="signature" />
+ <!-- Allows an application to add an address to the whitelisted protected sms
+ list
+ @hide -->
+ <permission android:name="android.permission.MODIFY_PROTECTED_SMS_LIST"
+ android:permissionGroup="android.permission-group.MESSAGES"
+ android:label="@string/permlab_modifyProtectedSmsList"
+ android:description="@string/permdesc_modifyProtectedSmsList"
+ android:protectionLevel="signature" />
+
+ <!-- Allows an application to receive sms (usually for auth or registration)
+ from whitelisted addresses
+ @hide -->
+ <permission android:name="android.permission.RECEIVE_PROTECTED_SMS"
+ android:permissionGroup="android.permission-group.MESSAGES"
+ android:label="@string/permlab_receiveProtectedSms"
+ android:description="@string/permdesc_receiveProtectedSms"
+ android:protectionLevel="signature" />
+
<!-- Allows an application to broadcast an SMS receipt notification.
<p>Not for use by third-party applications.
-->
@@ -2331,7 +2379,8 @@
<p>Not for use by third-party applications.
@hide pending API council -->
<permission android:name="android.permission.BACKUP"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged"
+ androidprv:allowViaWhitelist="true" />
<!-- Allows a package to launch the secure full-backup confirmation UI.
ONLY the system process may hold this permission.
@@ -2416,7 +2465,8 @@
<!-- @SystemApi Allow an application to read and write the cache partition.
@hide -->
<permission android:name="android.permission.ACCESS_CACHE_FILESYSTEM"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged"
+ androidprv:allowViaWhitelist="true" />
<!-- Must be required by default container service so that only
the system can bind to it and use it to copy
@@ -2531,7 +2581,8 @@
<!-- Allows an application to control keyguard. Only allowed for system processes.
@hide -->
<permission android:name="android.permission.CONTROL_KEYGUARD"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature"
+ androidprv:allowViaWhitelist="true" />
<!-- Allows an application to listen to trust changes. Only allowed for system processes.
@hide -->
@@ -2667,10 +2718,64 @@
<permission android:name="android.permission.DISPATCH_NFC_MESSAGE"
android:protectionLevel="signature|privileged" />
+ <!-- =============================================================== -->
+ <!-- Permissions for accessing security data -->
+ <!-- =============================================================== -->
+ <eat-comment />
+
+ <!-- Used for permissions that allow an application to access or configure
+ the device security information.
+ @hide This is not a third-party API (intended for system apps). -->
+ <permission-group android:name="android.permission-group.SECURITY"
+ android:label="@string/permgrouplab_security"
+ android:icon="@drawable/perm_group_security"
+ android:description="@string/permgroupdesc_security"
+ android:priority="400"/>
+
+ <!-- Allows an application to read the phone blacklist data.
+ @hide This is not a third-party API (intended for system apps). -->
+ <permission android:name="android.permission.READ_PHONE_BLACKLIST"
+ android:permissionGroup="android.permission-group.SECURITY"
+ android:protectionLevel="signature|system"
+ android:label="@string/permlab_readPhoneBlacklist"
+ android:description="@string/permdesc_readPhoneBlacklist" />
+
+ <!-- Allows an application to change the phone blacklist data.
+ @hide This is not a third-party API (intended for system apps). -->
+ <permission android:name="android.permission.CHANGE_PHONE_BLACKLIST"
+ android:permissionGroup="android.permission-group.SECURITY"
+ android:protectionLevel="signature|system"
+ android:label="@string/permlab_changePhoneBlacklist"
+ android:description="@string/permdesc_changePhoneBlacklist" />
+
<!-- The system process is explicitly the only one allowed to launch the
confirmation UI for full backup/restore -->
<uses-permission android:name="android.permission.CONFIRM_FULL_BACKUP"/>
+ <!-- Allows an application to use the Theme Service
+ @hide -->
+ <permission android:name="android.permission.ACCESS_THEME_MANAGER"
+ android:label="@string/permlab_accessThemeService"
+ android:description="@string/permdesc_accessThemeService"
+ android:protectionLevel="system|signature" />
+
+ <!-- Allows an application to read the current theme configuration and
+ get information about the various themes currently installed
+ @hide -->
+ <permission android:name="android.permission.READ_THEMES"
+ android:label="@string/permlab_readThemes"
+ android:description="@string/permdesc_readThemesDesc"
+ android:protectionLevel="normal" />
+
+ <!-- Allows an application to write the current theme configuration and
+ write information about the various themes currently installed.
+ Changing themes should be done through the service ACCESS_THEME_MANAGER
+ @hide -->
+ <permission android:name="android.permission.WRITE_THEMES"
+ android:label="@string/permlab_writeThemes"
+ android:description="@string/permdesc_writeThemesDesc"
+ android:protectionLevel="system|signature" />
+
<application android:process="system"
android:persistent="true"
android:hasCode="false"
@@ -2874,6 +2979,10 @@
</intent-filter>
</receiver>
+ <service android:name="com.android.internal.os.storage.ExternalStorageFormatter"
+ android:permission="android.permission.MASTER_CLEAR"
+ android:exported="true" />
+
<service android:name="android.hardware.location.GeofenceHardwareService"
android:permission="android.permission.LOCATION_HARDWARE"
android:exported="false" />
diff --git a/core/res/res/anim/last_app_in.xml b/core/res/res/anim/last_app_in.xml
new file mode 100644
index 0000000..bf89dbf
--- /dev/null
+++ b/core/res/res/anim/last_app_in.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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.
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+ >
+
+ <translate android:fromXDelta="0%" android:toXDelta="-35%"
+ android:zAdjustment="bottom"
+ android:duration="@android:integer/config_shortAnimTime"
+ android:interpolator="@android:interpolator/fast_out_linear_in"
+ />
+ <scale android:fromXScale="0.80" android:toXScale="1.0"
+ android:fromYScale="0.80" android:toYScale="1.0"
+ android:pivotX="50%" android:pivotY="50%"
+ android:duration="@android:integer/config_shortAnimTime"
+ android:interpolator="@android:interpolator/linear"
+ />
+ <translate android:fromXDelta="-35%" android:toXDelta="35%"
+ android:zAdjustment="top"
+ android:startOffset="@android:integer/config_shortAnimTime"
+ android:duration="@android:integer/config_shortAnimTime"
+ android:interpolator="@android:interpolator/linear_out_slow_in"
+ />
+ <alpha android:fromAlpha="0.6" android:toAlpha="1.0"
+ android:duration="@android:integer/config_shortAnimTime"
+ android:interpolator="@android:interpolator/linear"
+ />
+</set>
diff --git a/core/res/res/anim/last_app_out.xml b/core/res/res/anim/last_app_out.xml
new file mode 100644
index 0000000..834dfff
--- /dev/null
+++ b/core/res/res/anim/last_app_out.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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.
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+ >
+
+ <translate android:fromXDelta="-35%" android:toXDelta="35%"
+ android:zAdjustment="top"
+ android:duration="@android:integer/config_shortAnimTime"
+ android:interpolator="@android:interpolator/fast_out_linear_in"
+ />
+ <scale android:fromXScale="1.0" android:toXScale="0.80"
+ android:fromYScale="1.0" android:toYScale="0.80"
+ android:pivotX="50%" android:pivotY="50%"
+ android:duration="@android:integer/config_shortAnimTime"
+ android:interpolator="@android:interpolator/linear"
+ />
+ <translate android:fromXDelta="35%" android:toXDelta="-35%"
+ android:zAdjustment="bottom"
+ android:startOffset="@android:integer/config_shortAnimTime"
+ android:duration="@android:integer/config_shortAnimTime"
+ android:interpolator="@android:interpolator/linear_out_slow_in"
+ />
+ <alpha android:fromAlpha="1.0" android:toAlpha="0.6"
+ android:duration="@android:integer/config_shortAnimTime"
+ android:interpolator="@android:interpolator/linear"
+ />
+</set>
diff --git a/core/res/res/anim/lock_screen_wallpaper_exit_noop.xml b/core/res/res/anim/lock_screen_wallpaper_exit_noop.xml
new file mode 100644
index 0000000..4cc5c70
--- /dev/null
+++ b/core/res/res/anim/lock_screen_wallpaper_exit_noop.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2014 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.
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shareInterpolator="false" android:startOffset="100">
+ <alpha
+ android:fromAlpha="0.0" android:toAlpha="0.0"
+ android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
+ android:interpolator="@interpolator/fast_out_linear_in"
+ android:duration="150"/>
+
+ <!-- Empty animation so the animation has same duration as lock_screen_behind_enter animation
+ -->
+ <translate android:fromYDelta="0" android:toYDelta="0"
+ android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
+ android:interpolator="@interpolator/linear"
+ android:duration="300" />
+</set> \ No newline at end of file
diff --git a/core/res/res/drawable-hdpi/ic_launcher_android.png b/core/res/res/drawable-hdpi/ic_launcher_android.png
index cce5187..cde69bc 100644
--- a/core/res/res/drawable-hdpi/ic_launcher_android.png
+++ b/core/res/res/drawable-hdpi/ic_launcher_android.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lock_power_reboot_alpha.png b/core/res/res/drawable-hdpi/ic_lock_power_reboot_alpha.png
new file mode 100644
index 0000000..ca00936
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_lock_power_reboot_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lock_profile_alpha.png b/core/res/res/drawable-hdpi/ic_lock_profile_alpha.png
new file mode 100644
index 0000000..7fc4cec
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_lock_profile_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/perm_group_security.png b/core/res/res/drawable-hdpi/perm_group_security.png
new file mode 100644
index 0000000..47f0d6f
--- /dev/null
+++ b/core/res/res/drawable-hdpi/perm_group_security.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_upload_anim1.png b/core/res/res/drawable-hdpi/stat_sys_upload_anim1.png
index 39d2c95..3a9031e 100644
--- a/core/res/res/drawable-hdpi/stat_sys_upload_anim1.png
+++ b/core/res/res/drawable-hdpi/stat_sys_upload_anim1.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_upload_anim2.png b/core/res/res/drawable-hdpi/stat_sys_upload_anim2.png
index 3a9031e..39d2c95 100644
--- a/core/res/res/drawable-hdpi/stat_sys_upload_anim2.png
+++ b/core/res/res/drawable-hdpi/stat_sys_upload_anim2.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_launcher_android.png b/core/res/res/drawable-mdpi/ic_launcher_android.png
index 6a97d5b..c133a0c 100644
--- a/core/res/res/drawable-mdpi/ic_launcher_android.png
+++ b/core/res/res/drawable-mdpi/ic_launcher_android.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lock_power_reboot_alpha.png b/core/res/res/drawable-mdpi/ic_lock_power_reboot_alpha.png
new file mode 100644
index 0000000..2b125b9
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_lock_power_reboot_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lock_profile_alpha.png b/core/res/res/drawable-mdpi/ic_lock_profile_alpha.png
new file mode 100644
index 0000000..d47ba16
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_lock_profile_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/perm_group_security.png b/core/res/res/drawable-mdpi/perm_group_security.png
new file mode 100644
index 0000000..cc00c16
--- /dev/null
+++ b/core/res/res/drawable-mdpi/perm_group_security.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_upload_anim1.png b/core/res/res/drawable-mdpi/stat_sys_upload_anim1.png
index b9c364c..217ea4e 100644
--- a/core/res/res/drawable-mdpi/stat_sys_upload_anim1.png
+++ b/core/res/res/drawable-mdpi/stat_sys_upload_anim1.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_upload_anim2.png b/core/res/res/drawable-mdpi/stat_sys_upload_anim2.png
index 217ea4e..b9c364c 100644
--- a/core/res/res/drawable-mdpi/stat_sys_upload_anim2.png
+++ b/core/res/res/drawable-mdpi/stat_sys_upload_anim2.png
Binary files differ
diff --git a/core/res/res/drawable-nodpi/platlogo_cm.xml b/core/res/res/drawable-nodpi/platlogo_cm.xml
new file mode 100644
index 0000000..b863c27
--- /dev/null
+++ b/core/res/res/drawable-nodpi/platlogo_cm.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (c) 2015 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="48dp"
+ android:height="48dp"
+ android:viewportWidth="48.0"
+ android:viewportHeight="48.0">
+
+ <path
+ android:name="body"
+ android:fillColor="#FFFFFF"
+ android:pathData="M24,12L24,12L24,12L24,12L24,12c7.7,0,14,1.2,14.9,2.6c0,0,0,0,0,0c1,1.5,1.1,6.5,1.1,9.4s-0.1,7.8-1.1,9.4
+c0,0,0,0,0,0C38,34.8,31.7,36,24,36l0,0l0,0l0,0l0,0l0,0l0,0l0,0l0,0c-7.7,0-14-1.2-14.9-2.6c0,0,0,0,0,0C8.1,31.8,8,26.9,8,24
+s0.1-7.8,1.1-9.4c0,0,0,0,0,0C10,13.2,16.3,12,24,12L24,12L24,12L24,12L24,12z" />
+ <path
+ android:name="top"
+ android:fillColor="#EBEBEB"
+ android:pathData="M39,15c0,1.7-6.7,3-15,3S9,16.7,9,15s6.7-3,15-3S39,13.3,39,15z" />
+ <path
+ android:name="r_ant"
+ android:fillColor="#FFFFFF"
+ android:pathData="M35,15c-0.1,0-0.3,0-0.4-0.1c-0.5-0.2-0.8-0.8-0.5-1.3l2-5c0.2-0.5,0.8-0.8,1.3-0.5
+c0.5,0.2,0.8,0.8,0.5,1.3l-2,5C35.7,14.8,35.3,15,35,15z" />
+ <path
+ android:name="l_ant"
+ android:fillColor="#FFFFFF"
+ android:pathData="M13,15c0.1,0,0.3,0,0.4-0.1c0.5-0.2,0.8-0.8,0.5-1.3l-2-5c-0.2-0.5-0.8-0.8-1.3-0.5
+c-0.5,0.2-0.8,0.8-0.5,1.3l2,5C12.3,14.8,12.7,15,13,15z" />
+ <path
+ android:name="smile"
+ android:fillColor="#EBEBEB"
+ android:pathData="M22,32C22,32,22,32.1,22,32c0,0.9,0.6,1.5,1.4,1.5h1.1c0.8,0,1.5-0.7,1.5-1.5c0,0,0-0.1,0-0.1H22z" />
+ <path
+ android:name="l_eye"
+ android:fillColor="#EBEBEB"
+ android:pathData="M16,20c-2.8,0-5,2.2-5,5c0,2.8,2.2,5,5,5c2.8,0,5-2.2,5-5C21,22.2,18.8,20,16,20z" />
+ <path
+ android:name="r_eye"
+ android:fillColor="#EBEBEB"
+ android:pathData="M32,20c-2.8,0-5,2.2-5,5c0,2.8,2.2,5,5,5c2.8,0,5-2.2,5-5C37,22.2,34.8,20,32,20z" />
+</vector>
diff --git a/core/res/res/drawable-nodpi/stat_sys_adb.xml b/core/res/res/drawable-nodpi/stat_sys_adb.xml
index 8cc9961..9dd9497 100644
--- a/core/res/res/drawable-nodpi/stat_sys_adb.xml
+++ b/core/res/res/drawable-nodpi/stat_sys_adb.xml
@@ -1,11 +1,11 @@
<!--
-Copyright (C) 2014 The Android Open Source Project
+ Copyright (c) 2015 The CyanogenMod Project
- Licensed under the Apache License, Version 2.0 (the "License");
+ Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
+ http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
@@ -14,23 +14,26 @@ Copyright (C) 2014 The Android Open Source Project
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24.0dp"
- android:height="24.0dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+
+ <path
+ android:fillColor="#FFFFFF"
+ android:pathData="M21.3,6.6L21,6.9c0,1-3.8,1.7-9,1.7S3,7.9,3,6.9L2.7,6.6C2.1,7.6,2,10.7,2,12.5
+c0,1.8,0.1,4.9,0.7,5.8l0,0C3.2,19.3,7.2,20,12,20c4.8,0,8.8-0.7,9.3-1.7l0,0c0.6-1,0.7-4.1,0.7-5.8C22,10.7,21.9,7.6,21.3,6.6z
+M7,17c-1.7,0-3-1.3-3-3s1.3-3,3-3c1.7,0,3,1.3,3,3S8.7,17,7,17z
+M17,17c-1.7,0-3-1.3-3-3c0-1.7,1.3-3,3-3c1.7,0,3,1.3,3,3 C20,15.7,18.7,17,17,17z" />
<path
- android:pathData="M8.4,5.3c-0.2,0.0 -0.4,-0.2 -0.5,-0.4L7.1,1.6C7.0,1.4 7.2,1.1 7.4,1.0C7.7,0.9 8.0,1.1 8.0,1.4l0.8,3.3c0.1,0.3 -0.1,0.5 -0.4,0.6C8.5,5.3 8.4,5.3 8.4,5.3z"
- android:fillColor="#FFFFFF"/>
+ android:fillColor="#BBFFFFFF"
+ android:pathData="M21.4,6.9c0,1-4.2,1.9-9.4,1.9S2.6,7.9,2.6,6.9S6.8,5,12,5S21.4,5.8,21.4,6.9z" />
<path
- android:pathData="M15.6,5.3c0.0,0.0 -0.1,0.0 -0.1,0.0c-0.3,-0.1 -0.4,-0.3 -0.4,-0.6L16.0,1.4C16.0,1.1 16.3,0.9 16.6,1.0c0.3,0.1 0.4,0.3 0.4,0.6l-0.8,3.3C16.1,5.1 15.9,5.3 15.6,5.3z"
- android:fillColor="#FFFFFF"/>
+ android:fillColor="#FFFFFF"
+ android:pathData="M19.7,6.5c-0.1,0.3-0.5,0.5-0.8,0.3c-0.3-0.1-0.5-0.5-0.3-0.8l1.3-3.1c0.1-0.3,0.5-0.5,0.8-0.3
+C20.9,2.7,21.1,3,21,3.4L19.7,6.5z" />
<path
- android:pathData="M18.6,5.4c-0.1,-0.1 -0.2,-0.1 -0.3,-0.2c0.2,0.2 0.3,0.3 0.3,0.5c0.0,0.9 -2.9,1.7 -6.6,1.7S5.4,6.7 5.4,5.7c0.0,-0.2 0.1,-0.3 0.3,-0.5C5.6,5.3 5.5,5.4 5.4,5.4C5.0,5.9 4.0,8.0 4.0,12.0s1.0,6.1 1.4,6.6C5.9,19.0 8.0,20.0 12.0,20.0s6.1,-1.0 6.6,-1.4C19.0,18.1 20.0,16.0 20.0,12.0S19.0,5.9 18.6,5.4zM8.0,13.0c-0.6,0.0 -1.0,-0.4 -1.0,-1.0c0.0,-0.6 0.4,-1.0 1.0,-1.0s1.0,0.4 1.0,1.0C9.0,12.6 8.6,13.0 8.0,13.0zM16.0,13.0c-0.6,0.0 -1.0,-0.4 -1.0,-1.0c0.0,-0.6 0.4,-1.0 1.0,-1.0s1.0,0.4 1.0,1.0C17.0,12.6 16.6,13.0 16.0,13.0z"
- android:fillColor="#FFFFFF"/>
- <path
- android:pathData="M5.35,5.7
- a 6.6 1.75 0 1 1 13.25 0
- a 6.6 1.75 0 1 1 -13.25 0
- z"
- android:fillColor="#BBFFFFFF" />
+ android:fillColor="#FFFFFF"
+ android:pathData="M4.3,6.5C4.5,6.8,4.8,7,5.1,6.8C5.5,6.7,5.6,6.3,5.5,6L4.2,2.9C4.1,2.6,3.7,2.4,3.4,2.5
+C3.1,2.7,2.9,3,3,3.4L4.3,6.5z" />
</vector>
diff --git a/core/res/res/drawable-xhdpi/ic_launcher_android.png b/core/res/res/drawable-xhdpi/ic_launcher_android.png
index b1097d6..bfa42f0 100644
--- a/core/res/res/drawable-xhdpi/ic_launcher_android.png
+++ b/core/res/res/drawable-xhdpi/ic_launcher_android.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lock_power_reboot_alpha.png b/core/res/res/drawable-xhdpi/ic_lock_power_reboot_alpha.png
new file mode 100644
index 0000000..653970f
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_lock_power_reboot_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lock_profile_alpha.png b/core/res/res/drawable-xhdpi/ic_lock_profile_alpha.png
new file mode 100644
index 0000000..4c9472c
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_lock_profile_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/perm_group_security.png b/core/res/res/drawable-xhdpi/perm_group_security.png
new file mode 100644
index 0000000..d165c74
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/perm_group_security.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/stat_sys_upload_anim1.png b/core/res/res/drawable-xhdpi/stat_sys_upload_anim1.png
index cd0ca73..e443f45 100644
--- a/core/res/res/drawable-xhdpi/stat_sys_upload_anim1.png
+++ b/core/res/res/drawable-xhdpi/stat_sys_upload_anim1.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/stat_sys_upload_anim2.png b/core/res/res/drawable-xhdpi/stat_sys_upload_anim2.png
index e443f45..cd0ca73 100644
--- a/core/res/res/drawable-xhdpi/stat_sys_upload_anim2.png
+++ b/core/res/res/drawable-xhdpi/stat_sys_upload_anim2.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_launcher_android.png b/core/res/res/drawable-xxhdpi/ic_launcher_android.png
new file mode 100644
index 0000000..324e72c
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_launcher_android.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_lock_power_reboot_alpha.png b/core/res/res/drawable-xxhdpi/ic_lock_power_reboot_alpha.png
new file mode 100644
index 0000000..362bf28
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_lock_power_reboot_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_lock_profile_alpha.png b/core/res/res/drawable-xxhdpi/ic_lock_profile_alpha.png
new file mode 100644
index 0000000..e23c484
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_lock_profile_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/perm_group_security.png b/core/res/res/drawable-xxhdpi/perm_group_security.png
new file mode 100644
index 0000000..670ae68
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/perm_group_security.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/stat_sys_upload_anim1.png b/core/res/res/drawable-xxhdpi/stat_sys_upload_anim1.png
index 39dd3b8..b828430 100755
--- a/core/res/res/drawable-xxhdpi/stat_sys_upload_anim1.png
+++ b/core/res/res/drawable-xxhdpi/stat_sys_upload_anim1.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/stat_sys_upload_anim2.png b/core/res/res/drawable-xxhdpi/stat_sys_upload_anim2.png
index b828430..39dd3b8 100755
--- a/core/res/res/drawable-xxhdpi/stat_sys_upload_anim2.png
+++ b/core/res/res/drawable-xxhdpi/stat_sys_upload_anim2.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_launcher_android.png b/core/res/res/drawable-xxxhdpi/ic_launcher_android.png
new file mode 100644
index 0000000..aee44e1
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/ic_launcher_android.png
Binary files differ
diff --git a/core/res/res/drawable/ic_lock_lock.xml b/core/res/res/drawable/ic_lock_lock.xml
index 39f268a..6c87b42 100644
--- a/core/res/res/drawable/ic_lock_lock.xml
+++ b/core/res/res/drawable/ic_lock_lock.xml
@@ -16,4 +16,4 @@
<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
android:src="@drawable/ic_lock_lock_alpha"
- android:tint="?attr/colorControlActivated" />
+ android:tint="?attr/colorControlNormal" />
diff --git a/core/res/res/drawable/ic_lock_power_reboot.xml b/core/res/res/drawable/ic_lock_power_reboot.xml
new file mode 100644
index 0000000..82c7927
--- /dev/null
+++ b/core/res/res/drawable/ic_lock_power_reboot.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (c) 2014, The Linux Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+-->
+
+<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
+ android:src="@drawable/ic_lock_power_reboot_alpha"
+ android:tint="?attr/colorControlNormal" />
+
diff --git a/core/res/res/drawable/ic_lock_profile.xml b/core/res/res/drawable/ic_lock_profile.xml
new file mode 100644
index 0000000..393138b
--- /dev/null
+++ b/core/res/res/drawable/ic_lock_profile.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2015 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.
+-->
+<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
+ android:src="@drawable/ic_lock_profile_alpha"
+ android:tint="?attr/colorControlNormal" />
diff --git a/core/res/res/drawable/ic_lock_screenshot.xml b/core/res/res/drawable/ic_lock_screenshot.xml
new file mode 100644
index 0000000..b682f92
--- /dev/null
+++ b/core/res/res/drawable/ic_lock_screenshot.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2015 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="32dp"
+ android:height="32dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"
+ android:tint="?attr/colorControlNormal">
+
+ <path
+ android:fillColor="@color/white"
+ android:pathData="M16 1H8C6.34 1 5 2.34 5 4v16c0 1.66 1.34 3 3 3h8c1.66 0 3-1.34 3-3V4c0-1.66-1.34-3-3-3zm-2 20h-4v-1h4v1zm3.25-3H6.75V4h10.5v14z" />
+</vector>
diff --git a/core/res/res/drawable/ic_lock_settings.xml b/core/res/res/drawable/ic_lock_settings.xml
new file mode 100644
index 0000000..4c6ded2
--- /dev/null
+++ b/core/res/res/drawable/ic_lock_settings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2014 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="32dp"
+ android:height="32dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"
+ android:tint="?attr/colorControlNormal">
+
+ <path
+ android:fillColor="@color/white"
+ android:pathData="M19.4,13.0c0.0,-0.3 0.1,-0.6 0.1,-1.0s0.0,-0.7 -0.1,-1.0l2.1,-1.7c0.2,-0.2 0.2,-0.4 0.1,-0.6l-2.0,-3.5C19.5,5.1 19.3,5.0 19.0,5.1l-2.5,1.0c-0.5,-0.4 -1.1,-0.7 -1.7,-1.0l-0.4,-2.6C14.5,2.2 14.2,2.0 14.0,2.0l-4.0,0.0C9.8,2.0 9.5,2.2 9.5,2.4L9.1,5.1C8.5,5.3 8.0,5.7 7.4,6.1L5.0,5.1C4.7,5.0 4.5,5.1 4.3,5.3l-2.0,3.5C2.2,8.9 2.3,9.2 2.5,9.4L4.6,11.0c0.0,0.3 -0.1,0.6 -0.1,1.0s0.0,0.7 0.1,1.0l-2.1,1.7c-0.2,0.2 -0.2,0.4 -0.1,0.6l2.0,3.5C4.5,18.9 4.7,19.0 5.0,18.9l2.5,-1.0c0.5,0.4 1.1,0.7 1.7,1.0l0.4,2.6c0.0,0.2 0.2,0.4 0.5,0.4l4.0,0.0c0.2,0.0 0.5,-0.2 0.5,-0.4l0.4,-2.6c0.6,-0.3 1.2,-0.6 1.7,-1.0l2.5,1.0c0.2,0.1 0.5,0.0 0.6,-0.2l2.0,-3.5c0.1,-0.2 0.1,-0.5 -0.1,-0.6L19.4,13.0zM12.0,15.5c-1.9,0.0 -3.5,-1.6 -3.5,-3.5s1.6,-3.5 3.5,-3.5s3.5,1.6 3.5,3.5S13.9,15.5 12.0,15.5z" />
+</vector>
diff --git a/core/res/res/drawable/ic_lock_user.xml b/core/res/res/drawable/ic_lock_user.xml
new file mode 100644
index 0000000..e951319
--- /dev/null
+++ b/core/res/res/drawable/ic_lock_user.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2015 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="32dp"
+ android:height="32dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"
+ android:tint="?attr/colorControlNormal">
+
+ <path
+ android:fillColor="@color/white"
+ android:pathData="M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z" />
+</vector>
diff --git a/core/res/res/drawable/ic_zen_important.xml b/core/res/res/drawable/ic_zen_important.xml
new file mode 100644
index 0000000..4dc8793
--- /dev/null
+++ b/core/res/res/drawable/ic_zen_important.xml
@@ -0,0 +1,25 @@
+<!--
+Copyright (C) 2014 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="32dp"
+ android:height="32dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+
+ <path
+ android:fillColor="#8A000000"
+ android:pathData="M12.0,17.273l6.1800003,3.7269993 -1.6350002,-7.0290003 5.455,-4.7269993 -7.191,-0.6170006 -2.809,-6.627 -2.809,6.627 -7.191,0.6170006 5.455,4.7269993 -1.6349998,7.0290003z"/>
+</vector>
diff --git a/core/res/res/drawable/ic_zen_none.xml b/core/res/res/drawable/ic_zen_none.xml
new file mode 100644
index 0000000..bd74c38
--- /dev/null
+++ b/core/res/res/drawable/ic_zen_none.xml
@@ -0,0 +1,25 @@
+<!--
+Copyright (C) 2014 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="32dp"
+ android:height="32dp"
+ android:viewportWidth="48.0"
+ android:viewportHeight="48.0">
+
+ <path
+ android:fillColor="#8A000000"
+ android:pathData="M24.0,4.0C13.0,4.0 4.0,13.0 4.0,24.0c0.0,11.0 9.0,20.0 20.0,20.0c11.0,0.0 20.0,-9.0 20.0,-20.0C44.0,13.0 35.0,4.0 24.0,4.0zM24.0,40.0c-8.8,0.0 -16.0,-7.2 -16.0,-16.0c0.0,-3.7 1.3,-7.1 3.4,-9.8l22.4,22.4C31.1,38.7 27.7,40.0 24.0,40.0zM36.6,33.8L14.2,11.4C16.9,9.3 20.3,8.0 24.0,8.0c8.8,0.0 16.0,7.2 16.0,16.0C40.0,27.7 38.7,31.1 36.6,33.8z"/>
+</vector>
diff --git a/core/res/res/drawable/progress_large.xml b/core/res/res/drawable/progress_large.xml
index 4f016bc..44b4103 100644
--- a/core/res/res/drawable/progress_large.xml
+++ b/core/res/res/drawable/progress_large.xml
@@ -21,5 +21,5 @@
android:drawable="@drawable/spinner_black_76"
android:pivotX="50%"
android:pivotY="50%"
- android:framesCount="12"
- android:frameDuration="100" />
+ android:framesCount="48"
+ android:frameDuration="25" />
diff --git a/core/res/res/drawable/progress_large_white.xml b/core/res/res/drawable/progress_large_white.xml
index c690ed4..6c2388c 100644
--- a/core/res/res/drawable/progress_large_white.xml
+++ b/core/res/res/drawable/progress_large_white.xml
@@ -21,5 +21,5 @@
android:drawable="@drawable/spinner_white_76"
android:pivotX="50%"
android:pivotY="50%"
- android:framesCount="12"
- android:frameDuration="100" />
+ android:framesCount="48"
+ android:frameDuration="25" />
diff --git a/core/res/res/drawable/progress_medium.xml b/core/res/res/drawable/progress_medium.xml
index eb1bd50..82ad686 100644
--- a/core/res/res/drawable/progress_medium.xml
+++ b/core/res/res/drawable/progress_medium.xml
@@ -21,5 +21,5 @@
android:drawable="@drawable/spinner_black_48"
android:pivotX="50%"
android:pivotY="50%"
- android:framesCount="12"
- android:frameDuration="100" />
+ android:framesCount="48"
+ android:frameDuration="25" />
diff --git a/core/res/res/drawable/progress_medium_white.xml b/core/res/res/drawable/progress_medium_white.xml
index b4f9b31..886ee05 100644
--- a/core/res/res/drawable/progress_medium_white.xml
+++ b/core/res/res/drawable/progress_medium_white.xml
@@ -21,5 +21,5 @@
android:drawable="@drawable/spinner_white_48"
android:pivotX="50%"
android:pivotY="50%"
- android:framesCount="12"
- android:frameDuration="100" />
+ android:framesCount="48"
+ android:frameDuration="25" />
diff --git a/core/res/res/drawable/progress_small.xml b/core/res/res/drawable/progress_small.xml
index e0ee5e4..1881da3 100644
--- a/core/res/res/drawable/progress_small.xml
+++ b/core/res/res/drawable/progress_small.xml
@@ -21,5 +21,5 @@
android:drawable="@drawable/spinner_black_16"
android:pivotX="50%"
android:pivotY="50%"
- android:framesCount="12"
- android:frameDuration="100" />
+ android:framesCount="48"
+ android:frameDuration="25" />
diff --git a/core/res/res/drawable/progress_small_titlebar.xml b/core/res/res/drawable/progress_small_titlebar.xml
index 8cfba86..5bb5cf8 100644
--- a/core/res/res/drawable/progress_small_titlebar.xml
+++ b/core/res/res/drawable/progress_small_titlebar.xml
@@ -21,5 +21,5 @@
android:drawable="@drawable/spinner_white_16"
android:pivotX="50%"
android:pivotY="50%"
- android:framesCount="12"
- android:frameDuration="100" />
+ android:framesCount="48"
+ android:frameDuration="25" />
diff --git a/core/res/res/drawable/progress_small_white.xml b/core/res/res/drawable/progress_small_white.xml
index 8cfba86..5bb5cf8 100644
--- a/core/res/res/drawable/progress_small_white.xml
+++ b/core/res/res/drawable/progress_small_white.xml
@@ -21,5 +21,5 @@
android:drawable="@drawable/spinner_white_16"
android:pivotX="50%"
android:pivotY="50%"
- android:framesCount="12"
- android:frameDuration="100" />
+ android:framesCount="48"
+ android:frameDuration="25" />
diff --git a/core/res/res/drawable/search_spinner.xml b/core/res/res/drawable/search_spinner.xml
index 31a77c3..b8c8b09 100644
--- a/core/res/res/drawable/search_spinner.xml
+++ b/core/res/res/drawable/search_spinner.xml
@@ -21,5 +21,5 @@
android:drawable="@drawable/spinner_black_20"
android:pivotX="50%"
android:pivotY="50%"
- android:framesCount="12"
- android:frameDuration="100" />
+ android:framesCount="48"
+ android:frameDuration="25" />
diff --git a/core/res/res/drawable/stat_notify_privacy_guard.xml b/core/res/res/drawable/stat_notify_privacy_guard.xml
new file mode 100644
index 0000000..bcf3a7f
--- /dev/null
+++ b/core/res/res/drawable/stat_notify_privacy_guard.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="26dp"
+ android:height="24dp"
+ android:viewportWidth="26"
+ android:viewportHeight="24">
+
+ <path
+ android:pathData="M11.999,11.488c0.017,0.148,0.013,0.301-0.017,0.455c-0.155,0.804-0.932,1.33-1.736,1.175 c-0.804-0.155-1.33-0.933-1.175-1.736c0.03-0.154,0.083-0.297,0.154-0.428L11.999,11.488Z M16.775,10.953l-2.774,0.535 c-0.017,0.148-0.013,0.301,0.017,0.455c0.155,0.804,0.932,1.33,1.736,1.175c0.804-0.155,1.33-0.933,1.175-1.736 C16.899,11.228,16.846,11.084,16.775,10.953z M21.539,8.978c-0.132,2.629-0.803,5.264-2.162,7.534 c-1.186,1.991-2.889,3.675-4.905,4.82c-0.459,0.259-0.932,0.494-1.427,0.676c-0.061,0.029-0.122-0.014-0.18-0.032 c-1.047-0.415-2.019-1.006-2.909-1.693c-1.807-1.397-3.239-3.263-4.151-5.356c-0.725-1.651-1.137-3.429-1.297-5.222 C4.33,7.77,4.442,5.816,4.73,3.896c0.601,0.053,1.207,0.031,1.807-0.017c1.309-0.115,2.596-0.41,3.849-0.799 c0.888-0.283,1.766-0.604,2.611-0.999c1.13,0.523,2.311,0.935,3.512,1.26c1.549,0.412,3.157,0.666,4.763,0.562 c0.116,0.846,0.216,1.695,0.261,2.548c0.002,0.241,0.042,0.481,0.037,0.723C21.574,7.776,21.594,8.379,21.539,8.978z M17.957,10.132 c0-0.787-0.345-1.322-1.002-1.675V6.396c0-0.179-0.145-0.324-0.324-0.324c-0.179,0-0.324,0.145-0.324,0.324v1.799 c-0.821-0.248-1.933-0.34-3.307-0.34V7.86h0V7.856c-0.155,0-0.305,0.002-0.453,0.004h-0.001c-1.075,0.018-1.973,0.101-2.677,0.286 v-1.75c0-0.179-0.145-0.324-0.324-0.324c-0.179,0-0.324,0.145-0.324,0.324v1.975C8.449,8.72,8.043,9.277,8.043,10.132v1.943v0.504 v0.554c0,1.702,1.613,2.225,4.503,2.272v0.003h0.179c0.09,0.001,0.182,0.001,0.275,0.001v-0.001h0v0.001 c0.093,0,0.184-0.001,0.275-0.001h0.013c2.995-0.03,4.67-0.54,4.67-2.275v-0.554v-0.504V10.132z"
+ android:fillColor="#FFFFFFFF" />
+</vector>
diff --git a/core/res/res/layout/app_permission_item.xml b/core/res/res/layout/app_permission_item.xml
index 383d771..a80d40e 100644
--- a/core/res/res/layout/app_permission_item.xml
+++ b/core/res/res/layout/app_permission_item.xml
@@ -32,7 +32,7 @@
android:layout_marginStart="16dp"
android:layout_marginEnd="8dp"
android:scaleType="fitCenter"
- android:tint="@android:color/black"/>
+ android:tint="@color/app_permission_icon_tint"/>
<ImageView
android:layout_width="wrap_content"
diff --git a/core/res/res/layout/chooser_grid.xml b/core/res/res/layout/chooser_grid.xml
index 41726fb..c969060 100644
--- a/core/res/res/layout/chooser_grid.xml
+++ b/core/res/res/layout/chooser_grid.xml
@@ -31,7 +31,7 @@
android:layout_alwaysShow="true"
android:elevation="8dp"
android:paddingStart="16dp"
- android:background="@color/white" >
+ android:background="@color/resolver_list_bg" >
<ImageView android:id="@+id/title_icon"
android:layout_width="24dp"
android:layout_height="24dp"
@@ -89,7 +89,7 @@
android:id="@+id/resolver_list"
android:clipToPadding="false"
android:scrollbarStyle="outsideOverlay"
- android:background="@color/white"
+ android:background="@color/resolver_list_bg"
android:elevation="8dp"
android:listSelector="@color/transparent"
android:divider="@null"
@@ -100,7 +100,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alwaysShow="true"
- android:background="@color/white"
+ android:background="@color/resolver_list_bg"
android:text="@string/noApplications"
android:padding="32dp"
android:gravity="center"
diff --git a/core/res/res/layout/global_actions_silent_mode.xml b/core/res/res/layout/global_actions_silent_mode.xml
index a358623..92d688f 100644
--- a/core/res/res/layout/global_actions_silent_mode.xml
+++ b/core/res/res/layout/global_actions_silent_mode.xml
@@ -26,7 +26,7 @@
android:layout_width="64dp"
android:layout_height="match_parent"
android:background="?android:attr/actionBarItemBackground"
- android:contentDescription="@string/silent_mode_silent"
+ android:contentDescription="@string/silent_mode_none"
android:focusable="true"
>
<ImageView
@@ -37,12 +37,13 @@
android:layout_marginEnd="8dp"
android:layout_marginTop="6dp"
android:layout_marginBottom="6dp"
- android:src="@drawable/ic_audio_ring_notif_mute"
+ android:src="@drawable/ic_zen_none"
android:scaleType="center"
android:duplicateParentState="true"
android:background="@drawable/silent_mode_indicator"
/>
</LinearLayout>
+
<!-- Spacer -->
<View android:layout_width="0dp"
android:layout_height="match_parent"
@@ -54,6 +55,35 @@
android:layout_width="64dp"
android:layout_height="match_parent"
android:background="?android:attr/actionBarItemBackground"
+ android:contentDescription="@string/silent_mode_priority"
+ android:focusable="true"
+ >
+ <ImageView
+ android:layout_width="48dp"
+ android:layout_height="match_parent"
+ android:layout_gravity="center"
+ android:layout_marginStart="8dp"
+ android:layout_marginEnd="8dp"
+ android:layout_marginTop="6dp"
+ android:layout_marginBottom="6dp"
+ android:src="@drawable/ic_zen_important"
+ android:scaleType="center"
+ android:duplicateParentState="true"
+ android:background="@drawable/silent_mode_indicator"
+ />
+ </LinearLayout>
+
+ <!-- Spacer -->
+ <View android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:visibility="invisible"/>
+
+ <LinearLayout
+ android:id="@+id/option3"
+ android:layout_width="64dp"
+ android:layout_height="match_parent"
+ android:background="?android:attr/actionBarItemBackground"
android:contentDescription="@string/silent_mode_vibrate"
android:focusable="true"
>
@@ -79,7 +109,7 @@
android:visibility="invisible"/>
<LinearLayout
- android:id="@+id/option3"
+ android:id="@+id/option4"
android:layout_width="64dp"
android:layout_height="match_parent"
android:background="?android:attr/actionBarItemBackground"
@@ -100,4 +130,4 @@
android:background="@drawable/silent_mode_indicator"
/>
</LinearLayout>
-</LinearLayout> \ No newline at end of file
+</LinearLayout>
diff --git a/core/res/res/layout/immersive_mode_cling.xml b/core/res/res/layout/immersive_mode_cling.xml
index 28fbea5..9f3d44d 100644
--- a/core/res/res/layout/immersive_mode_cling.xml
+++ b/core/res/res/layout/immersive_mode_cling.xml
@@ -16,7 +16,7 @@
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:background="#ff009688"
+ android:background="@color/immersive_cling_bg_color"
android:gravity="center_vertical"
android:paddingBottom="24dp">
@@ -47,7 +47,7 @@
android:paddingTop="8dp"
android:scaleType="center"
android:src="@drawable/ic_expand_more_48dp"
- android:tint="#ff009688"/>
+ android:tint="@color/immersive_cling_bg_color"/>
</FrameLayout>
<TextView
@@ -59,7 +59,7 @@
android:paddingStart="48dp"
android:paddingTop="40dp"
android:text="@string/immersive_cling_title"
- android:textColor="@color/primary_text_default_material_light"
+ android:textColor="@color/immersive_cling_text_color"
android:textSize="24sp" />
<TextView
@@ -71,7 +71,7 @@
android:paddingStart="48dp"
android:paddingTop="12.6dp"
android:text="@string/immersive_cling_description"
- android:textColor="@color/primary_text_default_material_light"
+ android:textColor="@color/immersive_cling_text_color"
android:textSize="16sp" />
<Button
@@ -86,7 +86,7 @@
android:paddingEnd="8dp"
android:paddingStart="8dp"
android:text="@string/immersive_cling_positive"
- android:textColor="@android:color/white"
+ android:textColor="@color/immersive_cling_button_text_color"
android:textSize="14sp" />
</RelativeLayout> \ No newline at end of file
diff --git a/core/res/res/layout/notification_material_action.xml b/core/res/res/layout/notification_material_action.xml
index da8b2e7..0a4109a 100644
--- a/core/res/res/layout/notification_material_action.xml
+++ b/core/res/res/layout/notification_material_action.xml
@@ -25,7 +25,7 @@
android:gravity="start|center_vertical"
android:drawablePadding="8dp"
android:paddingStart="8dp"
- android:textColor="@color/secondary_text_material_light"
+ android:textColor="@color/notification_mtrl_action_textcolor"
android:textSize="13sp"
android:singleLine="true"
android:ellipsize="end"
diff --git a/core/res/res/layout/notification_template_material_big_picture.xml b/core/res/res/layout/notification_template_material_big_picture.xml
index f3768b5..81715a5 100644
--- a/core/res/res/layout/notification_template_material_big_picture.xml
+++ b/core/res/res/layout/notification_template_material_big_picture.xml
@@ -46,7 +46,7 @@
android:layout_marginTop="208dp"
android:paddingStart="@dimen/notification_large_icon_width"
android:layout_gravity="bottom"
- android:background="#CCEEEEEE"
+ android:background="@color/notification_mtrl_big_picture_bg"
>
<include
layout="@layout/notification_material_action_list"
diff --git a/core/res/res/layout/permission_confirmation_dialog.xml b/core/res/res/layout/permission_confirmation_dialog.xml
new file mode 100644
index 0000000..ab5b9fa
--- /dev/null
+++ b/core/res/res/layout/permission_confirmation_dialog.xml
@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright (c) 2013, The Linux Foundation. All rights reserved.
+** Not a Contribution.
+**
+** Copyright 2012 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/parentPanel"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="8dip"
+ android:layout_marginRight="8dip"
+ android:orientation="vertical">
+
+ <TextView android:id="@+id/permission_text"
+ style="?android:attr/textAppearanceMedium"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingLeft="20dip"
+ android:paddingRight="20dip"
+ android:paddingTop="16dip"
+ android:paddingBottom="16dip" />
+
+ <TableLayout android:id="@+id/permission_remember_layout"
+ android:shrinkColumns="1"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingLeft="16dip"
+ android:paddingRight="16dip">
+
+ <TableRow
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" >
+ <RelativeLayout android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingTop="12dip"
+ android:paddingLeft="8dip" >
+ <CheckBox android:id="@+id/permission_remember_choice_checkbox"
+ android:paddingTop="11dip"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+ </RelativeLayout>
+ <TextView android:id="@+id/permission_remember_choice_text"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingTop="18dip"
+ android:text="@string/permission_remember_choice" />
+ </TableRow>
+
+ </TableLayout>
+
+</LinearLayout>
diff --git a/core/res/res/layout/preference_list_fragment.xml b/core/res/res/layout/preference_list_fragment.xml
index 4e895b0..f073c33 100644
--- a/core/res/res/layout/preference_list_fragment.xml
+++ b/core/res/res/layout/preference_list_fragment.xml
@@ -41,6 +41,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="@dimen/preference_fragment_padding_side"
+ android:textAppearance="?android:attr/textAppearanceMedium"
android:gravity="center"
android:visibility="gone" />
diff --git a/core/res/res/layout/resolver_different_item_header.xml b/core/res/res/layout/resolver_different_item_header.xml
index 5889136..1386a70 100644
--- a/core/res/res/layout/resolver_different_item_header.xml
+++ b/core/res/res/layout/resolver_different_item_header.xml
@@ -29,6 +29,5 @@
android:paddingEnd="16dp"
android:paddingTop="8dp"
android:paddingBottom="8dp"
- android:background="@color/white"
- android:elevation="8dp"
+ android:background="@color/resolver_list_bg"
/>
diff --git a/core/res/res/layout/resolver_list.xml b/core/res/res/layout/resolver_list.xml
index 00c25e6..f849197 100644
--- a/core/res/res/layout/resolver_list.xml
+++ b/core/res/res/layout/resolver_list.xml
@@ -30,7 +30,7 @@
android:layout_height="wrap_content"
android:layout_alwaysShow="true"
android:elevation="8dp"
- android:background="@color/white" >
+ android:background="@color/resolver_list_bg" >
<TextView android:id="@+id/title"
android:layout_width="0dp"
android:layout_height="wrap_content"
@@ -38,6 +38,7 @@
android:minHeight="56dp"
android:textAppearance="?attr/textAppearanceMedium"
android:gravity="start|center_vertical"
+ android:background="@color/resolver_list_bg"
android:paddingStart="?attr/dialogPreferredPadding"
android:paddingEnd="?attr/dialogPreferredPadding"
android:paddingTop="8dp"
@@ -82,7 +83,7 @@
android:id="@+id/resolver_list"
android:clipToPadding="false"
android:scrollbarStyle="outsideOverlay"
- android:background="@color/white"
+ android:background="@color/resolver_list_bg"
android:elevation="8dp"
android:nestedScrollingEnabled="true"
android:divider="@null" />
@@ -108,7 +109,7 @@
android:orientation="horizontal"
android:layoutDirection="locale"
android:measureWithLargestChild="true"
- android:background="@color/white"
+ android:background="@color/resolver_list_bg"
android:paddingTop="8dp"
android:paddingBottom="8dp"
android:paddingStart="12dp"
diff --git a/core/res/res/layout/resolver_list_with_default.xml b/core/res/res/layout/resolver_list_with_default.xml
index 31361e5..f11112f 100644
--- a/core/res/res/layout/resolver_list_with_default.xml
+++ b/core/res/res/layout/resolver_list_with_default.xml
@@ -30,13 +30,18 @@
android:layout_height="wrap_content"
android:layout_alwaysShow="true"
android:orientation="vertical"
- android:background="@color/white"
+ android:background="@color/resolver_list_bg"
android:elevation="8dp" >
<LinearLayout
+ android:id="@+id/filtered_item_container"
android:layout_width="match_parent"
android:layout_height="64dp"
- android:orientation="horizontal" >
+ android:orientation="horizontal"
+ android:onClick="onButtonClick"
+ android:clickable="true"
+ android:background="?android:selectableItemBackground"
+ >
<ImageView android:id="@+id/icon"
android:layout_width="24dp"
@@ -52,6 +57,7 @@
android:layout_height="?android:attr/listPreferredItemHeight"
android:layout_marginStart="16dp"
android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textColor="?attr/textColorPrimary"
android:gravity="start|center_vertical"
android:paddingEnd="16dp" />
<LinearLayout android:id="@+id/profile_button"
@@ -102,8 +108,7 @@
android:paddingBottom="8dp"
android:paddingStart="12dp"
android:paddingEnd="12dp"
- android:background="@color/white"
- android:elevation="8dp">
+ android:background="@color/resolver_list_bg">
<Button android:id="@+id/button_once"
android:layout_width="wrap_content"
android:layout_gravity="start"
@@ -136,7 +141,7 @@
android:id="@+id/resolver_list"
android:clipToPadding="false"
android:scrollbarStyle="outsideOverlay"
- android:background="@color/white"
+ android:background="@color/resolver_list_bg"
android:elevation="8dp"
android:nestedScrollingEnabled="true"
android:divider="@null"
diff --git a/core/res/res/layout/transient_notification.xml b/core/res/res/layout/transient_notification.xml
index daa9faf..fb1b430 100644
--- a/core/res/res/layout/transient_notification.xml
+++ b/core/res/res/layout/transient_notification.xml
@@ -18,24 +18,35 @@
*/
-->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
- android:background="?android:attr/toastFrameBackground">
+ android:clipChildren="false">
<TextView
android:id="@android:id/message"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_weight="1"
android:layout_gravity="center_horizontal"
+ android:layout_marginTop="-16dp"
+ android:layout_marginStart="-16dp"
+ android:layout_toRightOf="@android:id/icon"
+ android:layout_below="@android:id/icon"
android:textAppearance="@style/TextAppearance.Toast"
android:textColor="@color/bright_foreground_dark"
android:shadowColor="#BB000000"
android:shadowRadius="2.75"
+ android:background="?android:attr/toastFrameBackground"
/>
-</LinearLayout>
+ <ImageView
+ android:id="@android:id/icon"
+ android:layout_width="24dp"
+ android:layout_height="24dp"
+ android:layout_alignParentTop="true"
+ android:layout_alignParentStart="true"/>
+
+</RelativeLayout>
diff --git a/core/res/res/values-ast-rES/donottranslate-maps.xml b/core/res/res/values-ast-rES/donottranslate-maps.xml
new file mode 100644
index 0000000..2e49ced
--- /dev/null
+++ b/core/res/res/values-ast-rES/donottranslate-maps.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2013 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.
+-->
+<resources>
+ <!-- Stub for Asturian -->
+ <integer-array name="maps_starting_lat_lng">
+ <item>40413496</item>
+ <item>-3713379</item>
+ </integer-array>
+ <integer-array name="maps_starting_zoom">
+ <item>6</item>
+ </integer-array>
+</resources>
diff --git a/core/res/res/values-ku-rIQ/donottranslate-maps.xml b/core/res/res/values-ku-rIQ/donottranslate-maps.xml
new file mode 100644
index 0000000..d9f6872
--- /dev/null
+++ b/core/res/res/values-ku-rIQ/donottranslate-maps.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2015 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.
+-->
+<resources>
+ <!-- Stub for Kurdish -->
+ <integer-array name="maps_starting_lat_lng">
+ <item>41034435</item>
+ <item>28977556</item>
+ </integer-array>
+ <integer-array name="maps_starting_zoom">
+ <item>3</item>
+ </integer-array>
+</resources>
diff --git a/core/res/res/values-lb-rLU/donottranslate-maps.xml b/core/res/res/values-lb-rLU/donottranslate-maps.xml
new file mode 100644
index 0000000..18c1eb5
--- /dev/null
+++ b/core/res/res/values-lb-rLU/donottranslate-maps.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2013-2014 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.
+-->
+<resources>
+ <!-- Stub for Luxembourgish -->
+ <integer-array name="maps_starting_lat_lng">
+ <item>50854509</item>
+ <item>4376678</item>
+ </integer-array>
+ <integer-array name="maps_starting_zoom">
+ <item>5</item>
+ </integer-array>
+</resources>
diff --git a/core/res/res/values-mcc204-mnc02/config.xml b/core/res/res/values-mcc204-mnc02/config.xml
new file mode 100644
index 0000000..ee7a899
--- /dev/null
+++ b/core/res/res/values-mcc204-mnc02/config.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- Tele2: Don't use roaming icon for T-Mo -->
+ <string-array translatable="false" name="config_operatorConsideredNonRoaming">
+ <item>20416</item>
+ </string-array>
+</resources>
diff --git a/core/res/res/values-mcc214-mnc32/config.xml b/core/res/res/values-mcc214-mnc32/config.xml
new file mode 100644
index 0000000..874e3a5
--- /dev/null
+++ b/core/res/res/values-mcc214-mnc32/config.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<resources>
+ <string-array translatable="false" name="config_operatorConsideredNonRoaming">
+ <item>21405</item>
+ <item>21407</item>
+ </string-array>
+</resources>
diff --git a/core/res/res/values-mcc219-mnc02/config.xml b/core/res/res/values-mcc219-mnc02/config.xml
index 2ac6ba6..d491951 100644
--- a/core/res/res/values-mcc219-mnc02/config.xml
+++ b/core/res/res/values-mcc219-mnc02/config.xml
@@ -20,6 +20,7 @@
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- Don't use roaming icon for considered operators -->
<string-array translatable="false" name="config_operatorConsideredNonRoaming">
- <item>21901</item>
+ <item>21901</item> <!-- Tele2: Don't use roaming icon for T-Mobile -->
+ <item>21910</item> <!-- Tele2: Don't use roaming icon for VIPnet -->
</string-array>
</resources>
diff --git a/core/res/res/values-mcc222-mnc07/config.xml b/core/res/res/values-mcc222-mnc07/config.xml
new file mode 100644
index 0000000..707c769
--- /dev/null
+++ b/core/res/res/values-mcc222-mnc07/config.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- Noverca: Don't use roaming icon for TIM -->
+ <string-array translatable="false" name="config_operatorConsideredNonRoaming">
+ <item>22201</item>
+ </string-array>
+</resources>
diff --git a/core/res/res/values-mcc232-mnc03/config.xml b/core/res/res/values-mcc232-mnc03/config.xml
new file mode 100644
index 0000000..bc19384
--- /dev/null
+++ b/core/res/res/values-mcc232-mnc03/config.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- Don't use roaming icon for considered operators -->
+ <string-array translatable="false" name="config_operatorConsideredNonRoaming">
+ <item>23210</item>
+ </string-array>
+</resources>
diff --git a/core/res/res/values-mcc232-mnc05/config.xml b/core/res/res/values-mcc232-mnc05/config.xml
new file mode 100644
index 0000000..11e2585
--- /dev/null
+++ b/core/res/res/values-mcc232-mnc05/config.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- Don't use roaming icon for considered operators -->
+ <string-array translatable="false" name="config_operatorConsideredNonRoaming">
+ <item>23203</item>
+ </string-array>
+</resources>
diff --git a/core/res/res/values-mcc232-mnc10/config.xml b/core/res/res/values-mcc232-mnc10/config.xml
new file mode 100644
index 0000000..11e2585
--- /dev/null
+++ b/core/res/res/values-mcc232-mnc10/config.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- Don't use roaming icon for considered operators -->
+ <string-array translatable="false" name="config_operatorConsideredNonRoaming">
+ <item>23203</item>
+ </string-array>
+</resources>
diff --git a/core/res/res/values-mcc232-mnc11/config.xml b/core/res/res/values-mcc232-mnc11/config.xml
new file mode 100644
index 0000000..27cc63d
--- /dev/null
+++ b/core/res/res/values-mcc232-mnc11/config.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- Don't use roaming icon for considered operators -->
+ <string-array translatable="false" name="config_operatorConsideredNonRoaming">
+ <item>23201</item>
+ </string-array>
+</resources>
diff --git a/core/res/res/values-mcc232-mnc12/config.xml b/core/res/res/values-mcc232-mnc12/config.xml
new file mode 100644
index 0000000..409cecc
--- /dev/null
+++ b/core/res/res/values-mcc232-mnc12/config.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ /*
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- Don't use roaming icon for considered operators -->
+ <string-array translatable="false" name="config_operatorConsideredNonRoaming">
+ <item>23201</item>
+ </string-array>
+</resources>
+
diff --git a/core/res/res/values-mcc234-mnc01/config.xml b/core/res/res/values-mcc234-mnc01/config.xml
new file mode 100644
index 0000000..32335ae2
--- /dev/null
+++ b/core/res/res/values-mcc234-mnc01/config.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- Vectone: Don't use roaming icon for T-Mobile -->
+ <string-array translatable="false" name="config_operatorConsideredNonRoaming">
+ <item>23430</item>
+ </string-array>
+</resources>
diff --git a/core/res/res/values-mcc240-mnc10/config.xml b/core/res/res/values-mcc240-mnc10/config.xml
new file mode 100644
index 0000000..28109e0
--- /dev/null
+++ b/core/res/res/values-mcc240-mnc10/config.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2014, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- Don't use roaming icon for considered operators -->
+ <string-array translatable="false" name="config_operatorConsideredNonRoaming">
+ <item>24005</item>
+ <item>24024</item>
+ </string-array>
+</resources>
diff --git a/core/res/res/values-mcc244-mnc21/config.xml b/core/res/res/values-mcc244-mnc21/config.xml
new file mode 100644
index 0000000..731a7fd
--- /dev/null
+++ b/core/res/res/values-mcc244-mnc21/config.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- Sunalahti: Don't use roaming icon for Elisa -->
+ <string-array translatable="false" name="config_operatorConsideredNonRoaming">
+ <item>24405</item>
+ </string-array>
+</resources>
diff --git a/core/res/res/values-mcc260-mnc06/config.xml b/core/res/res/values-mcc260-mnc06/config.xml
new file mode 100644
index 0000000..252565f
--- /dev/null
+++ b/core/res/res/values-mcc260-mnc06/config.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- Don't use roaming icon for considered operators -->
+ <string-array translatable="false" name="config_operatorConsideredNonRoaming">
+ <item>26001</item>
+ <item>26002</item>
+ <item>26003</item>
+ </string-array>
+</resources>
diff --git a/core/res/res/values-mcc268-mnc04/config.xml b/core/res/res/values-mcc268-mnc04/config.xml
new file mode 100644
index 0000000..cc70a32
--- /dev/null
+++ b/core/res/res/values-mcc268-mnc04/config.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- Lycamobile: Don't use roaming icon for Vodafone -->
+ <string-array translatable="false" name="config_operatorConsideredNonRoaming">
+ <item>26801</item>
+ </string-array>
+</resources>
diff --git a/core/res/res/values-mcc268-mnc07/config.xml b/core/res/res/values-mcc268-mnc07/config.xml
new file mode 100644
index 0000000..8af7199
--- /dev/null
+++ b/core/res/res/values-mcc268-mnc07/config.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- Vectone/Delight: Don't use roaming icon for Optimus/NOS -->
+ <string-array translatable="false" name="config_operatorConsideredNonRoaming">
+ <item>26803</item>
+ </string-array>
+</resources>
diff --git a/core/res/res/values-mcc272-mnc05/config.xml b/core/res/res/values-mcc272-mnc05/config.xml
new file mode 100644
index 0000000..50770ef
--- /dev/null
+++ b/core/res/res/values-mcc272-mnc05/config.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- Don't use roaming icon for considered operators -->
+ <string-array translatable="false" name="config_operatorConsideredNonRoaming">
+ <item>27201</item>
+ </string-array>
+</resources>
diff --git a/core/res/res/values-mcc272-mnc11/config.xml b/core/res/res/values-mcc272-mnc11/config.xml
new file mode 100644
index 0000000..f7850c9
--- /dev/null
+++ b/core/res/res/values-mcc272-mnc11/config.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- Don't use roaming icon for considered operators -->
+ <string-array translatable="false" name="config_operatorConsideredNonRoaming">
+ <item>27202</item>
+ </string-array>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc004/config.xml b/core/res/res/values-mcc310-mnc004/config.xml
index cbe5145..60b67d0 100755
--- a/core/res/res/values-mcc310-mnc004/config.xml
+++ b/core/res/res/values-mcc310-mnc004/config.xml
@@ -39,4 +39,11 @@
<item>true</item>
</string-array>
<string translatable="false" name="prohibit_manual_network_selection_in_gobal_mode">true</string>
+ <!-- Configuration that determines if ACTIVATE_REJECT_GGSN is to be
+ treated as a permanent error -->
+ <bool translatable="false" name="config_reject_ggsn_perm_failure">false</bool>
+ <!-- Configuration that determines if PROTOCOL_ERRORS is to be treated as
+ a permamnent error -->
+ <bool translatable="false" name="config_protocol_errors_perm_failure">false</bool>
+
</resources>
diff --git a/core/res/res/values-mcc310-mnc008/config.xml b/core/res/res/values-mcc310-mnc008/config.xml
new file mode 100644
index 0000000..48c98cc
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc008/config.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright (c) 2014 The Linux Foundation. All rights reserved.
+** Not a Contribution.
+** Copyright 2009, 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.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+ for different hardware and product builds. Do not translate. -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+ <!-- Configuration that determines if ACTIVATE_REJECT_GGSN is to be
+ treated as a permanent error -->
+ <bool translatable="false" name="config_reject_ggsn_perm_failure">false</bool>
+ <!-- Configuration that determines if PROTOCOL_ERRORS is to be treated as
+ a permamnent error -->
+ <bool translatable="false" name="config_protocol_errors_perm_failure">false</bool>
+
+</resources>
diff --git a/core/res/res/values-mcc310-mnc009/config.xml b/core/res/res/values-mcc310-mnc009/config.xml
new file mode 100644
index 0000000..48c98cc
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc009/config.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright (c) 2014 The Linux Foundation. All rights reserved.
+** Not a Contribution.
+** Copyright 2009, 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.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+ for different hardware and product builds. Do not translate. -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+ <!-- Configuration that determines if ACTIVATE_REJECT_GGSN is to be
+ treated as a permanent error -->
+ <bool translatable="false" name="config_reject_ggsn_perm_failure">false</bool>
+ <!-- Configuration that determines if PROTOCOL_ERRORS is to be treated as
+ a permamnent error -->
+ <bool translatable="false" name="config_protocol_errors_perm_failure">false</bool>
+
+</resources>
diff --git a/core/res/res/values-mcc311-mnc480/config.xml b/core/res/res/values-mcc311-mnc480/config.xml
index a986b75..343033d 100755
--- a/core/res/res/values-mcc311-mnc480/config.xml
+++ b/core/res/res/values-mcc311-mnc480/config.xml
@@ -69,4 +69,10 @@
<item>true</item>
</string-array>
<string translatable="false" name="prohibit_manual_network_selection_in_gobal_mode">true</string>
+ <!-- Configuration that determines if ACTIVATE_REJECT_GGSN is to be
+ treated as a permanent error -->
+ <bool translatable="false" name="config_reject_ggsn_perm_failure">false</bool>
+ <!-- Configuration that determines if PROTOCOL_ERRORS is to be treated as
+ a permamnent error -->
+ <bool translatable="false" name="config_protocol_errors_perm_failure">false</bool>
</resources>
diff --git a/core/res/res/values-mcc404-mnc55/config.xml b/core/res/res/values-mcc404-mnc55/config.xml
new file mode 100644
index 0000000..14d3d36
--- /dev/null
+++ b/core/res/res/values-mcc404-mnc55/config.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- Don't use roaming icon for considered operators -->
+ <string-array translatable="false" name="config_operatorConsideredNonRoaming">
+ <item>40454</item>
+ </string-array>
+</resources>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 0bafe95..5161d7e 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -1140,6 +1140,9 @@
<string name="car_mode_disable_notification_message" msgid="8035230537563503262">"触摸可退出车载模式。"</string>
<string name="tethered_notification_title" msgid="3146694234398202601">"网络共享或热点已启用"</string>
<string name="tethered_notification_message" msgid="6857031760103062982">"触摸可进行设置。"</string>
+ <string name="tethered_notification_no_device_message">"没有设备已连接。"</string>
+ <string name="tethered_notification_one_device_message">""<xliff:g id="count">%1$s</xliff:g>"个设备已连接。"</string>
+ <string name="tethered_notification_multi_device_message">""<xliff:g id="count">%1$s</xliff:g>"个设备已连接。"</string>
<string name="back_button_label" msgid="2300470004503343439">"上一步"</string>
<string name="next_button_label" msgid="1080555104677992408">"下一步"</string>
<string name="skip_button_label" msgid="1275362299471631819">"跳过"</string>
@@ -1517,4 +1520,8 @@
<item quantity="other">已选择 <xliff:g id="COUNT_1">%1$d</xliff:g> 项</item>
<item quantity="one">已选择 <xliff:g id="COUNT_0">%1$d</xliff:g> 项</item>
</plurals>
+ <!-- Carrier Name -->
+ <string name="China_Mobile">中国移动</string>
+ <string name="China_Unicom">中国联通</string>
+ <string name="China_Telecom">中国电信</string>
</resources>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index ef52d00..3576075 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -1517,4 +1517,8 @@
<item quantity="other">已選取 <xliff:g id="COUNT_1">%1$d</xliff:g> 個項目</item>
<item quantity="one">已選取 <xliff:g id="COUNT_0">%1$d</xliff:g> 個項目</item>
</plurals>
+ <!-- Carrier Name -->
+ <string name="China_Mobile">中國移動</string>
+ <string name="China_Unicom">中國聯通</string>
+ <string name="China_Telecom">中國電信</string>
</resources>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 67abe8d..4e220b1 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -6837,6 +6837,9 @@ i
<attr name="showDefault" format="boolean" />
<!-- Whether to show an item for 'Silent'. -->
<attr name="showSilent" format="boolean" />
+ <!-- The style of the ringtone dialog.
+ @hide -->
+ <attr name="dialogStyle" format="reference" />
</declare-styleable>
<!-- Base attributes available to VolumePreference. -->
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index cf08dea..a0b92b9 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -790,6 +790,8 @@
<flag name="smallestScreenSize" value="0x0800" />
<!-- The layout direction has changed. For example going from LTR to RTL. -->
<flag name="layoutDirection" value="0x2000" />
+ <!-- Theme has changed, This should be an ORed value of all ActivityInfo.CONFIG_THEME_* -->
+ <flag name="themeChange" value="0x300000" />
<!-- The font scaling factor has changed, that is the user has
selected a new global font size. -->
<flag name="fontScale" value="0x40000000" />
@@ -1289,6 +1291,9 @@
<attr name="description" />
<attr name="protectionLevel" />
<attr name="permissionFlags" />
+ <!-- @hide Allows permissions to be granted to specific application signatures,
+ which are defined in /system/etc/permissions/someapp.xml. -->
+ <attr name="allowViaWhitelist" format="boolean" />
</declare-styleable>
<!-- The <code>permission-group</code> tag declares a logical grouping of
diff --git a/core/res/res/values/bools.xml b/core/res/res/values/bools.xml
index 7c63950..0d33a51 100644
--- a/core/res/res/values/bools.xml
+++ b/core/res/res/values/bools.xml
@@ -29,4 +29,8 @@
<!-- Whether to allow vertically stacked button bars. This is disabled for
configurations with a small (e.g. less than 320dp) screen height. -->
<bool name="allow_stacked_button_bar">false</bool>
+ <!-- Whether to enable softap extention feature -->
+ <bool name="config_softap_extention">true</bool>
+ <!-- Whether to enable auto connection feature -->
+ <bool name="wifi_autocon">false</bool>
</resources>
diff --git a/core/res/res/values/cm_arrays.xml b/core/res/res/values/cm_arrays.xml
new file mode 100644
index 0000000..39ba389
--- /dev/null
+++ b/core/res/res/values/cm_arrays.xml
@@ -0,0 +1,191 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2013-2015 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.
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- 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>
+
+ <!-- Defines the shutdown options shown in the reboot dialog. -->
+ <array name="shutdown_reboot_options" translatable="false">
+ <item>@string/reboot_reboot</item>
+ <item>@string/reboot_soft</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>soft_reboot</item>
+ <item>recovery</item>
+ <item>bootloader</item>
+ </string-array>
+
+ <!-- List of packages that should not be themed.
+ Note: These strings are checked using String.startsWith() so include as much of the
+ package name as possible to avoid other packages being un-themed unintentionally -->
+ <string-array name="non_themeable_packages" translatable="false">
+ </string-array>
+
+ <!-- Do not translate. App ops request strings -->
+ <string-array name="app_ops_labels" translatable="false">
+ <!-- OP_COARSE_LOCATION -->
+ <item>@string/app_ops_access_location</item>
+ <!-- OP_FINE_LOCATION -->
+ <item>@string/app_ops_access_location</item>
+ <!-- OP_GPS -->
+ <item>@string/app_ops_access_location</item>
+ <!-- OP_VIBRATE -->
+ <item>@string/app_ops_use_vibrate</item>
+ <!-- OP_READ_CONTACTS -->
+ <item>@string/app_ops_read_contacts</item>
+ <!-- OP_WRITE_CONTACTS -->
+ <item>@string/app_ops_modify_contacts</item>
+ <!-- OP_READ_CALL_LOG -->
+ <item>@string/app_ops_read_call_log</item>
+ <!-- OP_WRITE_CALL_LOG -->
+ <item>@string/app_ops_modify_call_log</item>
+ <!-- OP_READ_CALENDAR -->
+ <item>@string/app_ops_read_calendar</item>
+ <!-- OP_WRITE_CALENDAR -->
+ <item>@string/app_ops_modify_calendar</item>
+ <!-- OP_WIFI_SCAN -->
+ <item>@string/app_ops_scan_wifi</item>
+ <!-- OP_POST_NOTIFICATION -->
+ <item>@string/app_ops_post_notification</item>
+ <!-- OP_NEIGHBORING_CELLS -->
+ <item>@string/app_ops_access_location</item>
+ <!-- OP_CALL_PHONE -->
+ <item>@string/app_ops_make_phone_call</item>
+ <!-- OP_READ_SMS -->
+ <item>@string/app_ops_read_sms</item>
+ <!-- OP_WRITE_SMS -->
+ <item>@string/app_ops_write_sms</item>
+ '<!-- OP_RECEIVE_SMS -->
+ <item>@string/app_ops_receive_sms</item>
+ <!-- OP_RECEIVE_EMERGENCY_SMS -->
+ <item>@string/app_ops_receive_sms</item>
+ <!-- OP_RECEIVE_MMS -->
+ <item>@string/app_ops_receive_sms</item>
+ <!-- OP_RECEIVE_WAP_PUSH -->
+ <item>@string/app_ops_receive_sms</item>
+ <!-- OP_SEND_SMS -->
+ <item>@string/app_ops_send_sms</item>
+ <!-- OP_READ_ICC_SMS -->
+ <item>@string/app_ops_read_sms</item>
+ <!-- OP_WRITE_ICC_SMS -->
+ <item>@string/app_ops_write_sms</item>
+ <!-- OP_WRITE_SETTINGS -->
+ <item>@string/app_ops_modify_settings</item>
+ <!-- OP_SYSTEM_ALERT_WINDOW -->
+ <item>@string/app_ops_draw_on_top</item>
+ <!-- OP_ACCESS_NOTIFICATIONS -->
+ <item>@string/app_ops_access_notifications</item>
+ <!-- OP_CAMERA -->
+ <item>@string/app_ops_access_camera</item>
+ <!-- OP_RECORD_AUDIO -->
+ <item>@string/app_ops_record_audio</item>
+ <!-- OP_PLAY_AUDIO -->
+ <item>@string/app_ops_play_audio</item>
+ <!-- OP_READ_CLIPBOARD -->
+ <item>@string/app_ops_read_clipboard</item>
+ <!-- OP_WRITE_CLIPBOARD -->
+ <item>@string/app_ops_modify_clipboard</item>
+ <!-- OP_TAKE_MEDIA_BUTTONS -->
+ <item>@string/app_ops_use_media_buttons</item>
+ <!-- OP_TAKE_AUDIO_FOCUS -->
+ <item>@string/app_ops_use_audio_focus</item>
+ <!-- OP_AUDIO_MASTER_VOLUME -->
+ <item>@string/app_ops_use_master_volume</item>
+ <!-- OP_AUDIO_VOICE_VOLUME -->
+ <item>@string/app_ops_use_voice_volume</item>
+ <!-- OP_AUDIO_RING_VOLUME -->
+ <item>@string/app_ops_use_ring_volume</item>
+ <!-- OP_AUDIO_MEDIA_VOLUME -->
+ <item>@string/app_ops_use_media_volume</item>
+ <!-- OP_AUDIO_ALARM_VOLUME -->
+ <item>@string/app_ops_use_alarm_volume</item>
+ <!-- OP_AUDIO_NOTIFICATION_VOLUME -->
+ <item>@string/app_ops_use_notification_volume</item>
+ <!-- OP_AUDIO_BLUETOOTH_VOLUME -->
+ <item>@string/app_ops_use_bluetooth_volume</item>
+ <!-- OP_WAKE_LOCK -->
+ <item>@string/app_ops_keep_device_awake</item>
+ <!-- OP_MONITOR_LOCATION -->
+ <item>@string/app_ops_access_location</item>
+ <!-- OP_MONITOR_HIGH_POWER_LOCATION -->
+ <item>@string/app_ops_access_location</item>
+ <!-- OP_GET_USAGE_STATS -->
+ <item>@string/app_ops_get_usage_stats</item>
+ <!-- OP_MUTE_MICROPHONE -->
+ <item>@string/app_ops_mute_unmute_microphone</item>
+ <!-- OP_TOAST_WINDOW -->
+ <item>@string/app_ops_toast_window</item>
+ <!-- OP_PROJECT_MEDIA -->
+ <item>@string/app_ops_project_media</item>
+ <!-- OP_ACTIVATE_VPN -->
+ <item>@string/app_ops_activate_vpn</item>
+ <!-- OP_WRITE_WALLPAPER -->
+ <item>@string/app_ops_change_wallpaper</item>
+ <!-- OP_ASSIST_STRUCTURE -->
+ <item>@string/app_ops_assist_structure</item>
+ <!-- OP_ASSIST_SCREENSHOT -->
+ <item>@string/app_ops_assist_screenshot</item>
+ <!-- OP_READ_PHONE_STATE -->
+ <item>@string/app_ops_read_phone_state</item>
+ <!-- OP_ADD_VOICEMAIL -->
+ <item>@string/app_ops_add_voicemail</item>
+ <!-- OP_USE_SIP -->
+ <item>@string/app_ops_make_phone_call</item>
+ <!-- OP_PROCESS_OUTGOING_CALLS -->
+ <item>@string/app_ops_make_phone_call</item>
+ <!-- OP_USE_FINGERPRINT -->
+ <item>@string/app_ops_use_fingerprint</item>
+ <!-- OP_BODY_SENSORS -->
+ <item>@string/app_ops_use_body_sensors</item>
+ <!-- OP_READ_CELL_BROADCASTS -->
+ <item>@string/app_ops_read_cell_broadcasts</item>
+ <!-- OP_MOCK_LOCATION -->
+ <item>@string/app_ops_mock_location</item>
+ <!-- OP_READ_EXTERNAL_STORAGE -->
+ <item>@string/app_ops_read_external_storage</item>
+ <!-- OP_WRITE_EXTERNAL_STORAGE -->
+ <item>@string/app_ops_write_external_storage</item>
+ <!-- OP_TURN_SCREEN_ON -->
+ <item>@string/app_ops_turn_on_screen</item>
+ <!-- OP_GET_ACCOUNTS -->
+ <item>@string/app_ops_get_accounts</item>
+ <!-- OP_WIFI_CHANGE -->
+ <item>@string/app_ops_wifi_change</item>
+ <!-- OP_BLUETOOTH_CHANGE -->
+ <item>@string/app_ops_toggle_bluetooth</item>
+ <!-- OP_BOOT_COMPLETED -->
+ <item>@string/app_ops_start_at_bootup</item>
+ <!-- OP_NFC_CHANGE -->
+ <item>@string/app_ops_toggle_nfc</item>
+ <!-- OP_DATA_CONNECT_CHANGE -->
+ <item>@string/app_ops_toggle_mobile_data</item>
+ <!-- OP_SU -->
+ <item>@string/app_ops_su</item>
+ </string-array>
+
+</resources>
diff --git a/core/res/res/values/cm_colors.xml b/core/res/res/values/cm_colors.xml
new file mode 100644
index 0000000..8e7e5c5
--- /dev/null
+++ b/core/res/res/values/cm_colors.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <color name="immersive_cling_bg_color">#ff009688</color>
+ <color name="immersive_cling_text_color">@color/primary_text_default_material_light</color>
+ <color name="immersive_cling_button_text_color">@android:color/white</color>
+ <color name="app_permission_icon_tint">@android:color/black</color>
+ <color name="notification_mtrl_action_textcolor">@color/secondary_text_material_light</color>
+ <color name="notification_mtrl_big_picture_bg">#CCEEEEEE</color>
+ <color name="resolver_list_bg">@color/white</color>
+</resources>
diff --git a/core/res/res/values/cm_strings.xml b/core/res/res/values/cm_strings.xml
new file mode 100644
index 0000000..ed573a8
--- /dev/null
+++ b/core/res/res/values/cm_strings.xml
@@ -0,0 +1,209 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2012-2014 The CyanogenMod Project
+ Copyright (c) 2013, The Linux Foundation. All rights reserved.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+ <!-- label for item that screenshots in phone options dialog -->
+ <string name="global_action_screenshot">Screenshot</string>
+
+ <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permlab_receiveProtectedSms">receive protected SMS</string>
+ <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permdesc_receiveProtectedSms">Allows the app to receive an incoming protected SMS.</string>
+
+ <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permlab_modifyProtectedSmsList">modify protected SMS list</string>
+ <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permdesc_modifyProtectedSmsList">Allows the app to modify the protected sms address list.</string>
+
+ <!-- Title of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permgrouplab_security">Security</string>
+ <!-- Description of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permgroupdesc_security">Permissions related to device security information.</string>
+
+ <!-- [CHAR LIMIT=NONE] Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permlab_readPhoneBlacklist">read phone blacklist</string>
+ <!-- [CHAR LIMIT=NONE] Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permdesc_readPhoneBlacklist">Allows an app to read information about phone numbers that are blocked for incoming calls or messages.</string>
+
+ <!-- [CHAR LIMIT=NONE] Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permlab_changePhoneBlacklist">change phone blacklist</string>
+ <!-- [CHAR LIMIT=NONE] Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permdesc_changePhoneBlacklist">Allows an app to change the phone numbers that are blocked for incoming calls or messages.</string>
+
+ <!-- label for item that opens the profile choosing dialog -->
+ <string name="global_action_choose_profile">Profile</string>
+
+ <!-- Title of an application permission, listed so the user can choose whether they want the application to do this. -->
+ <string name="permlab_setKeyguardWallpaper">set keyguard wallpaper</string>
+ <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permdesc_setKeyguardWallpaper">Allows an app to change the lock screen wallpaper.</string>
+
+ <!-- label for item that reboots the phone in phone options dialog -->
+ <string name="global_action_reboot">Reboot</string>
+ <!-- label for current user in phone options dialog -->
+ <string name="global_action_current_user">Current</string>
+
+ <!-- Reboot menu -->
+ <!-- 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 download, within the Reboot Options dialog -->
+ <string name="reboot_download">Download</string>
+ <!-- Button to soft reboot the device, within the Reboot Options dialog -->
+ <string name="reboot_soft">Soft reboot</string>
+
+ <!-- Title of dialog to confirm rebooting. -->
+ <string name="reboot_title">Reboot</string>
+
+ <!-- Reboot Confirmation Dialog. When the user chooses to reboot the device, there will
+ be a confirmation dialog. This is the message. -->
+ <string name="reboot_confirm" product="tablet">Your tablet will reboot.</string>
+ <string name="reboot_confirm" product="default">Your phone will reboot.</string>
+
+ <!-- Reboot Progress Dialog. This is shown if the user chooses to reboot the phone. -->
+ <string name="reboot_progress">Rebooting\u2026</string>
+
+ <!-- Long-press back kill application -->
+ <string name="app_killed_message">Application killed</string>
+
+ <!-- ADB over network notification -->
+ <string name="adb_net_active_notification_title">ADB over network enabled</string>
+ <!-- ADB over USB and network notification -->
+ <string name="adb_both_active_notification_title">ADB over USB &amp; network enabled</string>
+ <!-- ADB notification message-->
+ <string name="adb_active_generic_notification_message">Touch to disable debugging.</string>
+
+ <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permlab_accessThemeService">access theme service</string>
+ <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permdesc_accessThemeService">Allows an app to access the theme service. Should never be needed for normal apps.</string>
+
+ <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permlab_readThemes">read your theme info</string>
+ <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permdesc_readThemesDesc">Allows the app to read your themes and
+ determine which theme you have applied.</string>
+
+ <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permlab_writeThemes">modify your themes</string>
+ <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permdesc_writeThemesDesc">Allows the app to insert new themes and
+ modify which theme you have applied.</string>
+
+ <!-- Theme installation error notification -->
+ <string name="theme_install_error_title">Failed to install theme</string>
+ <string name="theme_install_error_message">%s failed to install</string>
+
+ <!-- stylus gestures support -->
+ <string name="stylus_app_not_installed">%s is not installed</string>
+
+ <string name="theme_reset_notification_title">Theme reset</string>
+ <string name="theme_reset_notification_body">System theme restored due to multiple app crashes.</string>
+
+ <!-- Zen mode buttons -->
+ <string name="silent_mode_priority">Priority</string>
+ <string name="silent_mode_none">None</string>
+
+ <!-- Wifi Hotspot disabled due to subscription change -->
+ <string name="subscription_change_disabled_wifi_ap">Disabled Wi-Fi hotspot due to SIM subscription change</string>
+
+ <!-- WiFi turn off notification action text -->
+ <string name="notify_turn_wifi_off_title">Turn Wi-Fi off</string>
+
+ <!-- Privacy Guard -->
+ <string name="permlab_changePrivacyGuardState">enable or disable Privacy Guard</string>
+ <string name="permdesc_changePrivacyGuardState">Allows the app to change whether another app runs with Privacy Guard. When an app is running with Privacy Guard, it will not have access to personal data such as contacts, call logs, or messages.</string>
+ <string name="privacy_guard_notification">Privacy Guard active</string>
+ <string name="privacy_guard_notification_detail"><xliff:g id="app">%1$s</xliff:g> will not be able to access personal data</string>
+ <string name="privacy_guard_dialog_title">Privacy Guard</string>
+ <string name="privacy_guard_dialog_summary"><xliff:g id="app">%1$s</xliff:g> would like to <xliff:g id="op">%2$s</xliff:g>.</string>
+
+ <!-- App ops requests -->
+ <string name="app_ops_access_camera">access the camera</string>
+ <string name="app_ops_access_location">access your location</string>
+ <string name="app_ops_access_notifications">read your notifications</string>
+ <string name="app_ops_activate_vpn">activate a VPN</string>
+ <string name="app_ops_auto_start">start at power up</string>
+ <string name="app_ops_delete_call_log">delete your call log</string>
+ <string name="app_ops_delete_contacts">delete your contacts</string>
+ <string name="app_ops_delete_mms">delete your MMS messages</string>
+ <string name="app_ops_delete_sms">delete your SMS messages</string>
+ <string name="app_ops_draw_on_top">draw windows on top</string>
+ <string name="app_ops_get_usage_stats">get app usage stats</string>
+ <string name="app_ops_keep_device_awake">keep your device awake</string>
+ <string name="app_ops_make_phone_call">make a phone call</string>
+ <string name="app_ops_modify_calendar">update your calendar</string>
+ <string name="app_ops_modify_call_log">update the call log</string>
+ <string name="app_ops_modify_clipboard">modify the clipboard</string>
+ <string name="app_ops_modify_contacts">update your contacts</string>
+ <string name="app_ops_modify_settings">update system settings</string>
+ <string name="app_ops_mute_unmute_microphone">mute/unmute the microphone</string>
+ <string name="app_ops_play_audio">play audio</string>
+ <string name="app_ops_post_notification">post a notification</string>
+ <string name="app_ops_project_media">project media</string>
+ <string name="app_ops_read_calendar">read your calendar</string>
+ <string name="app_ops_read_call_log">read the call log</string>
+ <string name="app_ops_read_clipboard">read the clipboard</string>
+ <string name="app_ops_read_contacts">read your contacts</string>
+ <string name="app_ops_read_mms">read your MMS messages</string>
+ <string name="app_ops_read_sms">read your SMS messages</string>
+ <string name="app_ops_receive_sms">receive an SMS message</string>
+ <string name="app_ops_record_audio">record audio</string>
+ <string name="app_ops_send_mms">send an MMS message</string>
+ <string name="app_ops_send_sms">send an SMS message</string>
+ <string name="app_ops_start_at_bootup">start at power up</string>
+ <string name="app_ops_toast_window">display toast messages</string>
+ <string name="app_ops_toggle_bluetooth">toggle Bluetooth</string>
+ <string name="app_ops_toggle_mobile_data">toggle mobile data</string>
+ <string name="app_ops_toggle_nfc">toggle NFC</string>
+ <string name="app_ops_toggle_wifi">toggle WiFi</string>
+ <string name="app_ops_use_alarm_volume">control alarm volume</string>
+ <string name="app_ops_use_audio_focus">control the audio focus</string>
+ <string name="app_ops_use_bluetooth_volume">control the Bluetooth volume</string>
+ <string name="app_ops_use_master_volume">control the master volume</string>
+ <string name="app_ops_use_media_buttons">use the media buttons</string>
+ <string name="app_ops_use_media_volume">control the media volume</string>
+ <string name="app_ops_use_notification_volume">control the notification volume</string>
+ <string name="app_ops_use_ring_volume">control the ringtone volume</string>
+ <string name="app_ops_use_vibrate">use haptic feedback</string>
+ <string name="app_ops_use_voice_volume">control the voice call volume</string>
+ <string name="app_ops_write_mms">write an MMS message</string>
+ <string name="app_ops_write_sms">write an SMS message</string>
+ <string name="app_ops_use_fingerprint">use fingerprint</string>
+ <string name="app_ops_add_voicemail">add a voicemail</string>
+ <string name="app_ops_read_phone_state">access phone state</string>
+ <string name="app_ops_scan_wifi">Scan WiFi Networks</string>
+ <string name="app_ops_change_wallpaper">change the wallpaper</string>
+ <string name="app_ops_assist_structure">use assist structure</string>
+ <string name="app_ops_assist_screenshot">take a screenshot</string>
+ <string name="app_ops_use_body_sensors">use body sensors</string>
+ <string name="app_ops_read_cell_broadcasts">read cell broadcasts</string>
+ <string name="app_ops_mock_location">mock your location</string>
+ <string name="app_ops_read_external_storage">read external storage</string>
+ <string name="app_ops_write_external_storage">write external storage</string>
+ <string name="app_ops_turn_on_screen">turn the screen on</string>
+ <string name="app_ops_get_accounts">get device accounts</string>
+ <string name="app_ops_wifi_change">change WiFI state</string>
+ <string name="app_ops_su">get Superuser access</string>
+
+ <!-- Notify user that they are in Lock-to-app (for devices without navbar) -->
+ <string name="lock_to_app_toast_no_navbar">To unpin this screen, touch and hold the Back button.</string>
+</resources>
diff --git a/core/res/res/values/cm_symbols.xml b/core/res/res/values/cm_symbols.xml
new file mode 100644
index 0000000..293b951
--- /dev/null
+++ b/core/res/res/values/cm_symbols.xml
@@ -0,0 +1,101 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2012-2015 The CyanogenMod Project
+ Copyright (c) 2013, The Linux Foundation. All rights reserved.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<resources>
+ <!-- We don't want to publish private symbols in android.R as part of the
+ SDK. Instead, put them here. -->
+ <private-symbols package="com.android.internal" />
+
+ <!-- Private symbols that we need to reference from framework code. See
+ frameworks/base/core/res/MakeJavaSymbols.sed for how to easily generate
+ this.
+ -->
+ <!-- External CM specific core services -->
+ <java-symbol type="array" name="config_externalCMServices" />
+
+ <java-symbol type="bool" name="config_singleStageCameraKey" />
+ <java-symbol type="integer" name="config_longPressOnMenuBehavior" />
+ <java-symbol type="integer" name="config_longPressOnAppSwitchBehavior" />
+
+ <!-- Notification and battery light -->
+ <java-symbol type="bool" name="config_intrusiveNotificationLed" />
+ <java-symbol type="bool" name="config_multiColorNotificationLed" />
+ <java-symbol type="bool" name="config_intrusiveBatteryLed" />
+ <java-symbol type="bool" name="config_multiColorBatteryLed" />
+ <java-symbol type="array" name="notification_light_package_mapping" />
+ <java-symbol type="array" name="config_notificationNoAlertsVibePattern" />
+
+ <!-- Package Manager -->
+ <java-symbol type="array" name="config_disabledComponents" />
+ <java-symbol type="array" name="config_forceEnabledComponents" />
+
+ <java-symbol type="string" name="global_action_current_user" />
+ <java-symbol type="dimen" name="global_actions_avatar_size" />
+
+ <!-- Theme install failure notification -->
+ <java-symbol type="string" name="theme_install_error_title" />
+ <java-symbol type="string" name="theme_install_error_message" />
+
+ <!-- Stylus gestures -->
+ <java-symbol type="bool" name="config_stylusGestures" />
+ <java-symbol type="string" name="stylus_app_not_installed" />
+
+ <!-- Theme reset notification -->
+ <java-symbol type="string" name="theme_reset_notification_title" />
+ <java-symbol type="string" name="theme_reset_notification_body" />
+
+ <!-- global actions (zen mode buttons) -->
+ <java-symbol type="id" name="option4" />
+
+ <!-- LED pulse -->
+ <java-symbol type="bool" name="config_ledCanPulse" />
+
+ <!-- Non-themeable packages -->
+ <java-symbol type="array" name="non_themeable_packages" />
+
+ <!-- Wifi AP Disabled from Subscription change -->
+ <java-symbol type="string" name="subscription_change_disabled_wifi_ap" />
+
+ <!-- WiFi turn off notification -->
+ <java-symbol type="string" name="notify_turn_wifi_off_title" />
+
+ <!-- Region locked prebundled packages (per mcc) -->
+ <java-symbol type="array" name="config_region_locked_packages" />
+
+ <!-- Packages in this list should be a union of all packages defined in values-mccxxx (mcc) -->
+ <java-symbol type="array" name="config_restrict_to_region_locked_devices" />
+
+ <!-- Support Samsung docks -->
+ <java-symbol type="bool" name="config_forceAnalogCarDock" />
+ <java-symbol type="bool" name="config_forceAnalogDeskDock" />
+
+ <!-- Privacy Guard -->
+ <java-symbol type="drawable" name="stat_notify_privacy_guard" />
+ <java-symbol type="string" name="privacy_guard_notification" />
+ <java-symbol type="string" name="privacy_guard_notification_detail" />
+ <java-symbol type="string" name="privacy_guard_dialog_title" />
+ <java-symbol type="string" name="privacy_guard_dialog_summary" />
+
+ <!-- Blur effects -->
+ <java-symbol type="bool" name="config_ui_blur_enabled" />
+
+ <!-- Advanced settings switch -->
+ <java-symbol type="string" name="lock_to_app_toast_no_navbar" />
+
+ <!-- PlatLogo -->
+ <java-symbol type="drawable" name="platlogo_cm" />
+</resources>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 6c96f84..8530e7e 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -30,6 +30,7 @@
<item><xliff:g id="id">cast</xliff:g></item>
<item><xliff:g id="id">hotspot</xliff:g></item>
<item><xliff:g id="id">location</xliff:g></item>
+ <item><xliff:g id="id">su</xliff:g></item>
<item><xliff:g id="id">bluetooth</xliff:g></item>
<item><xliff:g id="id">nfc</xliff:g></item>
<item><xliff:g id="id">tty</xliff:g></item>
@@ -519,6 +520,9 @@
<!-- Operating volatage for wifi radio. 0 by default-->
<integer translatable="false" name="config_wifi_operating_voltage_mv">0</integer>
+ <!-- Wifi framework supports ECBM mode -->
+ <bool translatable="false" name="config_wifi_ecbm_mode_change">true</bool>
+
<!-- Flag indicating whether the we should enable the automatic brightness in Settings.
Software implementation will be used if config_hardware_auto_brightness_available is not set -->
<bool name="config_automatic_brightness_available">false</bool>
@@ -680,6 +684,10 @@
we rely on gravity to determine the effective orientation. -->
<bool name="config_deskDockEnablesAccelerometer">true</bool>
+ <!-- Control whether a desk dock event should override the default bluetooth
+ audio routing, FORCE_BT_DESK_DOCK, with an analog dock, FORCE_ANALOG_DOCK. -->
+ <bool name="config_forceAnalogDeskDock">false</bool>
+
<!-- Car dock behavior -->
<!-- The number of degrees to rotate the display when the device is in a car dock.
@@ -698,6 +706,10 @@
<bool name="config_carDockEnablesAccelerometer">true</bool>
+ <!-- Control whether a car dock event should override the default bluetooth
+ audio routing, FORCE_BT_CAR_DOCK, with an analog dock, FORCE_ANALOG_DOCK. -->
+ <bool name="config_forceAnalogCarDock">false</bool>
+
<!-- HDMI behavior -->
<!-- The number of degrees to rotate the display when the device has HDMI connected
@@ -896,6 +908,21 @@
<!-- Is the notification LED intrusive? Used to decide if there should be a disable option -->
<bool name="config_intrusiveNotificationLed">false</bool>
+ <!-- Does the notification LED support multiple colors?
+ Used to decide if the user can change the colors -->
+ <bool name="config_multiColorNotificationLed">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>
+
+ <!-- Do the battery/notification LEDs support pulsing?
+ Used to decide if we show pulse settings -->
+ <bool name="config_ledCanPulse">true</bool>
+
<!-- Default value for LED off time when the battery is low on charge in miliseconds -->
<integer name="config_notificationsBatteryLedOff">2875</integer>
@@ -931,21 +958,84 @@
<!-- Control the behavior when the user long presses the home button.
0 - Nothing
- 1 - Recent apps view in SystemUI
- 2 - Launch assist intent
+ 1 - Menu key
+ 2 - Recent apps view in SystemUI
+ 3 - Launch assist intent
+ 4 - Voice Search
+ 5 - In-app Search
This needs to match the constants in
policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
-->
- <integer name="config_longPressOnHomeBehavior">0</integer>
+ <integer name="config_longPressOnHomeBehavior">2</integer>
<!-- Control the behavior when the user double-taps the home button.
0 - Nothing
- 1 - Recent apps view in SystemUI
+ 1 - Menu key
+ 2 - Recent apps view in SystemUI
+ 3 - Launch assist intent
+ 4 - Voice Search
+ 5 - In-app Search
This needs to match the constants in
policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
-->
<integer name="config_doubleTapOnHomeBehavior">0</integer>
+ <!-- Control the behavior when the user long presses the menu button.
+ 0 - Nothing
+ 1 - Menu key
+ 2 - Recent apps view in SystemUI
+ 3 - Launch assist intent
+ 4 - Voice Search
+ 5 - In-app Search
+ This needs to match the constants in
+ policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+ -->
+ <integer name="config_longPressOnMenuBehavior">3</integer>
+
+ <!-- Control the behavior when the user long presses the app switch button.
+ 0 - Nothing
+ 1 - Menu key
+ 2 - Recent apps view in SystemUI
+ 3 - Launch assist intent
+ 4 - Voice Search
+ 5 - In-app Search
+ This needs to match the constants in
+ services/core/java/com/android/server/policy/policy/impl/PhoneWindowManager.java
+ -->
+ <integer name="config_longPressOnAppSwitchBehavior">0</integer>
+
+ <!-- Hardware keys present on the device, stored as a bit field.
+ This integer should equal the sum of the corresponding value for each
+ of the following keys present:
+ 1 - Home
+ 2 - Back
+ 4 - Menu
+ 8 - Assistant (search)
+ 16 - App switch
+ 32 - Camera
+ 64 - Volume rocker
+ For example, a device with Home, Back and Menu keys would set this
+ config to 7. -->
+ <integer name="config_deviceHardwareKeys">79</integer>
+
+ <!-- Hardware keys present on the device with the ability to wake, stored as a bit field.
+ This integer should equal the sum of the corresponding value for each
+ of the following keys present:
+ 1 - Home
+ 2 - Back
+ 4 - Menu
+ 8 - Assistant (search)
+ 16 - App switch
+ 32 - Camera
+ 64 - Volume rocker
+ For example, a device with Home, Back and Menu keys would set this
+ config to 7. -->
+ <integer name="config_deviceHardwareWakeKeys">79</integer>
+
+ <!-- Indicates that the device has Single-stage Camera key
+ (without "Focus" state) instead of Dual-stage. -->
+ <bool name="config_singleStageCameraKey">false</bool>
+
<!-- Minimum screen brightness setting allowed by the power manager.
The user is forbidden from setting the brightness below this level. -->
<integer name="config_screenBrightnessSettingMinimum">10</integer>
@@ -1055,6 +1145,10 @@
<integer-array name="config_autoBrightnessKeyboardBacklightValues">
</integer-array>
+ <integer name="config_buttonBrightnessSettingDefault">255</integer>
+ <integer name="config_keyboardBrightnessSettingDefault">0</integer>
+ <bool name="config_deviceHasVariableButtonBrightness">false</bool>
+
<!-- Amount of time it takes for the light sensor to warm up in milliseconds.
For this time after the screen turns on, the Power Manager
will not debounce light sensor readings -->
@@ -1193,6 +1287,11 @@
-->
</string-array>
+ <!-- Component name of the combo network location provider. -->
+ <string name="config_comboNetworkLocationProvider" translatable="false">@null</string>
+ <!-- Component name of the service providing geofence API support. -->
+ <string name="config_geofenceProvider" translatable="false">@null</string>
+
<!-- Boolean indicating if current platform supports bluetooth SCO for off call
use cases -->
<bool name="config_bluetooth_sco_off_call">true</bool>
@@ -1728,6 +1827,9 @@
<!-- Configure wifi tcp buffersizes in the form:
rmem_min,rmem_def,rmem_max,wmem_min,wmem_def,wmem_max -->
<string name="config_wifi_tcp_buffers" translatable="false">524288,1048576,2097152,262144,524288,1048576</string>
+ <!-- Configuration to send sms on 1x when UE is attached to eHRPD and there is an active
+ 1xRTT voice call, irrespective of IMS registration state -->
+ <bool name="config_send_sms1x_on_voice_call">true</bool>
<!-- Whether WiFi display is supported by this device.
There are many prerequisites for this feature to work correctly.
@@ -1836,6 +1938,16 @@
<item>100</item>
</integer-array>
+ <!-- Vibrator pattern to be used as for notifications while alerts
+ are disabled (e.g. during phone calls) if enabled by the user.
+ -->
+ <integer-array name="config_notificationNoAlertsVibePattern">
+ <item>0</item>
+ <item>50</item>
+ <item>100</item>
+ <item>50</item>
+ </integer-array>
+
<!-- Flag indicating if the speed up audio on mt call code should be executed -->
<bool name="config_speed_up_audio_on_mt_calls">false</bool>
@@ -2098,6 +2210,12 @@
<bool name="config_networkSamplingWakesDevice">true</bool>
+ <!-- Path to the library that contains a device specific key handler -->
+ <string name="config_deviceKeyHandlerLib" translatable="false"></string>
+
+ <!-- Name of that key handler class -->
+ <string name="config_deviceKeyHandlerClass" translatable="false"></string>
+
<string-array translatable="false" name="config_cdma_home_system" />
<!--From SmsMessage-->
@@ -2105,9 +2223,13 @@
string that's stored in 8-bit unpacked format) characters.-->
<bool translatable="false" name="config_sms_decode_gsm_8bit_data">false</bool>
- <!-- Package name providing WebView implementation. -->
+ <!-- Package name providing default WebView implementation. -->
<string name="config_webViewPackageName" translatable="false">com.android.webview</string>
+ <!-- Package name providing alternate WebView implementation.
+ Fall back to config_webViewPackageName if not available. -->
+ <string name="config_alternateWebViewPackageName" translatable="false">com.google.android.webview</string>
+
<!-- If EMS is not supported, framework breaks down EMS into single segment SMS
and adds page info " x/y". This config is used to set which carrier doesn't
support EMS and whether page info should be added at the beginning or the end.
@@ -2122,6 +2244,9 @@
<bool name="config_auto_attach_data_on_creation">true</bool>
+ <!-- True if the gesture service should be started at system start -->
+ <bool name="config_enableGestureService">false</bool>
+
<!-- Values for GPS configuration -->
<string-array translatable="false" name="config_gpsParameters">
<item>SUPL_HOST=supl.google.com</item>
@@ -2182,6 +2307,7 @@
when evaluating RSRP for LTE antenna bar display
0. Strict threshold
1. Lenient threshold
+ 2. Custom threshold
-->
<integer name="config_LTE_RSRP_threshold_type">1</integer>
@@ -2310,6 +2436,55 @@
<string-array name="config_cell_retries_per_error_code">
</string-array>
+ <!-- Configuration to play sms ringtone during MO/MT call -->
+ <bool name="config_sms_ringtone_incall">false</bool>
+ <!-- IpReachability monitor enable/Disable -->
+ <bool translatable="false" name="config_wifi_ipreachability_monitor">false</bool>
+
+ <!-- Configuration that determines if ACTIVATE_REJECT_GGSN is to be treated as
+ a permanent error -->
+ <bool translatable="false" name="config_reject_ggsn_perm_failure">true</bool>
+ <!-- Configuration that determines if PROTOCOL_ERRORS is to be treated as a
+ permanent error -->
+ <bool translatable="false" name="config_protocol_errors_perm_failure">true</bool>
+
+ <!-- External CM Services list -->
+ <string-array name="config_externalCMServices"></string-array>
+
+ <!-- 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>
+
+ <!-- Setting to false will disable CM's IME switcher implementation for tablets -->
+ <bool name="config_show_cmIMESwitcher">true</bool>
+
+ <!-- The list of components which should be automatically disabled. -->
+ <string-array name="config_disabledComponents" translatable="false">
+ </string-array>
+
+ <!-- The list of components which should be forced to be enabled. -->
+ <string-array name="config_forceEnabledComponents" translatable="false">
+ </string-array>
+
+ <!-- Boolean to enable stk functionality on Samsung phones -->
+ <bool name="config_samsung_stk">false</bool>
+
+ <!-- If a dock provides a lid switch, that lid can be removed. This
+ setting is used to determine, whether lidOpenRotation has to be
+ applied. -->
+ <bool name="config_hasRemovableLid">false</bool>
+
+ <!-- Boolean to enable Stylus gestures -->
+ <bool name="config_stylusGestures">false</bool>
+
+ <!-- Config to enable installation of region locked packages -->
+ <string-array name="config_region_locked_packages" translatable="false">
+ </string-array>
+
+ <!-- Packages in this list should be a union of all packages defined in values-mccxxx (mcc) -->
+ <string-array name="config_restrict_to_region_locked_devices" translatable="false">
+ </string-array>
+
<!-- Set initial MaxRetry value for operators -->
<integer name="config_mdc_initial_max_retry">1</integer>
@@ -2323,6 +2498,63 @@
is non-interactive. -->
<bool name="config_cameraDoubleTapPowerGestureEnabled">true</bool>
+ <!-- Support in Surfaceflinger for blur layers.
+ NOTE: This requires additional hardware-specific code. -->
+ <bool name="config_ui_blur_enabled">false</bool>
+
+ <string-array name="origin_carrier_names">
+ <item>CHINA\u0020\u0020MOBILE</item>
+ <item>CMCC</item>
+ <item>CHN-UNICOM</item>
+ <item>China Mobile</item>
+ <item>China Unicom</item>
+ <item>China Telecom</item>
+ <item>中国移动</item>
+ <item>中国联通</item>
+ <item>中国电信</item>
+ <item>中國移動</item>
+ <item>中國聯通</item>
+ <item>中國電信</item>
+ <item>Searching for Service</item>
+ </string-array>
+
+ <string-array name="locale_carrier_names">
+ <item>China_Mobile</item>
+ <item>China_Mobile</item>
+ <item>China_Unicom</item>
+ <item>China_Mobile</item>
+ <item>China_Unicom</item>
+ <item>China_Telecom</item>
+ <item>China_Mobile</item>
+ <item>China_Unicom</item>
+ <item>China_Telecom</item>
+ <item>China_Mobile</item>
+ <item>China_Unicom</item>
+ <item>China_Telecom</item>
+ <item>roamingTextSearching</item>
+ </string-array>
+
+ <!-- monitor locale change -->
+ <bool name="config_monitor_locale_change">false</bool>
+
+ <!-- display for radio tech -->
+ <bool name="config_display_rat">false</bool>
+
+ <!-- config 2G/3G/4G RAT strings for carriers -->
+ <string name="config_rat_2g" translatable="false">2G</string>
+ <string name="config_rat_3g" translatable="false">3G</string>
+ <string name="config_rat_4g" translatable="false">4G</string>
+
+ <!-- When config_LTE_RSRP_threshold_type is set to "custom" -->
+ <integer-array name="config_LTE_RSRP_custom_levels">
+ <item>-140</item>
+ <item>-128</item>
+ <item>-118</item>
+ <item>-108</item>
+ <item>-98</item>
+ <item>-44</item>
+ </integer-array>
+
<!-- The BT name of the keyboard packaged with the device. If this is defined, SystemUI will
automatically try to pair with it when the device exits tablet mode. -->
<string translatable="false" name="config_packagedKeyboardName"></string>
diff --git a/core/res/res/values/customize.xml b/core/res/res/values/customize.xml
new file mode 100644
index 0000000..0cb79cf
--- /dev/null
+++ b/core/res/res/values/customize.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright (c) 2015, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+-->
+
+<resources>
+ <!-- Support for disabling to fetch APN from OMH card
+ for some cdma carriers -->
+ <java-symbol type="bool" name="config_fetch_apn_from_omh_card" />
+ <bool name="config_fetch_apn_from_omh_card">false</bool>
+</resources>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 8635a4f..59a73c6 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -405,4 +405,17 @@
<item type="dimen" format="integer" name="time_picker_column_start_material">0</item>
<item type="dimen" format="integer" name="time_picker_column_end_material">1</item>
+
+ <!-- EdgeGesture service: Distance a swipe must travel to be recognized as swipe. -->
+ <dimen name="edge_gesture_trigger_distance">12dp</dimen>
+
+ <!-- EdgeGesture service: This is the distance a swipe can travel orthogonally to its actual swipe
+ direction to be still recognized as swipe. -->
+ <dimen name="edge_gesture_perpendicular_distance">15dp</dimen>
+
+ <!-- EdgeGesture service: Thickness of the active trigger fields around the screen border -->
+ <dimen name="edge_gesture_trigger_thickness">12dp</dimen>
+
+ <!-- Largest size an avatar might need to be drawn in the power menu user picker -->
+ <dimen name="global_actions_avatar_size">40dp</dimen>
</resources>
diff --git a/core/res/res/values/qcom_strings.xml b/core/res/res/values/qcom_strings.xml
new file mode 100644
index 0000000..40e3563
--- /dev/null
+++ b/core/res/res/values/qcom_strings.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 2015, 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.
+*/
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- Text of the checkbox for the permission confirmation dialog to remember the user's choice. [CHAR LIMIT=40] -->
+ <string name="permission_remember_choice">Remember</string>
+ <string name="permission">Permission</string>
+</resources>
diff --git a/core/res/res/values/qcom_symbols.xml b/core/res/res/values/qcom_symbols.xml
new file mode 100755
index 0000000..c922397
--- /dev/null
+++ b/core/res/res/values/qcom_symbols.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+** Not a Contribution.
+**
+** Copyright 2015, 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.
+*/
+-->
+<resources>
+ <!-- We don't want to publish private symbols in android.R as part of the
+ SDK. Instead, put them here. -->
+ <private-symbols package="com.android.internal" />
+
+ <!-- Private symbols that we need to reference from framework code. See
+ frameworks/base/core/res/MakeJavaSymbols.sed for how to easily generate
+ this.
+ -->
+
+ <!-- app opps always-ask -->
+ <java-symbol type="id" name="permission_text" />
+ <java-symbol type="id" name="permission_remember_layout" />
+ <java-symbol type="id" name="permission_remember_choice_checkbox" />
+ <java-symbol type="id" name="permission_remember_choice_text" />
+ <java-symbol type="string" name="allow" />
+ <java-symbol type="string" name="deny" />
+ <java-symbol type="string" name="permission" />
+ <java-symbol type="layout" name="permission_confirmation_dialog" />
+ <java-symbol type="array" name="app_ops_labels" />
+
+</resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 8a9b9cf..3258ce2 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -265,6 +265,8 @@
<string name="wfc_mode_cellular_preferred_summary">Cellular preferred</string>
<!-- WFC, summary for Wi-Fi Only -->
<string name="wfc_mode_wifi_only_summary">Wi-Fi only</string>
+ <!-- Template for showing cellular network operator name while LTE calling is enabled -->
+ <string name="high_definition_tag">%s</string>
<!--
{0} is one of "bearerServiceCode*"
@@ -3147,6 +3149,9 @@
<!-- Shown when the device is tethered -->
<string name="tethered_notification_title">Tethering or hotspot active</string>
<string name="tethered_notification_message">Touch to set up.</string>
+ <string name="tethered_notification_no_device_message">No connected device</string>
+ <string name="tethered_notification_one_device_message"><xliff:g id="count">%1$s</xliff:g> connected device</string>
+ <string name="tethered_notification_multi_device_message"><xliff:g id="count">%1$s</xliff:g> connected devices</string>
<!-- Strings for possible PreferenceActivity Back/Next buttons -->
<string name="back_button_label">Back</string>
@@ -4109,4 +4114,17 @@
<item quantity="one"><xliff:g id="count" example="1">%1$d</xliff:g> selected</item>
<item quantity="other"><xliff:g id="count" example="3">%1$d</xliff:g> selected</item>
</plurals>
+
+ <!-- Used to replace a range of characters in text that is too wide
+ for the space allocated to it (three dots). -->
+ <string name="ellipsis">\u2026</string>
+
+ <!-- Used to replace a range of characters in text that is too wide
+ for the space allocated to it (two dots). -->
+ <string name="ellipsis_two_dots">\u2025</string>
+
+ <!-- Carrier Name -->
+ <string name="China_Mobile">China Mobile</string>
+ <string name="China_Unicom">China Unicom</string>
+ <string name="China_Telecom">China Telecom</string>
</resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 1bfb06c..5fa5e3f 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -220,6 +220,7 @@
<java-symbol type="id" name="profile_badge_line2" />
<java-symbol type="id" name="profile_badge_line3" />
<java-symbol type="id" name="transitionPosition" />
+ <java-symbol type="id" name="filtered_item_container" />
<java-symbol type="attr" name="actionModeShareDrawable" />
<java-symbol type="attr" name="alertDialogCenterButtons" />
@@ -292,6 +293,7 @@
<java-symbol type="bool" name="config_useFixedVolume" />
<java-symbol type="bool" name="config_forceDefaultOrientation" />
<java-symbol type="bool" name="config_wifi_batched_scan_supported" />
+ <java-symbol type="bool" name="config_wifi_ecbm_mode_change" />
<java-symbol type="bool" name="config_enableMultiUserUI"/>
<java-symbol type="bool" name="config_disableUsbPermissionDialogs"/>
<java-symbol type="bool" name="config_hasRecents" />
@@ -354,6 +356,7 @@
<java-symbol type="integer" name="config_wifi_framework_max_auth_errors_to_blacklist" />
<java-symbol type="integer" name="config_wifi_framework_network_black_list_min_time_milli" />
<java-symbol type="integer" name="config_wifi_framework_current_network_boost" />
+ <java-symbol type="bool" name="config_send_sms1x_on_voice_call" />
<java-symbol type="integer" name="config_bluetooth_max_advertisers" />
<java-symbol type="integer" name="config_bluetooth_max_scan_filters" />
<java-symbol type="integer" name="config_burnInProtectionMinHorizontalOffset" />
@@ -820,8 +823,11 @@
<java-symbol type="string" name="reboot_to_update_reboot" />
<java-symbol type="string" name="reboot_to_reset_title" />
<java-symbol type="string" name="reboot_to_reset_message" />
+ <java-symbol type="string" name="reboot_confirm" />
<java-symbol type="string" name="reboot_safemode_confirm" />
<java-symbol type="string" name="reboot_safemode_title" />
+ <java-symbol type="string" name="reboot_title" />
+ <java-symbol type="string" name="reboot_progress" />
<java-symbol type="string" name="relationTypeAssistant" />
<java-symbol type="string" name="relationTypeBrother" />
<java-symbol type="string" name="relationTypeChild" />
@@ -1101,6 +1107,7 @@
<java-symbol type="string" name="lockscreen_transport_pause_description" />
<java-symbol type="string" name="config_ethernet_tcp_buffers" />
<java-symbol type="string" name="config_wifi_tcp_buffers" />
+ <java-symbol type="string" name="high_definition_tag" />
<java-symbol type="plurals" name="duration_hours" />
<java-symbol type="plurals" name="duration_minutes" />
@@ -1457,6 +1464,8 @@
<java-symbol type="array" name="config_safeModeEnabledVibePattern" />
<java-symbol type="array" name="config_contextClickVibePattern" />
<java-symbol type="array" name="config_virtualKeyVibePattern" />
+ <java-symbol type="array" name="shutdown_reboot_options" />
+ <java-symbol type="array" name="shutdown_reboot_actions" />
<java-symbol type="attr" name="actionModePopupWindowStyle" />
<java-symbol type="attr" name="dialogCustomTitleDecorLayout" />
<java-symbol type="attr" name="dialogTitleDecorLayout" />
@@ -1485,6 +1494,7 @@
<java-symbol type="drawable" name="ic_jog_dial_vibrate_on" />
<java-symbol type="drawable" name="ic_lock_airplane_mode" />
<java-symbol type="drawable" name="ic_lock_airplane_mode_off" />
+ <java-symbol type="drawable" name="ic_lock_power_reboot" />
<java-symbol type="drawable" name="ic_menu_cc" />
<java-symbol type="drawable" name="jog_tab_bar_left_unlock" />
<java-symbol type="drawable" name="jog_tab_bar_right_sound_off" />
@@ -1528,6 +1538,8 @@
<java-symbol type="integer" name="config_carDockRotation" />
<java-symbol type="integer" name="config_defaultUiModeType" />
<java-symbol type="integer" name="config_deskDockRotation" />
+ <java-symbol type="integer" name="config_deviceHardwareKeys" />
+ <java-symbol type="integer" name="config_deviceHardwareWakeKeys" />
<java-symbol type="integer" name="config_doubleTapOnHomeBehavior" />
<java-symbol type="integer" name="config_lidKeyboardAccessibility" />
<java-symbol type="integer" name="config_lidNavigationAccessibility" />
@@ -1554,6 +1566,7 @@
<java-symbol type="string" name="config_orientationSensorType" />
<java-symbol type="string" name="faceunlock_multiple_failures" />
<java-symbol type="string" name="global_action_power_off" />
+ <java-symbol type="string" name="global_action_reboot" />
<java-symbol type="string" name="global_actions_airplane_mode_off_status" />
<java-symbol type="string" name="global_actions_airplane_mode_on_status" />
<java-symbol type="string" name="global_actions_toggle_airplane_mode" />
@@ -1712,6 +1725,9 @@
<java-symbol type="integer" name="config_screenBrightnessDark" />
<java-symbol type="integer" name="config_screenBrightnessDim" />
<java-symbol type="integer" name="config_screenBrightnessDoze" />
+ <java-symbol type="integer" name="config_buttonBrightnessSettingDefault" />
+ <java-symbol type="integer" name="config_keyboardBrightnessSettingDefault" />
+ <java-symbol type="bool" name="config_deviceHasVariableButtonBrightness" />
<java-symbol type="integer" name="config_shutdownBatteryTemperature" />
<java-symbol type="integer" name="config_undockedHdmiRotation" />
<java-symbol type="integer" name="config_virtualKeyQuietTimeMillis" />
@@ -1746,6 +1762,8 @@
<java-symbol type="string" name="config_geocoderProviderPackageName" />
<java-symbol type="string" name="config_geofenceProviderPackageName" />
<java-symbol type="string" name="config_networkLocationProviderPackageName" />
+ <java-symbol type="string" name="config_comboNetworkLocationProvider" />
+ <java-symbol type="string" name="config_geofenceProvider" />
<java-symbol type="string" name="config_wimaxManagerClassname" />
<java-symbol type="string" name="config_wimaxNativeLibLocation" />
<java-symbol type="string" name="config_wimaxServiceClassname" />
@@ -1796,6 +1814,9 @@
<java-symbol type="string" name="smv_application" />
<java-symbol type="string" name="smv_process" />
<java-symbol type="string" name="tethered_notification_message" />
+ <java-symbol type="string" name="tethered_notification_no_device_message" />
+ <java-symbol type="string" name="tethered_notification_one_device_message" />
+ <java-symbol type="string" name="tethered_notification_multi_device_message" />
<java-symbol type="string" name="tethered_notification_title" />
<java-symbol type="string" name="usb_accessory_notification_title" />
<java-symbol type="string" name="usb_mtp_notification_title" />
@@ -1881,6 +1902,7 @@
<java-symbol type="anim" name="lock_screen_behind_enter_fade_in" />
<java-symbol type="anim" name="lock_screen_wallpaper_exit" />
<java-symbol type="anim" name="launch_task_behind_source" />
+ <java-symbol type="anim" name="lock_screen_wallpaper_exit_noop" />
<java-symbol type="bool" name="config_alwaysUseCdmaRssi" />
<java-symbol type="dimen" name="status_bar_icon_size" />
@@ -2020,6 +2042,7 @@
<java-symbol type="string" name="websearch" />
<java-symbol type="drawable" name="ic_media_video_poster" />
<java-symbol type="string" name="config_webViewPackageName" />
+ <java-symbol type="string" name="config_alternateWebViewPackageName" />
<!-- From SubtitleView -->
<java-symbol type="dimen" name="subtitle_corner_radius" />
@@ -2034,6 +2057,10 @@
<java-symbol type="layout" name="year_label_text_view" />
<java-symbol type="layout" name="date_picker_material" />
+ <!-- Config.xml entries -->
+ <java-symbol type="string" name="config_deviceKeyHandlerLib" />
+ <java-symbol type="string" name="config_deviceKeyHandlerClass" />
+
<java-symbol type="id" name="time_header" />
<java-symbol type="id" name="hours" />
<java-symbol type="id" name="minutes" />
@@ -2207,6 +2234,7 @@
<!-- From SignalStrength -->
<java-symbol type="integer" name="config_LTE_RSRP_threshold_type" />
+ <java-symbol type="array" name="config_LTE_RSRP_custom_levels" />
<java-symbol type="string" name="android_system_label" />
<java-symbol type="string" name="system_error_wipe_data" />
@@ -2329,7 +2357,70 @@
<java-symbol type="string" name="config_cameraLaunchGestureSensorStringType" />
<java-symbol type="bool" name="config_cameraDoubleTapPowerGestureEnabled" />
+ <!-- config softap extention feature -->
+ <java-symbol type="bool" name="config_softap_extention" />
+
+ <!-- for wifi auto connection -->
+ <java-symbol type="bool" name="wifi_autocon" />
+ <!-- Configuration to play sms ringtone during MO/MT call -->
+ <java-symbol type="bool" name="config_sms_ringtone_incall" />
+
+ <!-- IpReachability Monitor -->
+ <java-symbol type="bool" name="config_wifi_ipreachability_monitor" />
+
+ <!-- Data Connectivity Error Configurations -->
+ <java-symbol type="bool" name="config_reject_ggsn_perm_failure" />
+ <java-symbol type="bool" name="config_protocol_errors_perm_failure" />
+
+ <!-- Gesture Sensor -->
+ <java-symbol type="bool" name="config_enableGestureService" />
+
+ <!-- Config.xml entries -->
+ <java-symbol type="bool" name="config_show_cmIMESwitcher"/>
+ <java-symbol type="bool" name="config_samsung_stk" />
+ <java-symbol type="bool" name="config_hasRemovableLid" />
+
+ <!-- Power menu -->
+ <java-symbol type="drawable" name="ic_lock_screenshot" />
+ <java-symbol type="string" name="global_action_screenshot" />
+ <java-symbol type="drawable" name="ic_lock_settings" />
+ <java-symbol type="drawable" name="ic_lock_user" />
+
+ <!-- EdgeGesture service -->
+ <java-symbol type="dimen" name="edge_gesture_trigger_distance" />
+ <java-symbol type="dimen" name="edge_gesture_perpendicular_distance" />
+ <java-symbol type="dimen" name="edge_gesture_trigger_thickness" />
+
+ <!-- Developer settings - Kill app back press -->
+ <java-symbol type="string" name="app_killed_message" />
+
+ <!-- Config.xml entries -->
+ <java-symbol type="integer" name="config_backKillTimeout" />
+
+ <!-- ADB notification -->
+ <java-symbol type="string" name="adb_net_active_notification_title" />
+ <java-symbol type="string" name="adb_both_active_notification_title" />
+ <java-symbol type="string" name="adb_active_generic_notification_message" />
+
+ <!-- Last app switch animations -->
+ <java-symbol type="anim" name="last_app_in" />
+ <java-symbol type="anim" name="last_app_out" />
+
<java-symbol type="drawable" name="platlogo_m" />
+ <!-- config 2G/3G/4G RAT strings for carriers -->
+ <java-symbol type="string" name="config_rat_2g" />
+ <java-symbol type="string" name="config_rat_3g" />
+ <java-symbol type="string" name="config_rat_4g" />
+
+ <!-- monitor locale change -->
+ <java-symbol type="bool" name="config_monitor_locale_change" />
+
+ <!-- display for radio tech -->
+ <java-symbol type="bool" name="config_display_rat" />
+
+ <java-symbol type="array" name="origin_carrier_names" />
+ <java-symbol type="array" name="locale_carrier_names" />
+
<java-symbol type="string" name="config_packagedKeyboardName" />
</resources>
diff --git a/core/res/res/xml/sms_short_codes.xml b/core/res/res/xml/sms_short_codes.xml
index 5783a49..0baeaff 100644
--- a/core/res/res/xml/sms_short_codes.xml
+++ b/core/res/res/xml/sms_short_codes.xml
@@ -111,6 +111,9 @@
http://clients.txtnation.com/entries/209633-hungary-premium-sms-short-code-regulations -->
<shortcode country="hu" pattern="[01](?:\\d{3}|\\d{9})" premium="0691227910|1784" free="116\\d{3}" />
+ <!-- Indonesia: 2-4 digit codes with a whitelist of free codes -->
+ <shortcode country="id" pattern="\\d{2,4}" free="11|123|1233|1234|2233|228|261|2619|355|388|4444|551|807|808|888|995|999" />
+
<!-- Ireland: 5 digits, 5xxxx (50xxx=free, 5[12]xxx=standard), plus EU:
http://www.comreg.ie/_fileupload/publications/ComReg1117.pdf -->
<shortcode country="ie" pattern="\\d{5}" premium="5[3-9]\\d{3}" free="50\\d{3}|116\\d{3}" standard="5[12]\\d{3}" />
diff --git a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
index baa772e..a4214cf 100644
--- a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
+++ b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
@@ -3324,11 +3324,6 @@ public class PackageManagerTests extends AndroidTestCase {
}
installFromRawResource("keysetApi.apk", R.raw.keyset_splat_api,
0, false, false, -1, PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
- try {
- ks = pm.getKeySetByAlias(otherPkgName, "A");
- assertTrue(false); // should have thrown
- } catch (SecurityException e) {
- }
cleanUpInstall(otherPkgName);
ks = pm.getKeySetByAlias(mPkgName, "A");
assertNotNull(ks);
diff --git a/data/sounds/AllAudio.mk b/data/sounds/AllAudio.mk
index f6d8ee9..0457c4a 100644
--- a/data/sounds/AllAudio.mk
+++ b/data/sounds/AllAudio.mk
@@ -19,24 +19,18 @@ PRODUCT_COPY_FILES += \
$(LOCAL_PATH)/Alarm_Beep_02.ogg:system/media/audio/alarms/Alarm_Beep_02.ogg \
$(LOCAL_PATH)/Alarm_Beep_03.ogg:system/media/audio/alarms/Alarm_Beep_03.ogg \
$(LOCAL_PATH)/Alarm_Buzzer.ogg:system/media/audio/alarms/Alarm_Buzzer.ogg \
- $(LOCAL_PATH)/Alarm_Classic.ogg:system/media/audio/alarms/Alarm_Classic.ogg \
$(LOCAL_PATH)/Alarm_Rooster_02.ogg:system/media/audio/alarms/Alarm_Rooster_02.ogg \
$(LOCAL_PATH)/alarms/ogg/Argon.ogg:system/media/audio/alarms/Argon.ogg \
$(LOCAL_PATH)/alarms/ogg/Barium.ogg:system/media/audio/alarms/Barium.ogg \
$(LOCAL_PATH)/alarms/ogg/Carbon.ogg:system/media/audio/alarms/Carbon.ogg \
$(LOCAL_PATH)/alarms/ogg/Cesium.ogg:system/media/audio/alarms/Cesium.ogg \
- $(LOCAL_PATH)/alarms/ogg/Fermium.ogg:system/media/audio/alarms/Fermium.ogg \
- $(LOCAL_PATH)/alarms/ogg/Hassium.ogg:system/media/audio/alarms/Hassium.ogg \
$(LOCAL_PATH)/alarms/ogg/Helium.ogg:system/media/audio/alarms/Helium.ogg \
$(LOCAL_PATH)/alarms/ogg/Krypton.ogg:system/media/audio/alarms/Krypton.ogg \
$(LOCAL_PATH)/alarms/ogg/Neon.ogg:system/media/audio/alarms/Neon.ogg \
$(LOCAL_PATH)/alarms/ogg/Neptunium.ogg:system/media/audio/alarms/Neptunium.ogg \
- $(LOCAL_PATH)/alarms/ogg/Nobelium.ogg:system/media/audio/alarms/Nobelium.ogg \
$(LOCAL_PATH)/alarms/ogg/Osmium.ogg:system/media/audio/alarms/Osmium.ogg \
$(LOCAL_PATH)/alarms/ogg/Oxygen.ogg:system/media/audio/alarms/Oxygen.ogg \
$(LOCAL_PATH)/alarms/ogg/Platinum.ogg:system/media/audio/alarms/Platinum.ogg \
- $(LOCAL_PATH)/alarms/ogg/Plutonium.ogg:system/media/audio/alarms/Plutonium.ogg \
- $(LOCAL_PATH)/alarms/ogg/Promethium.ogg:system/media/audio/alarms/Promethium.ogg \
$(LOCAL_PATH)/alarms/ogg/Scandium.ogg:system/media/audio/alarms/Scandium.ogg \
$(LOCAL_PATH)/notifications/ogg/Adara.ogg:system/media/audio/notifications/Adara.ogg \
$(LOCAL_PATH)/notifications/Aldebaran.ogg:system/media/audio/notifications/Aldebaran.ogg \
@@ -97,7 +91,6 @@ PRODUCT_COPY_FILES += \
$(LOCAL_PATH)/notifications/ogg/Syrma.ogg:system/media/audio/notifications/Syrma.ogg \
$(LOCAL_PATH)/notifications/TaDa.ogg:system/media/audio/notifications/TaDa.ogg \
$(LOCAL_PATH)/notifications/ogg/Talitha.ogg:system/media/audio/notifications/Talitha.ogg \
- $(LOCAL_PATH)/notifications/ogg/Tejat.ogg:system/media/audio/notifications/Tejat.ogg \
$(LOCAL_PATH)/notifications/ogg/Thallium.ogg:system/media/audio/notifications/Thallium.ogg \
$(LOCAL_PATH)/notifications/Tinkerbell.ogg:system/media/audio/notifications/Tinkerbell.ogg \
$(LOCAL_PATH)/notifications/ogg/Upsilon.ogg:system/media/audio/notifications/Upsilon.ogg \
@@ -113,11 +106,119 @@ PRODUCT_COPY_FILES += \
$(LOCAL_PATH)/notifications/sirius.ogg:system/media/audio/notifications/sirius.ogg \
$(LOCAL_PATH)/notifications/tweeters.ogg:system/media/audio/notifications/tweeters.ogg \
$(LOCAL_PATH)/notifications/vega.ogg:system/media/audio/notifications/vega.ogg \
- $(LOCAL_PATH)/ringtones/ANDROMEDA.ogg:system/media/audio/ringtones/ANDROMEDA.ogg \
+
+ifeq ($(TARGET_NEEDS_BOOSTED_SOUNDS),true)
+PRODUCT_COPY_FILES += \
+ $(LOCAL_PATH)/ringtones/boosted/Andromeda.ogg:system/media/audio/ringtones/Andromeda.ogg \
+ $(LOCAL_PATH)/ringtones/boosted/Aquila.ogg:system/media/audio/ringtones/Aquila.ogg \
+ $(LOCAL_PATH)/ringtones/boosted/ArgoNavis.ogg:system/media/audio/ringtones/ArgoNavis.ogg \
+ $(LOCAL_PATH)/ringtones/boosted/BOOTES.ogg:system/media/audio/ringtones/BOOTES.ogg \
+ $(LOCAL_PATH)/ringtones/boosted/Backroad.ogg:system/media/audio/ringtones/Backroad.ogg \
+ $(LOCAL_PATH)/ringtones/boosted/BeatPlucker.ogg:system/media/audio/ringtones/BeatPlucker.ogg \
+ $(LOCAL_PATH)/ringtones/boosted/BentleyDubs.ogg:system/media/audio/ringtones/BentleyDubs.ogg \
+ $(LOCAL_PATH)/ringtones/boosted/Big_Easy.ogg:system/media/audio/ringtones/Big_Easy.ogg \
+ $(LOCAL_PATH)/ringtones/boosted/BirdLoop.ogg:system/media/audio/ringtones/BirdLoop.ogg \
+ $(LOCAL_PATH)/ringtones/boosted/Bollywood.ogg:system/media/audio/ringtones/Bollywood.ogg \
+ $(LOCAL_PATH)/ringtones/boosted/BussaMove.ogg:system/media/audio/ringtones/BussaMove.ogg \
+ $(LOCAL_PATH)/ringtones/boosted/CASSIOPEIA.ogg:system/media/audio/ringtones/CASSIOPEIA.ogg \
+ $(LOCAL_PATH)/ringtones/boosted/Cairo.ogg:system/media/audio/ringtones/Cairo.ogg \
+ $(LOCAL_PATH)/ringtones/boosted/Calypso_Steel.ogg:system/media/audio/ringtones/Calypso_Steel.ogg \
+ $(LOCAL_PATH)/ringtones/boosted/CanisMajor.ogg:system/media/audio/ringtones/CanisMajor.ogg \
+ $(LOCAL_PATH)/ringtones/boosted/CaribbeanIce.ogg:system/media/audio/ringtones/CaribbeanIce.ogg \
+ $(LOCAL_PATH)/ringtones/boosted/Carina.ogg:system/media/audio/ringtones/Carina.ogg \
+ $(LOCAL_PATH)/ringtones/boosted/Centaurus.ogg:system/media/audio/ringtones/Centaurus.ogg \
+ $(LOCAL_PATH)/ringtones/boosted/Champagne_Edition.ogg:system/media/audio/ringtones/Champagne_Edition.ogg \
+ $(LOCAL_PATH)/ringtones/boosted/Club_Cubano.ogg:system/media/audio/ringtones/Club_Cubano.ogg \
+ $(LOCAL_PATH)/ringtones/boosted/CrayonRock.ogg:system/media/audio/ringtones/CrayonRock.ogg \
+ $(LOCAL_PATH)/ringtones/boosted/CrazyDream.ogg:system/media/audio/ringtones/CrazyDream.ogg \
+ $(LOCAL_PATH)/ringtones/boosted/CurveBall.ogg:system/media/audio/ringtones/CurveBall.ogg \
+ $(LOCAL_PATH)/ringtones/boosted/Cygnus.ogg:system/media/audio/ringtones/Cygnus.ogg \
+ $(LOCAL_PATH)/ringtones/boosted/DancinFool.ogg:system/media/audio/ringtones/DancinFool.ogg \
+ $(LOCAL_PATH)/ringtones/boosted/DonMessWivIt.ogg:system/media/audio/ringtones/DonMessWivIt.ogg \
+ $(LOCAL_PATH)/ringtones/boosted/Draco.ogg:system/media/audio/ringtones/Draco.ogg \
+ $(LOCAL_PATH)/ringtones/boosted/DreamTheme.ogg:system/media/audio/ringtones/DreamTheme.ogg \
+ $(LOCAL_PATH)/ringtones/boosted/Eastern_Sky.ogg:system/media/audio/ringtones/Eastern_Sky.ogg \
+ $(LOCAL_PATH)/ringtones/boosted/Enter_the_Nexus.ogg:system/media/audio/ringtones/Enter_the_Nexus.ogg \
+ $(LOCAL_PATH)/ringtones/boosted/Eridani.ogg:system/media/audio/ringtones/Eridani.ogg \
+ $(LOCAL_PATH)/ringtones/boosted/EtherShake.ogg:system/media/audio/ringtones/EtherShake.ogg \
+ $(LOCAL_PATH)/ringtones/boosted/FreeFlight.ogg:system/media/audio/ringtones/FreeFlight.ogg \
+ $(LOCAL_PATH)/ringtones/boosted/FriendlyGhost.ogg:system/media/audio/ringtones/FriendlyGhost.ogg \
+ $(LOCAL_PATH)/ringtones/boosted/Funk_Yall.ogg:system/media/audio/ringtones/Funk_Yall.ogg \
+ $(LOCAL_PATH)/ringtones/boosted/GameOverGuitar.ogg:system/media/audio/ringtones/GameOverGuitar.ogg \
+ $(LOCAL_PATH)/ringtones/boosted/Gimme_Mo_Town.ogg:system/media/audio/ringtones/Gimme_Mo_Town.ogg \
+ $(LOCAL_PATH)/ringtones/boosted/Girtab.ogg:system/media/audio/ringtones/Girtab.ogg \
+ $(LOCAL_PATH)/ringtones/boosted/Glacial_Groove.ogg:system/media/audio/ringtones/Glacial_Groove.ogg \
+ $(LOCAL_PATH)/ringtones/boosted/Growl.ogg:system/media/audio/ringtones/Growl.ogg \
+ $(LOCAL_PATH)/ringtones/boosted/HalfwayHome.ogg:system/media/audio/ringtones/HalfwayHome.ogg \
+ $(LOCAL_PATH)/ringtones/boosted/Hydra.ogg:system/media/audio/ringtones/Hydra.ogg \
+ $(LOCAL_PATH)/ringtones/boosted/InsertCoin.ogg:system/media/audio/ringtones/InsertCoin.ogg \
+ $(LOCAL_PATH)/ringtones/boosted/Kuma.ogg:system/media/audio/ringtones/Kuma.ogg \
+ $(LOCAL_PATH)/ringtones/boosted/LoopyLounge.ogg:system/media/audio/ringtones/LoopyLounge.ogg \
+ $(LOCAL_PATH)/ringtones/boosted/LoveFlute.ogg:system/media/audio/ringtones/LoveFlute.ogg \
+ $(LOCAL_PATH)/ringtones/boosted/Lyra.ogg:system/media/audio/ringtones/Lyra.ogg \
+ $(LOCAL_PATH)/ringtones/boosted/Machina.ogg:system/media/audio/ringtones/Machina.ogg \
+ $(LOCAL_PATH)/ringtones/boosted/MidEvilJaunt.ogg:system/media/audio/ringtones/MidEvilJaunt.ogg \
+ $(LOCAL_PATH)/ringtones/boosted/MildlyAlarming.ogg:system/media/audio/ringtones/MildlyAlarming.ogg \
+ $(LOCAL_PATH)/ringtones/boosted/Nairobi.ogg:system/media/audio/ringtones/Nairobi.ogg \
+ $(LOCAL_PATH)/ringtones/boosted/Nassau.ogg:system/media/audio/ringtones/Nassau.ogg \
+ $(LOCAL_PATH)/ringtones/boosted/NewPlayer.ogg:system/media/audio/ringtones/NewPlayer.ogg \
+ $(LOCAL_PATH)/ringtones/boosted/No_Limits.ogg:system/media/audio/ringtones/No_Limits.ogg \
+ $(LOCAL_PATH)/ringtones/boosted/Noises2.ogg:system/media/audio/ringtones/Noises2.ogg \
+ $(LOCAL_PATH)/ringtones/boosted/Noises3.ogg:system/media/audio/ringtones/Noises3.ogg \
+ $(LOCAL_PATH)/ringtones/boosted/OrganDub.ogg:system/media/audio/ringtones/OrganDub.ogg \
+ $(LOCAL_PATH)/ringtones/boosted/Orion.ogg:system/media/audio/ringtones/Orion.ogg \
+ $(LOCAL_PATH)/ringtones/boosted/Paradise_Island.ogg:system/media/audio/ringtones/Paradise_Island.ogg \
+ $(LOCAL_PATH)/ringtones/boosted/Pegasus.ogg:system/media/audio/ringtones/Pegasus.ogg \
+ $(LOCAL_PATH)/ringtones/boosted/Perseus.ogg:system/media/audio/ringtones/Perseus.ogg \
+ $(LOCAL_PATH)/ringtones/boosted/Playa.ogg:system/media/audio/ringtones/Playa.ogg \
+ $(LOCAL_PATH)/ringtones/boosted/Rasalas.ogg:system/media/audio/ringtones/Rasalas.ogg \
+ $(LOCAL_PATH)/ringtones/boosted/Revelation.ogg:system/media/audio/ringtones/Revelation.ogg \
+ $(LOCAL_PATH)/ringtones/boosted/Rigel.ogg:system/media/audio/ringtones/Rigel.ogg \
+ $(LOCAL_PATH)/ringtones/boosted/Ring_Classic_02.ogg:system/media/audio/ringtones/Ring_Classic_02.ogg \
+ $(LOCAL_PATH)/ringtones/boosted/Ring_Digital_02.ogg:system/media/audio/ringtones/Ring_Digital_02.ogg \
+ $(LOCAL_PATH)/ringtones/boosted/Ring_Synth_02.ogg:system/media/audio/ringtones/Ring_Synth_02.ogg \
+ $(LOCAL_PATH)/ringtones/boosted/Ring_Synth_04.ogg:system/media/audio/ringtones/Ring_Synth_04.ogg \
+ $(LOCAL_PATH)/ringtones/boosted/Road_Trip.ogg:system/media/audio/ringtones/Road_Trip.ogg \
+ $(LOCAL_PATH)/ringtones/boosted/RomancingTheTone.ogg:system/media/audio/ringtones/RomancingTheTone.ogg \
+ $(LOCAL_PATH)/ringtones/boosted/Safari.ogg:system/media/audio/ringtones/Safari.ogg \
+ $(LOCAL_PATH)/ringtones/boosted/Savannah.ogg:system/media/audio/ringtones/Savannah.ogg \
+ $(LOCAL_PATH)/ringtones/boosted/Scarabaeus.ogg:system/media/audio/ringtones/Scarabaeus.ogg \
+ $(LOCAL_PATH)/ringtones/boosted/Sceptrum.ogg:system/media/audio/ringtones/Sceptrum.ogg \
+ $(LOCAL_PATH)/ringtones/boosted/Seville.ogg:system/media/audio/ringtones/Seville.ogg \
+ $(LOCAL_PATH)/ringtones/boosted/Shes_All_That.ogg:system/media/audio/ringtones/Shes_All_That.ogg \
+ $(LOCAL_PATH)/ringtones/boosted/SilkyWay.ogg:system/media/audio/ringtones/SilkyWay.ogg \
+ $(LOCAL_PATH)/ringtones/boosted/SitarVsSitar.ogg:system/media/audio/ringtones/SitarVsSitar.ogg \
+ $(LOCAL_PATH)/ringtones/boosted/Solarium.ogg:system/media/audio/ringtones/Solarium.ogg \
+ $(LOCAL_PATH)/ringtones/boosted/SpringyJalopy.ogg:system/media/audio/ringtones/SpringyJalopy.ogg \
+ $(LOCAL_PATH)/ringtones/boosted/Steppin_Out.ogg:system/media/audio/ringtones/Steppin_Out.ogg \
+ $(LOCAL_PATH)/ringtones/boosted/Terminated.ogg:system/media/audio/ringtones/Terminated.ogg \
+ $(LOCAL_PATH)/ringtones/boosted/Testudo.ogg:system/media/audio/ringtones/Testudo.ogg \
+ $(LOCAL_PATH)/ringtones/boosted/Themos.ogg:system/media/audio/ringtones/Themos.ogg \
+ $(LOCAL_PATH)/ringtones/boosted/Third_Eye.ogg:system/media/audio/ringtones/Third_Eye.ogg \
+ $(LOCAL_PATH)/ringtones/boosted/Thunderfoot.ogg:system/media/audio/ringtones/Thunderfoot.ogg \
+ $(LOCAL_PATH)/ringtones/boosted/TwirlAway.ogg:system/media/audio/ringtones/TwirlAway.ogg \
+ $(LOCAL_PATH)/ringtones/boosted/UrsaMinor.ogg:system/media/audio/ringtones/UrsaMinor.ogg \
+ $(LOCAL_PATH)/ringtones/boosted/VeryAlarmed.ogg:system/media/audio/ringtones/VeryAlarmed.ogg \
+ $(LOCAL_PATH)/ringtones/boosted/Vespa.ogg:system/media/audio/ringtones/Vespa.ogg \
+ $(LOCAL_PATH)/ringtones/boosted/World.ogg:system/media/audio/ringtones/World.ogg \
+ $(LOCAL_PATH)/ringtones/boosted/Zeta.ogg:system/media/audio/ringtones/Zeta.ogg \
+ $(LOCAL_PATH)/ringtones/boosted/Atria.ogg:system/media/audio/ringtones/Atria.ogg \
+ $(LOCAL_PATH)/ringtones/boosted/Callisto.ogg:system/media/audio/ringtones/Callisto.ogg \
+ $(LOCAL_PATH)/ringtones/boosted/Dione.ogg:system/media/audio/ringtones/Dione.ogg \
+ $(LOCAL_PATH)/ringtones/boosted/Ganymede.ogg:system/media/audio/ringtones/Ganymede.ogg \
+ $(LOCAL_PATH)/ringtones/boosted/Luna.ogg:system/media/audio/ringtones/Luna.ogg \
+ $(LOCAL_PATH)/ringtones/boosted/Oberon.ogg:system/media/audio/ringtones/Oberon.ogg \
+ $(LOCAL_PATH)/ringtones/boosted/Phobos.ogg:system/media/audio/ringtones/Phobos.ogg \
+ $(LOCAL_PATH)/ringtones/boosted/Pyxis.ogg:system/media/audio/ringtones/Pyxis.ogg \
+ $(LOCAL_PATH)/ringtones/boosted/Sedna.ogg:system/media/audio/ringtones/Sedna.ogg \
+ $(LOCAL_PATH)/ringtones/boosted/Titania.ogg:system/media/audio/ringtones/Titania.ogg \
+ $(LOCAL_PATH)/ringtones/boosted/Triton.ogg:system/media/audio/ringtones/Triton.ogg \
+ $(LOCAL_PATH)/ringtones/boosted/Umbriel.ogg:system/media/audio/ringtones/Umbriel.ogg
+else
+PRODUCT_COPY_FILES += \
$(LOCAL_PATH)/ringtones/ogg/Andromeda.ogg:system/media/audio/ringtones/Andromeda.ogg \
$(LOCAL_PATH)/ringtones/ogg/Aquila.ogg:system/media/audio/ringtones/Aquila.ogg \
$(LOCAL_PATH)/ringtones/ogg/ArgoNavis.ogg:system/media/audio/ringtones/ArgoNavis.ogg \
- $(LOCAL_PATH)/ringtones/ogg/Atria.ogg:system/media/audio/ringtones/Atria.ogg \
$(LOCAL_PATH)/ringtones/BOOTES.ogg:system/media/audio/ringtones/BOOTES.ogg \
$(LOCAL_PATH)/newwavelabs/Backroad.ogg:system/media/audio/ringtones/Backroad.ogg \
$(LOCAL_PATH)/newwavelabs/BeatPlucker.ogg:system/media/audio/ringtones/BeatPlucker.ogg \
@@ -126,7 +227,6 @@ PRODUCT_COPY_FILES += \
$(LOCAL_PATH)/newwavelabs/BirdLoop.ogg:system/media/audio/ringtones/BirdLoop.ogg \
$(LOCAL_PATH)/newwavelabs/Bollywood.ogg:system/media/audio/ringtones/Bollywood.ogg \
$(LOCAL_PATH)/newwavelabs/BussaMove.ogg:system/media/audio/ringtones/BussaMove.ogg \
- $(LOCAL_PATH)/ringtones/CANISMAJOR.ogg:system/media/audio/ringtones/CANISMAJOR.ogg \
$(LOCAL_PATH)/ringtones/CASSIOPEIA.ogg:system/media/audio/ringtones/CASSIOPEIA.ogg \
$(LOCAL_PATH)/newwavelabs/Cairo.ogg:system/media/audio/ringtones/Cairo.ogg \
$(LOCAL_PATH)/newwavelabs/Calypso_Steel.ogg:system/media/audio/ringtones/Calypso_Steel.ogg \
@@ -176,12 +276,10 @@ PRODUCT_COPY_FILES += \
$(LOCAL_PATH)/newwavelabs/Noises3.ogg:system/media/audio/ringtones/Noises3.ogg \
$(LOCAL_PATH)/newwavelabs/OrganDub.ogg:system/media/audio/ringtones/OrganDub.ogg \
$(LOCAL_PATH)/ringtones/ogg/Orion.ogg:system/media/audio/ringtones/Orion.ogg \
- $(LOCAL_PATH)/ringtones/PERSEUS.ogg:system/media/audio/ringtones/PERSEUS.ogg \
$(LOCAL_PATH)/newwavelabs/Paradise_Island.ogg:system/media/audio/ringtones/Paradise_Island.ogg \
$(LOCAL_PATH)/ringtones/ogg/Pegasus.ogg:system/media/audio/ringtones/Pegasus.ogg \
$(LOCAL_PATH)/ringtones/ogg/Perseus.ogg:system/media/audio/ringtones/Perseus.ogg \
$(LOCAL_PATH)/newwavelabs/Playa.ogg:system/media/audio/ringtones/Playa.ogg \
- $(LOCAL_PATH)/ringtones/ogg/Pyxis.ogg:system/media/audio/ringtones/Pyxis.ogg \
$(LOCAL_PATH)/ringtones/ogg/Rasalas.ogg:system/media/audio/ringtones/Rasalas.ogg \
$(LOCAL_PATH)/newwavelabs/Revelation.ogg:system/media/audio/ringtones/Revelation.ogg \
$(LOCAL_PATH)/ringtones/ogg/Rigel.ogg:system/media/audio/ringtones/Rigel.ogg \
@@ -208,13 +306,26 @@ PRODUCT_COPY_FILES += \
$(LOCAL_PATH)/newwavelabs/Third_Eye.ogg:system/media/audio/ringtones/Third_Eye.ogg \
$(LOCAL_PATH)/newwavelabs/Thunderfoot.ogg:system/media/audio/ringtones/Thunderfoot.ogg \
$(LOCAL_PATH)/newwavelabs/TwirlAway.ogg:system/media/audio/ringtones/TwirlAway.ogg \
- $(LOCAL_PATH)/ringtones/URSAMINOR.ogg:system/media/audio/ringtones/URSAMINOR.ogg \
$(LOCAL_PATH)/ringtones/ogg/UrsaMinor.ogg:system/media/audio/ringtones/UrsaMinor.ogg \
$(LOCAL_PATH)/newwavelabs/VeryAlarmed.ogg:system/media/audio/ringtones/VeryAlarmed.ogg \
$(LOCAL_PATH)/ringtones/Vespa.ogg:system/media/audio/ringtones/Vespa.ogg \
$(LOCAL_PATH)/newwavelabs/World.ogg:system/media/audio/ringtones/World.ogg \
$(LOCAL_PATH)/ringtones/ogg/Zeta.ogg:system/media/audio/ringtones/Zeta.ogg \
- $(LOCAL_PATH)/ringtones/hydra.ogg:system/media/audio/ringtones/hydra.ogg \
+ $(LOCAL_PATH)/ringtones/material/ogg/Atria.ogg:system/media/audio/ringtones/Atria.ogg \
+ $(LOCAL_PATH)/ringtones/material/ogg/Callisto.ogg:system/media/audio/ringtones/Callisto.ogg \
+ $(LOCAL_PATH)/ringtones/material/ogg/Dione.ogg:system/media/audio/ringtones/Dione.ogg \
+ $(LOCAL_PATH)/ringtones/material/ogg/Ganymede.ogg:system/media/audio/ringtones/Ganymede.ogg \
+ $(LOCAL_PATH)/ringtones/material/ogg/Luna.ogg:system/media/audio/ringtones/Luna.ogg \
+ $(LOCAL_PATH)/ringtones/material/ogg/Oberon.ogg:system/media/audio/ringtones/Oberon.ogg \
+ $(LOCAL_PATH)/ringtones/material/ogg/Phobos.ogg:system/media/audio/ringtones/Phobos.ogg \
+ $(LOCAL_PATH)/ringtones/material/ogg/Pyxis.ogg:system/media/audio/ringtones/Pyxis.ogg \
+ $(LOCAL_PATH)/ringtones/material/ogg/Sedna.ogg:system/media/audio/ringtones/Sedna.ogg \
+ $(LOCAL_PATH)/ringtones/material/ogg/Titania.ogg:system/media/audio/ringtones/Titania.ogg \
+ $(LOCAL_PATH)/ringtones/material/ogg/Triton.ogg:system/media/audio/ringtones/Triton.ogg \
+ $(LOCAL_PATH)/ringtones/material/ogg/Umbriel.ogg:system/media/audio/ringtones/Umbriel.ogg
+endif
+
+PRODUCT_COPY_FILES += \
$(LOCAL_PATH)/effects/ogg/Dock.ogg:system/media/audio/ui/Dock.ogg \
$(LOCAL_PATH)/effects/ogg/Effect_Tick_48k.ogg:system/media/audio/ui/Effect_Tick.ogg \
$(LOCAL_PATH)/effects/ogg/KeypressDelete_120_48k.ogg:system/media/audio/ui/KeypressDelete.ogg \
@@ -231,4 +342,14 @@ PRODUCT_COPY_FILES += \
$(LOCAL_PATH)/effects/ogg/WirelessChargingStarted.ogg:system/media/audio/ui/WirelessChargingStarted.ogg \
$(LOCAL_PATH)/effects/ogg/camera_click_48k.ogg:system/media/audio/ui/camera_click.ogg \
$(LOCAL_PATH)/effects/ogg/camera_focus.ogg:system/media/audio/ui/camera_focus.ogg \
-
+ $(LOCAL_PATH)/notifications/material/ogg/Ariel.ogg:system/media/audio/notifications/Ariel.ogg \
+ $(LOCAL_PATH)/notifications/material/ogg/Carme.ogg:system/media/audio/notifications/Carme.ogg \
+ $(LOCAL_PATH)/notifications/material/ogg/Ceres.ogg:system/media/audio/notifications/Ceres.ogg \
+ $(LOCAL_PATH)/notifications/material/ogg/Elara.ogg:system/media/audio/notifications/Elara.ogg \
+ $(LOCAL_PATH)/notifications/material/ogg/Europa.ogg:system/media/audio/notifications/Europa.ogg \
+ $(LOCAL_PATH)/notifications/material/ogg/Iapetus.ogg:system/media/audio/notifications/Iapetus.ogg \
+ $(LOCAL_PATH)/notifications/material/ogg/Io.ogg:system/media/audio/notifications/Io.ogg \
+ $(LOCAL_PATH)/notifications/material/ogg/Rhea.ogg:system/media/audio/notifications/Rhea.ogg \
+ $(LOCAL_PATH)/notifications/material/ogg/Salacia.ogg:system/media/audio/notifications/Salacia.ogg \
+ $(LOCAL_PATH)/notifications/material/ogg/Tethys.ogg:system/media/audio/notifications/Tethys.ogg \
+ $(LOCAL_PATH)/notifications/material/ogg/Titan.ogg:system/media/audio/notifications/Titan.ogg
diff --git a/data/sounds/AudioPackage10.mk b/data/sounds/AudioPackage10.mk
index 5a5eea6..6eaa323 100644
--- a/data/sounds/AudioPackage10.mk
+++ b/data/sounds/AudioPackage10.mk
@@ -45,7 +45,6 @@ PRODUCT_COPY_FILES += \
$(LOCAL_PATH)/notifications/ogg/Spica.ogg:system/media/audio/notifications/Spica.ogg \
$(LOCAL_PATH)/notifications/ogg/Syrma.ogg:system/media/audio/notifications/Syrma.ogg \
$(LOCAL_PATH)/notifications/ogg/Talitha.ogg:system/media/audio/notifications/Talitha.ogg \
- $(LOCAL_PATH)/notifications/ogg/Tejat.ogg:system/media/audio/notifications/Tejat.ogg \
$(LOCAL_PATH)/notifications/ogg/Vega.ogg:system/media/audio/notifications/Vega.ogg \
$(LOCAL_PATH)/ringtones/ogg/Andromeda.ogg:system/media/audio/ringtones/Andromeda.ogg \
$(LOCAL_PATH)/ringtones/ogg/Aquila.ogg:system/media/audio/ringtones/Aquila.ogg \
diff --git a/data/sounds/AudioPackage11.mk b/data/sounds/AudioPackage11.mk
index 0f85b33..b85282a 100644
--- a/data/sounds/AudioPackage11.mk
+++ b/data/sounds/AudioPackage11.mk
@@ -45,7 +45,6 @@ PRODUCT_COPY_FILES += \
$(LOCAL_PATH)/notifications/ogg/Spica.ogg:system/media/audio/notifications/Spica.ogg \
$(LOCAL_PATH)/notifications/ogg/Syrma.ogg:system/media/audio/notifications/Syrma.ogg \
$(LOCAL_PATH)/notifications/ogg/Talitha.ogg:system/media/audio/notifications/Talitha.ogg \
- $(LOCAL_PATH)/notifications/ogg/Tejat_proc48.ogg:system/media/audio/notifications/Tejat.ogg \
$(LOCAL_PATH)/notifications/ogg/Vega.ogg:system/media/audio/notifications/Vega.ogg \
$(LOCAL_PATH)/ringtones/ogg/Andromeda.ogg:system/media/audio/ringtones/Andromeda.ogg \
$(LOCAL_PATH)/ringtones/ogg/Aquila.ogg:system/media/audio/ringtones/Aquila.ogg \
diff --git a/data/sounds/AudioPackage6.mk b/data/sounds/AudioPackage6.mk
index c843fdc..7740901 100644
--- a/data/sounds/AudioPackage6.mk
+++ b/data/sounds/AudioPackage6.mk
@@ -10,7 +10,6 @@ LOCAL_PATH:= frameworks/base/data/sounds
PRODUCT_COPY_FILES += \
$(LOCAL_PATH)/alarms/ogg/Barium.ogg:system/media/audio/alarms/Barium.ogg \
$(LOCAL_PATH)/alarms/ogg/Cesium.ogg:system/media/audio/alarms/Cesium.ogg \
- $(LOCAL_PATH)/alarms/ogg/Plutonium.ogg:system/media/audio/alarms/Plutonium.ogg \
$(LOCAL_PATH)/alarms/ogg/Scandium.ogg:system/media/audio/alarms/Scandium.ogg \
$(LOCAL_PATH)/effects/ogg/Effect_Tick.ogg:system/media/audio/ui/Effect_Tick.ogg \
$(LOCAL_PATH)/effects/ogg/KeypressStandard.ogg:system/media/audio/ui/KeypressStandard.ogg \
diff --git a/data/sounds/AudioPackage7.mk b/data/sounds/AudioPackage7.mk
index ce82651..a090be8 100644
--- a/data/sounds/AudioPackage7.mk
+++ b/data/sounds/AudioPackage7.mk
@@ -9,11 +9,7 @@ LOCAL_PATH:= frameworks/base/data/sounds
PRODUCT_COPY_FILES += \
$(LOCAL_PATH)/alarms/ogg/Cesium.ogg:system/media/audio/alarms/Cesium.ogg \
- $(LOCAL_PATH)/alarms/ogg/Fermium.ogg:system/media/audio/alarms/Fermium.ogg \
- $(LOCAL_PATH)/alarms/ogg/Hassium.ogg:system/media/audio/alarms/Hassium.ogg \
$(LOCAL_PATH)/alarms/ogg/Neptunium.ogg:system/media/audio/alarms/Neptunium.ogg \
- $(LOCAL_PATH)/alarms/ogg/Nobelium.ogg:system/media/audio/alarms/Nobelium.ogg \
- $(LOCAL_PATH)/alarms/ogg/Plutonium.ogg:system/media/audio/alarms/Plutonium.ogg \
$(LOCAL_PATH)/effects/ogg/Effect_Tick.ogg:system/media/audio/ui/Effect_Tick.ogg \
$(LOCAL_PATH)/effects/ogg/KeypressStandard_120.ogg:system/media/audio/ui/KeypressStandard.ogg \
$(LOCAL_PATH)/effects/ogg/KeypressSpacebar_120.ogg:system/media/audio/ui/KeypressSpacebar.ogg \
@@ -43,7 +39,6 @@ PRODUCT_COPY_FILES += \
$(LOCAL_PATH)/notifications/ogg/Proxima.ogg:system/media/audio/notifications/Proxima.ogg \
$(LOCAL_PATH)/notifications/ogg/Shaula.ogg:system/media/audio/notifications/Shaula.ogg \
$(LOCAL_PATH)/notifications/ogg/Spica.ogg:system/media/audio/notifications/Spica.ogg \
- $(LOCAL_PATH)/notifications/ogg/Tejat.ogg:system/media/audio/notifications/Tejat.ogg \
$(LOCAL_PATH)/notifications/ogg/Upsilon.ogg:system/media/audio/notifications/Upsilon.ogg \
$(LOCAL_PATH)/notifications/ogg/Vega.ogg:system/media/audio/notifications/Vega.ogg \
$(LOCAL_PATH)/ringtones/ogg/Andromeda.ogg:system/media/audio/ringtones/Andromeda.ogg \
diff --git a/data/sounds/AudioPackage7alt.mk b/data/sounds/AudioPackage7alt.mk
index db468f3..9865f41 100644
--- a/data/sounds/AudioPackage7alt.mk
+++ b/data/sounds/AudioPackage7alt.mk
@@ -42,7 +42,6 @@ PRODUCT_COPY_FILES += \
$(LOCAL_PATH)/notifications/ogg/Proxima.ogg:system/media/audio/notifications/Proxima.ogg \
$(LOCAL_PATH)/notifications/ogg/Shaula.ogg:system/media/audio/notifications/Shaula.ogg \
$(LOCAL_PATH)/notifications/ogg/Spica.ogg:system/media/audio/notifications/Spica.ogg \
- $(LOCAL_PATH)/notifications/ogg/Tejat.ogg:system/media/audio/notifications/Tejat.ogg \
$(LOCAL_PATH)/notifications/ogg/Upsilon.ogg:system/media/audio/notifications/Upsilon.ogg \
$(LOCAL_PATH)/notifications/ogg/Vega.ogg:system/media/audio/notifications/Vega.ogg \
$(LOCAL_PATH)/ringtones/ogg/Andromeda.ogg:system/media/audio/ringtones/Andromeda.ogg \
diff --git a/data/sounds/AudioPackage8.mk b/data/sounds/AudioPackage8.mk
index 4112c18..e1526bf 100644
--- a/data/sounds/AudioPackage8.mk
+++ b/data/sounds/AudioPackage8.mk
@@ -9,13 +9,8 @@ LOCAL_PATH:= frameworks/base/data/sounds
PRODUCT_COPY_FILES += \
$(LOCAL_PATH)/alarms/ogg/Cesium.ogg:system/media/audio/alarms/Cesium.ogg \
- $(LOCAL_PATH)/alarms/ogg/Fermium.ogg:system/media/audio/alarms/Fermium.ogg \
- $(LOCAL_PATH)/alarms/ogg/Hassium.ogg:system/media/audio/alarms/Hassium.ogg \
$(LOCAL_PATH)/alarms/ogg/Neptunium.ogg:system/media/audio/alarms/Neptunium.ogg \
- $(LOCAL_PATH)/alarms/ogg/Nobelium.ogg:system/media/audio/alarms/Nobelium.ogg \
$(LOCAL_PATH)/alarms/ogg/Osmium.ogg:system/media/audio/alarms/Osmium.ogg \
- $(LOCAL_PATH)/alarms/ogg/Plutonium.ogg:system/media/audio/alarms/Plutonium.ogg \
- $(LOCAL_PATH)/alarms/ogg/Promethium.ogg:system/media/audio/alarms/Promethium.ogg \
$(LOCAL_PATH)/effects/ogg/Effect_Tick.ogg:system/media/audio/ui/Effect_Tick.ogg \
$(LOCAL_PATH)/effects/ogg/KeypressStandard.ogg:system/media/audio/ui/KeypressStandard.ogg \
$(LOCAL_PATH)/effects/ogg/KeypressSpacebar.ogg:system/media/audio/ui/KeypressSpacebar.ogg \
@@ -45,7 +40,6 @@ PRODUCT_COPY_FILES += \
$(LOCAL_PATH)/notifications/ogg/Proxima.ogg:system/media/audio/notifications/Proxima.ogg \
$(LOCAL_PATH)/notifications/ogg/Shaula.ogg:system/media/audio/notifications/Shaula.ogg \
$(LOCAL_PATH)/notifications/ogg/Spica.ogg:system/media/audio/notifications/Spica.ogg \
- $(LOCAL_PATH)/notifications/ogg/Tejat.ogg:system/media/audio/notifications/Tejat.ogg \
$(LOCAL_PATH)/notifications/ogg/Upsilon.ogg:system/media/audio/notifications/Upsilon.ogg \
$(LOCAL_PATH)/notifications/ogg/Vega.ogg:system/media/audio/notifications/Vega.ogg \
$(LOCAL_PATH)/ringtones/ogg/Andromeda.ogg:system/media/audio/ringtones/Andromeda.ogg \
diff --git a/data/sounds/AudioPackage9.mk b/data/sounds/AudioPackage9.mk
index 1b430c0..e89dbb1 100644
--- a/data/sounds/AudioPackage9.mk
+++ b/data/sounds/AudioPackage9.mk
@@ -44,6 +44,5 @@ PRODUCT_COPY_FILES += \
$(LOCAL_PATH)/notifications/ogg/Spica.ogg:system/media/audio/notifications/Spica.ogg \
$(LOCAL_PATH)/notifications/ogg/Syrma.ogg:system/media/audio/notifications/Syrma.ogg \
$(LOCAL_PATH)/notifications/ogg/Talitha.ogg:system/media/audio/notifications/Talitha.ogg \
- $(LOCAL_PATH)/notifications/ogg/Tejat.ogg:system/media/audio/notifications/Tejat.ogg \
$(LOCAL_PATH)/notifications/ogg/Vega.ogg:system/media/audio/notifications/Vega.ogg \
$(LOCAL_PATH)/ringtones/ogg/Girtab.ogg:system/media/audio/ringtones/Girtab.ogg
diff --git a/data/sounds/Ring_Digital_02.ogg b/data/sounds/Ring_Digital_02.ogg
index f823739..6345151 100644
--- a/data/sounds/Ring_Digital_02.ogg
+++ b/data/sounds/Ring_Digital_02.ogg
Binary files differ
diff --git a/data/sounds/alarms/ogg/Fermium.ogg b/data/sounds/alarms/ogg/Fermium.ogg
deleted file mode 100644
index d8f6124..0000000
--- a/data/sounds/alarms/ogg/Fermium.ogg
+++ /dev/null
Binary files differ
diff --git a/data/sounds/alarms/ogg/Hassium.ogg b/data/sounds/alarms/ogg/Hassium.ogg
deleted file mode 100644
index 793c269..0000000
--- a/data/sounds/alarms/ogg/Hassium.ogg
+++ /dev/null
Binary files differ
diff --git a/data/sounds/alarms/ogg/Nobelium.ogg b/data/sounds/alarms/ogg/Nobelium.ogg
deleted file mode 100644
index 1f94d1e..0000000
--- a/data/sounds/alarms/ogg/Nobelium.ogg
+++ /dev/null
Binary files differ
diff --git a/data/sounds/alarms/ogg/Plutonium.ogg b/data/sounds/alarms/ogg/Plutonium.ogg
deleted file mode 100644
index 5e9a750..0000000
--- a/data/sounds/alarms/ogg/Plutonium.ogg
+++ /dev/null
Binary files differ
diff --git a/data/sounds/alarms/ogg/Promethium.ogg b/data/sounds/alarms/ogg/Promethium.ogg
deleted file mode 100644
index d5f0893..0000000
--- a/data/sounds/alarms/ogg/Promethium.ogg
+++ /dev/null
Binary files differ
diff --git a/data/sounds/notifications/ogg/Tejat.ogg b/data/sounds/notifications/ogg/Tejat.ogg
deleted file mode 100644
index 04ba06c..0000000
--- a/data/sounds/notifications/ogg/Tejat.ogg
+++ /dev/null
Binary files differ
diff --git a/data/sounds/notifications/ogg/Tejat_proc48.ogg b/data/sounds/notifications/ogg/Tejat_proc48.ogg
deleted file mode 100644
index b1637d7..0000000
--- a/data/sounds/notifications/ogg/Tejat_proc48.ogg
+++ /dev/null
Binary files differ
diff --git a/data/sounds/ringtones/boosted/Andromeda.ogg b/data/sounds/ringtones/boosted/Andromeda.ogg
new file mode 100644
index 0000000..68dda8b
--- /dev/null
+++ b/data/sounds/ringtones/boosted/Andromeda.ogg
Binary files differ
diff --git a/data/sounds/ringtones/boosted/Aquila.ogg b/data/sounds/ringtones/boosted/Aquila.ogg
new file mode 100644
index 0000000..569c248
--- /dev/null
+++ b/data/sounds/ringtones/boosted/Aquila.ogg
Binary files differ
diff --git a/data/sounds/ringtones/boosted/ArgoNavis.ogg b/data/sounds/ringtones/boosted/ArgoNavis.ogg
new file mode 100644
index 0000000..797f9fa
--- /dev/null
+++ b/data/sounds/ringtones/boosted/ArgoNavis.ogg
Binary files differ
diff --git a/data/sounds/ringtones/boosted/Atria.ogg b/data/sounds/ringtones/boosted/Atria.ogg
new file mode 100644
index 0000000..c37feaa
--- /dev/null
+++ b/data/sounds/ringtones/boosted/Atria.ogg
Binary files differ
diff --git a/data/sounds/ringtones/boosted/BOOTES.ogg b/data/sounds/ringtones/boosted/BOOTES.ogg
new file mode 100644
index 0000000..affb115
--- /dev/null
+++ b/data/sounds/ringtones/boosted/BOOTES.ogg
Binary files differ
diff --git a/data/sounds/ringtones/boosted/Backroad.ogg b/data/sounds/ringtones/boosted/Backroad.ogg
new file mode 100644
index 0000000..e1ee99b
--- /dev/null
+++ b/data/sounds/ringtones/boosted/Backroad.ogg
Binary files differ
diff --git a/data/sounds/ringtones/boosted/BeatPlucker.ogg b/data/sounds/ringtones/boosted/BeatPlucker.ogg
new file mode 100644
index 0000000..f619d44
--- /dev/null
+++ b/data/sounds/ringtones/boosted/BeatPlucker.ogg
Binary files differ
diff --git a/data/sounds/ringtones/boosted/BentleyDubs.ogg b/data/sounds/ringtones/boosted/BentleyDubs.ogg
new file mode 100644
index 0000000..86af876
--- /dev/null
+++ b/data/sounds/ringtones/boosted/BentleyDubs.ogg
Binary files differ
diff --git a/data/sounds/ringtones/boosted/Big_Easy.ogg b/data/sounds/ringtones/boosted/Big_Easy.ogg
new file mode 100644
index 0000000..e02a3c8
--- /dev/null
+++ b/data/sounds/ringtones/boosted/Big_Easy.ogg
Binary files differ
diff --git a/data/sounds/ringtones/boosted/BirdLoop.ogg b/data/sounds/ringtones/boosted/BirdLoop.ogg
new file mode 100644
index 0000000..28220f2
--- /dev/null
+++ b/data/sounds/ringtones/boosted/BirdLoop.ogg
Binary files differ
diff --git a/data/sounds/ringtones/boosted/Bollywood.ogg b/data/sounds/ringtones/boosted/Bollywood.ogg
new file mode 100644
index 0000000..26b69d2
--- /dev/null
+++ b/data/sounds/ringtones/boosted/Bollywood.ogg
Binary files differ
diff --git a/data/sounds/ringtones/boosted/BussaMove.ogg b/data/sounds/ringtones/boosted/BussaMove.ogg
new file mode 100644
index 0000000..c8eb07b
--- /dev/null
+++ b/data/sounds/ringtones/boosted/BussaMove.ogg
Binary files differ
diff --git a/data/sounds/ringtones/boosted/CASSIOPEIA.ogg b/data/sounds/ringtones/boosted/CASSIOPEIA.ogg
new file mode 100644
index 0000000..38e1b0f
--- /dev/null
+++ b/data/sounds/ringtones/boosted/CASSIOPEIA.ogg
Binary files differ
diff --git a/data/sounds/ringtones/boosted/Cairo.ogg b/data/sounds/ringtones/boosted/Cairo.ogg
new file mode 100644
index 0000000..a065a21
--- /dev/null
+++ b/data/sounds/ringtones/boosted/Cairo.ogg
Binary files differ
diff --git a/data/sounds/ringtones/boosted/Callisto.ogg b/data/sounds/ringtones/boosted/Callisto.ogg
new file mode 100644
index 0000000..1f5977e
--- /dev/null
+++ b/data/sounds/ringtones/boosted/Callisto.ogg
Binary files differ
diff --git a/data/sounds/ringtones/boosted/Calypso_Steel.ogg b/data/sounds/ringtones/boosted/Calypso_Steel.ogg
new file mode 100644
index 0000000..91eb551
--- /dev/null
+++ b/data/sounds/ringtones/boosted/Calypso_Steel.ogg
Binary files differ
diff --git a/data/sounds/ringtones/boosted/CanisMajor.ogg b/data/sounds/ringtones/boosted/CanisMajor.ogg
new file mode 100644
index 0000000..0830c0f
--- /dev/null
+++ b/data/sounds/ringtones/boosted/CanisMajor.ogg
Binary files differ
diff --git a/data/sounds/ringtones/boosted/CaribbeanIce.ogg b/data/sounds/ringtones/boosted/CaribbeanIce.ogg
new file mode 100644
index 0000000..dcb8da6
--- /dev/null
+++ b/data/sounds/ringtones/boosted/CaribbeanIce.ogg
Binary files differ
diff --git a/data/sounds/ringtones/boosted/Carina.ogg b/data/sounds/ringtones/boosted/Carina.ogg
new file mode 100644
index 0000000..007eea3
--- /dev/null
+++ b/data/sounds/ringtones/boosted/Carina.ogg
Binary files differ
diff --git a/data/sounds/ringtones/boosted/Centaurus.ogg b/data/sounds/ringtones/boosted/Centaurus.ogg
new file mode 100644
index 0000000..f374f08
--- /dev/null
+++ b/data/sounds/ringtones/boosted/Centaurus.ogg
Binary files differ
diff --git a/data/sounds/ringtones/boosted/Champagne_Edition.ogg b/data/sounds/ringtones/boosted/Champagne_Edition.ogg
new file mode 100644
index 0000000..35ffb87
--- /dev/null
+++ b/data/sounds/ringtones/boosted/Champagne_Edition.ogg
Binary files differ
diff --git a/data/sounds/ringtones/boosted/Club_Cubano.ogg b/data/sounds/ringtones/boosted/Club_Cubano.ogg
new file mode 100644
index 0000000..5de77f8
--- /dev/null
+++ b/data/sounds/ringtones/boosted/Club_Cubano.ogg
Binary files differ
diff --git a/data/sounds/ringtones/boosted/CrayonRock.ogg b/data/sounds/ringtones/boosted/CrayonRock.ogg
new file mode 100644
index 0000000..625e80d
--- /dev/null
+++ b/data/sounds/ringtones/boosted/CrayonRock.ogg
Binary files differ
diff --git a/data/sounds/ringtones/boosted/CrazyDream.ogg b/data/sounds/ringtones/boosted/CrazyDream.ogg
new file mode 100644
index 0000000..cb53fdd
--- /dev/null
+++ b/data/sounds/ringtones/boosted/CrazyDream.ogg
Binary files differ
diff --git a/data/sounds/ringtones/boosted/CurveBall.ogg b/data/sounds/ringtones/boosted/CurveBall.ogg
new file mode 100644
index 0000000..7655585
--- /dev/null
+++ b/data/sounds/ringtones/boosted/CurveBall.ogg
Binary files differ
diff --git a/data/sounds/ringtones/boosted/Cygnus.ogg b/data/sounds/ringtones/boosted/Cygnus.ogg
new file mode 100644
index 0000000..ed777fd
--- /dev/null
+++ b/data/sounds/ringtones/boosted/Cygnus.ogg
Binary files differ
diff --git a/data/sounds/ringtones/boosted/DancinFool.ogg b/data/sounds/ringtones/boosted/DancinFool.ogg
new file mode 100644
index 0000000..60ff0e9
--- /dev/null
+++ b/data/sounds/ringtones/boosted/DancinFool.ogg
Binary files differ
diff --git a/data/sounds/ringtones/boosted/Dione.ogg b/data/sounds/ringtones/boosted/Dione.ogg
new file mode 100644
index 0000000..7fff3c2
--- /dev/null
+++ b/data/sounds/ringtones/boosted/Dione.ogg
Binary files differ
diff --git a/data/sounds/ringtones/boosted/DonMessWivIt.ogg b/data/sounds/ringtones/boosted/DonMessWivIt.ogg
new file mode 100644
index 0000000..c6f9e3c
--- /dev/null
+++ b/data/sounds/ringtones/boosted/DonMessWivIt.ogg
Binary files differ
diff --git a/data/sounds/ringtones/boosted/Draco.ogg b/data/sounds/ringtones/boosted/Draco.ogg
new file mode 100644
index 0000000..66da7b4
--- /dev/null
+++ b/data/sounds/ringtones/boosted/Draco.ogg
Binary files differ
diff --git a/data/sounds/ringtones/boosted/DreamTheme.ogg b/data/sounds/ringtones/boosted/DreamTheme.ogg
new file mode 100644
index 0000000..d0b0708
--- /dev/null
+++ b/data/sounds/ringtones/boosted/DreamTheme.ogg
Binary files differ
diff --git a/data/sounds/ringtones/boosted/Eastern_Sky.ogg b/data/sounds/ringtones/boosted/Eastern_Sky.ogg
new file mode 100644
index 0000000..87273bc
--- /dev/null
+++ b/data/sounds/ringtones/boosted/Eastern_Sky.ogg
Binary files differ
diff --git a/data/sounds/ringtones/boosted/Enter_the_Nexus.ogg b/data/sounds/ringtones/boosted/Enter_the_Nexus.ogg
new file mode 100644
index 0000000..6d08950
--- /dev/null
+++ b/data/sounds/ringtones/boosted/Enter_the_Nexus.ogg
Binary files differ
diff --git a/data/sounds/ringtones/boosted/Eridani.ogg b/data/sounds/ringtones/boosted/Eridani.ogg
new file mode 100644
index 0000000..7a02018
--- /dev/null
+++ b/data/sounds/ringtones/boosted/Eridani.ogg
Binary files differ
diff --git a/data/sounds/ringtones/boosted/EtherShake.ogg b/data/sounds/ringtones/boosted/EtherShake.ogg
new file mode 100644
index 0000000..1dee33a
--- /dev/null
+++ b/data/sounds/ringtones/boosted/EtherShake.ogg
Binary files differ
diff --git a/data/sounds/ringtones/boosted/FreeFlight.ogg b/data/sounds/ringtones/boosted/FreeFlight.ogg
new file mode 100644
index 0000000..9e84e31
--- /dev/null
+++ b/data/sounds/ringtones/boosted/FreeFlight.ogg
Binary files differ
diff --git a/data/sounds/ringtones/boosted/FriendlyGhost.ogg b/data/sounds/ringtones/boosted/FriendlyGhost.ogg
new file mode 100644
index 0000000..c44e6c0
--- /dev/null
+++ b/data/sounds/ringtones/boosted/FriendlyGhost.ogg
Binary files differ
diff --git a/data/sounds/ringtones/boosted/Funk_Yall.ogg b/data/sounds/ringtones/boosted/Funk_Yall.ogg
new file mode 100644
index 0000000..43f98aa
--- /dev/null
+++ b/data/sounds/ringtones/boosted/Funk_Yall.ogg
Binary files differ
diff --git a/data/sounds/ringtones/boosted/GameOverGuitar.ogg b/data/sounds/ringtones/boosted/GameOverGuitar.ogg
new file mode 100644
index 0000000..2da9602
--- /dev/null
+++ b/data/sounds/ringtones/boosted/GameOverGuitar.ogg
Binary files differ
diff --git a/data/sounds/ringtones/boosted/Ganymede.ogg b/data/sounds/ringtones/boosted/Ganymede.ogg
new file mode 100644
index 0000000..aadad88
--- /dev/null
+++ b/data/sounds/ringtones/boosted/Ganymede.ogg
Binary files differ
diff --git a/data/sounds/ringtones/boosted/Gimme_Mo_Town.ogg b/data/sounds/ringtones/boosted/Gimme_Mo_Town.ogg
new file mode 100644
index 0000000..86526a5
--- /dev/null
+++ b/data/sounds/ringtones/boosted/Gimme_Mo_Town.ogg
Binary files differ
diff --git a/data/sounds/ringtones/boosted/Girtab.ogg b/data/sounds/ringtones/boosted/Girtab.ogg
new file mode 100644
index 0000000..1a7a7b0
--- /dev/null
+++ b/data/sounds/ringtones/boosted/Girtab.ogg
Binary files differ
diff --git a/data/sounds/ringtones/boosted/Glacial_Groove.ogg b/data/sounds/ringtones/boosted/Glacial_Groove.ogg
new file mode 100644
index 0000000..d7cab21
--- /dev/null
+++ b/data/sounds/ringtones/boosted/Glacial_Groove.ogg
Binary files differ
diff --git a/data/sounds/ringtones/boosted/Growl.ogg b/data/sounds/ringtones/boosted/Growl.ogg
new file mode 100644
index 0000000..e418785
--- /dev/null
+++ b/data/sounds/ringtones/boosted/Growl.ogg
Binary files differ
diff --git a/data/sounds/ringtones/boosted/HalfwayHome.ogg b/data/sounds/ringtones/boosted/HalfwayHome.ogg
new file mode 100644
index 0000000..3abb74a
--- /dev/null
+++ b/data/sounds/ringtones/boosted/HalfwayHome.ogg
Binary files differ
diff --git a/data/sounds/ringtones/boosted/Hydra.ogg b/data/sounds/ringtones/boosted/Hydra.ogg
new file mode 100644
index 0000000..1783b8d
--- /dev/null
+++ b/data/sounds/ringtones/boosted/Hydra.ogg
Binary files differ
diff --git a/data/sounds/ringtones/boosted/InsertCoin.ogg b/data/sounds/ringtones/boosted/InsertCoin.ogg
new file mode 100644
index 0000000..a7cd52b
--- /dev/null
+++ b/data/sounds/ringtones/boosted/InsertCoin.ogg
Binary files differ
diff --git a/data/sounds/ringtones/boosted/Kuma.ogg b/data/sounds/ringtones/boosted/Kuma.ogg
new file mode 100644
index 0000000..2ab496c
--- /dev/null
+++ b/data/sounds/ringtones/boosted/Kuma.ogg
Binary files differ
diff --git a/data/sounds/ringtones/boosted/LoopyLounge.ogg b/data/sounds/ringtones/boosted/LoopyLounge.ogg
new file mode 100644
index 0000000..4463e79
--- /dev/null
+++ b/data/sounds/ringtones/boosted/LoopyLounge.ogg
Binary files differ
diff --git a/data/sounds/ringtones/boosted/LoveFlute.ogg b/data/sounds/ringtones/boosted/LoveFlute.ogg
new file mode 100644
index 0000000..2074360
--- /dev/null
+++ b/data/sounds/ringtones/boosted/LoveFlute.ogg
Binary files differ
diff --git a/data/sounds/ringtones/boosted/Luna.ogg b/data/sounds/ringtones/boosted/Luna.ogg
new file mode 100644
index 0000000..b222f5a
--- /dev/null
+++ b/data/sounds/ringtones/boosted/Luna.ogg
Binary files differ
diff --git a/data/sounds/ringtones/boosted/Lyra.ogg b/data/sounds/ringtones/boosted/Lyra.ogg
new file mode 100644
index 0000000..1c79eeb
--- /dev/null
+++ b/data/sounds/ringtones/boosted/Lyra.ogg
Binary files differ
diff --git a/data/sounds/ringtones/boosted/Machina.ogg b/data/sounds/ringtones/boosted/Machina.ogg
new file mode 100644
index 0000000..2218e11
--- /dev/null
+++ b/data/sounds/ringtones/boosted/Machina.ogg
Binary files differ
diff --git a/data/sounds/ringtones/boosted/MidEvilJaunt.ogg b/data/sounds/ringtones/boosted/MidEvilJaunt.ogg
new file mode 100644
index 0000000..8437ebb
--- /dev/null
+++ b/data/sounds/ringtones/boosted/MidEvilJaunt.ogg
Binary files differ
diff --git a/data/sounds/ringtones/boosted/MildlyAlarming.ogg b/data/sounds/ringtones/boosted/MildlyAlarming.ogg
new file mode 100644
index 0000000..54f0344
--- /dev/null
+++ b/data/sounds/ringtones/boosted/MildlyAlarming.ogg
Binary files differ
diff --git a/data/sounds/ringtones/boosted/Nairobi.ogg b/data/sounds/ringtones/boosted/Nairobi.ogg
new file mode 100644
index 0000000..b43723d
--- /dev/null
+++ b/data/sounds/ringtones/boosted/Nairobi.ogg
Binary files differ
diff --git a/data/sounds/ringtones/boosted/Nassau.ogg b/data/sounds/ringtones/boosted/Nassau.ogg
new file mode 100644
index 0000000..96f26ba
--- /dev/null
+++ b/data/sounds/ringtones/boosted/Nassau.ogg
Binary files differ
diff --git a/data/sounds/ringtones/boosted/NewPlayer.ogg b/data/sounds/ringtones/boosted/NewPlayer.ogg
new file mode 100644
index 0000000..adf42f7
--- /dev/null
+++ b/data/sounds/ringtones/boosted/NewPlayer.ogg
Binary files differ
diff --git a/data/sounds/ringtones/boosted/No_Limits.ogg b/data/sounds/ringtones/boosted/No_Limits.ogg
new file mode 100644
index 0000000..4055fdb
--- /dev/null
+++ b/data/sounds/ringtones/boosted/No_Limits.ogg
Binary files differ
diff --git a/data/sounds/ringtones/boosted/Noises2.ogg b/data/sounds/ringtones/boosted/Noises2.ogg
new file mode 100644
index 0000000..0861bc2
--- /dev/null
+++ b/data/sounds/ringtones/boosted/Noises2.ogg
Binary files differ
diff --git a/data/sounds/ringtones/boosted/Noises3.ogg b/data/sounds/ringtones/boosted/Noises3.ogg
new file mode 100644
index 0000000..7aa83af
--- /dev/null
+++ b/data/sounds/ringtones/boosted/Noises3.ogg
Binary files differ
diff --git a/data/sounds/ringtones/boosted/Oberon.ogg b/data/sounds/ringtones/boosted/Oberon.ogg
new file mode 100644
index 0000000..4b6e8f1
--- /dev/null
+++ b/data/sounds/ringtones/boosted/Oberon.ogg
Binary files differ
diff --git a/data/sounds/ringtones/boosted/OrganDub.ogg b/data/sounds/ringtones/boosted/OrganDub.ogg
new file mode 100644
index 0000000..7494355
--- /dev/null
+++ b/data/sounds/ringtones/boosted/OrganDub.ogg
Binary files differ
diff --git a/data/sounds/ringtones/boosted/Orion.ogg b/data/sounds/ringtones/boosted/Orion.ogg
new file mode 100644
index 0000000..e283ea5
--- /dev/null
+++ b/data/sounds/ringtones/boosted/Orion.ogg
Binary files differ
diff --git a/data/sounds/ringtones/boosted/Paradise_Island.ogg b/data/sounds/ringtones/boosted/Paradise_Island.ogg
new file mode 100644
index 0000000..63ee12a
--- /dev/null
+++ b/data/sounds/ringtones/boosted/Paradise_Island.ogg
Binary files differ
diff --git a/data/sounds/ringtones/boosted/Pegasus.ogg b/data/sounds/ringtones/boosted/Pegasus.ogg
new file mode 100644
index 0000000..87b8a67
--- /dev/null
+++ b/data/sounds/ringtones/boosted/Pegasus.ogg
Binary files differ
diff --git a/data/sounds/ringtones/boosted/Perseus.ogg b/data/sounds/ringtones/boosted/Perseus.ogg
new file mode 100644
index 0000000..80fb2bd
--- /dev/null
+++ b/data/sounds/ringtones/boosted/Perseus.ogg
Binary files differ
diff --git a/data/sounds/ringtones/boosted/Phobos.ogg b/data/sounds/ringtones/boosted/Phobos.ogg
new file mode 100644
index 0000000..e3195b0
--- /dev/null
+++ b/data/sounds/ringtones/boosted/Phobos.ogg
Binary files differ
diff --git a/data/sounds/ringtones/boosted/Playa.ogg b/data/sounds/ringtones/boosted/Playa.ogg
new file mode 100644
index 0000000..7a69073
--- /dev/null
+++ b/data/sounds/ringtones/boosted/Playa.ogg
Binary files differ
diff --git a/data/sounds/ringtones/boosted/Pyxis.ogg b/data/sounds/ringtones/boosted/Pyxis.ogg
new file mode 100644
index 0000000..77401f6
--- /dev/null
+++ b/data/sounds/ringtones/boosted/Pyxis.ogg
Binary files differ
diff --git a/data/sounds/ringtones/boosted/Rasalas.ogg b/data/sounds/ringtones/boosted/Rasalas.ogg
new file mode 100644
index 0000000..beb985a
--- /dev/null
+++ b/data/sounds/ringtones/boosted/Rasalas.ogg
Binary files differ
diff --git a/data/sounds/ringtones/boosted/Revelation.ogg b/data/sounds/ringtones/boosted/Revelation.ogg
new file mode 100644
index 0000000..5cce13f
--- /dev/null
+++ b/data/sounds/ringtones/boosted/Revelation.ogg
Binary files differ
diff --git a/data/sounds/ringtones/boosted/Rigel.ogg b/data/sounds/ringtones/boosted/Rigel.ogg
new file mode 100644
index 0000000..8aa4348
--- /dev/null
+++ b/data/sounds/ringtones/boosted/Rigel.ogg
Binary files differ
diff --git a/data/sounds/ringtones/boosted/Ring_Classic_02.ogg b/data/sounds/ringtones/boosted/Ring_Classic_02.ogg
new file mode 100644
index 0000000..eb65743
--- /dev/null
+++ b/data/sounds/ringtones/boosted/Ring_Classic_02.ogg
Binary files differ
diff --git a/data/sounds/ringtones/boosted/Ring_Digital_02.ogg b/data/sounds/ringtones/boosted/Ring_Digital_02.ogg
new file mode 100644
index 0000000..76694ed
--- /dev/null
+++ b/data/sounds/ringtones/boosted/Ring_Digital_02.ogg
Binary files differ
diff --git a/data/sounds/ringtones/boosted/Ring_Synth_02.ogg b/data/sounds/ringtones/boosted/Ring_Synth_02.ogg
new file mode 100644
index 0000000..4b48c4b
--- /dev/null
+++ b/data/sounds/ringtones/boosted/Ring_Synth_02.ogg
Binary files differ
diff --git a/data/sounds/ringtones/boosted/Ring_Synth_04.ogg b/data/sounds/ringtones/boosted/Ring_Synth_04.ogg
new file mode 100644
index 0000000..b63a3e5
--- /dev/null
+++ b/data/sounds/ringtones/boosted/Ring_Synth_04.ogg
Binary files differ
diff --git a/data/sounds/ringtones/boosted/Road_Trip.ogg b/data/sounds/ringtones/boosted/Road_Trip.ogg
new file mode 100644
index 0000000..2af6fd0
--- /dev/null
+++ b/data/sounds/ringtones/boosted/Road_Trip.ogg
Binary files differ
diff --git a/data/sounds/ringtones/boosted/RomancingTheTone.ogg b/data/sounds/ringtones/boosted/RomancingTheTone.ogg
new file mode 100644
index 0000000..fef977c
--- /dev/null
+++ b/data/sounds/ringtones/boosted/RomancingTheTone.ogg
Binary files differ
diff --git a/data/sounds/ringtones/boosted/Safari.ogg b/data/sounds/ringtones/boosted/Safari.ogg
new file mode 100644
index 0000000..af9935f
--- /dev/null
+++ b/data/sounds/ringtones/boosted/Safari.ogg
Binary files differ
diff --git a/data/sounds/ringtones/boosted/Savannah.ogg b/data/sounds/ringtones/boosted/Savannah.ogg
new file mode 100644
index 0000000..c700f90
--- /dev/null
+++ b/data/sounds/ringtones/boosted/Savannah.ogg
Binary files differ
diff --git a/data/sounds/ringtones/boosted/Scarabaeus.ogg b/data/sounds/ringtones/boosted/Scarabaeus.ogg
new file mode 100644
index 0000000..627d400
--- /dev/null
+++ b/data/sounds/ringtones/boosted/Scarabaeus.ogg
Binary files differ
diff --git a/data/sounds/ringtones/boosted/Sceptrum.ogg b/data/sounds/ringtones/boosted/Sceptrum.ogg
new file mode 100644
index 0000000..a9e41b7
--- /dev/null
+++ b/data/sounds/ringtones/boosted/Sceptrum.ogg
Binary files differ
diff --git a/data/sounds/ringtones/boosted/Sedna.ogg b/data/sounds/ringtones/boosted/Sedna.ogg
new file mode 100644
index 0000000..9e84526
--- /dev/null
+++ b/data/sounds/ringtones/boosted/Sedna.ogg
Binary files differ
diff --git a/data/sounds/ringtones/boosted/Seville.ogg b/data/sounds/ringtones/boosted/Seville.ogg
new file mode 100644
index 0000000..539152a
--- /dev/null
+++ b/data/sounds/ringtones/boosted/Seville.ogg
Binary files differ
diff --git a/data/sounds/ringtones/boosted/Shes_All_That.ogg b/data/sounds/ringtones/boosted/Shes_All_That.ogg
new file mode 100644
index 0000000..6984976
--- /dev/null
+++ b/data/sounds/ringtones/boosted/Shes_All_That.ogg
Binary files differ
diff --git a/data/sounds/ringtones/boosted/SilkyWay.ogg b/data/sounds/ringtones/boosted/SilkyWay.ogg
new file mode 100644
index 0000000..16dbd5a
--- /dev/null
+++ b/data/sounds/ringtones/boosted/SilkyWay.ogg
Binary files differ
diff --git a/data/sounds/ringtones/boosted/SitarVsSitar.ogg b/data/sounds/ringtones/boosted/SitarVsSitar.ogg
new file mode 100644
index 0000000..dbd739e
--- /dev/null
+++ b/data/sounds/ringtones/boosted/SitarVsSitar.ogg
Binary files differ
diff --git a/data/sounds/ringtones/boosted/Solarium.ogg b/data/sounds/ringtones/boosted/Solarium.ogg
new file mode 100644
index 0000000..f1e2f96
--- /dev/null
+++ b/data/sounds/ringtones/boosted/Solarium.ogg
Binary files differ
diff --git a/data/sounds/ringtones/boosted/SpringyJalopy.ogg b/data/sounds/ringtones/boosted/SpringyJalopy.ogg
new file mode 100644
index 0000000..f3b9b20
--- /dev/null
+++ b/data/sounds/ringtones/boosted/SpringyJalopy.ogg
Binary files differ
diff --git a/data/sounds/ringtones/boosted/Steppin_Out.ogg b/data/sounds/ringtones/boosted/Steppin_Out.ogg
new file mode 100644
index 0000000..ae86b48
--- /dev/null
+++ b/data/sounds/ringtones/boosted/Steppin_Out.ogg
Binary files differ
diff --git a/data/sounds/ringtones/boosted/Terminated.ogg b/data/sounds/ringtones/boosted/Terminated.ogg
new file mode 100644
index 0000000..8543392
--- /dev/null
+++ b/data/sounds/ringtones/boosted/Terminated.ogg
Binary files differ
diff --git a/data/sounds/ringtones/boosted/Testudo.ogg b/data/sounds/ringtones/boosted/Testudo.ogg
new file mode 100644
index 0000000..9fafd9a
--- /dev/null
+++ b/data/sounds/ringtones/boosted/Testudo.ogg
Binary files differ
diff --git a/data/sounds/ringtones/boosted/Themos.ogg b/data/sounds/ringtones/boosted/Themos.ogg
new file mode 100644
index 0000000..25c5411
--- /dev/null
+++ b/data/sounds/ringtones/boosted/Themos.ogg
Binary files differ
diff --git a/data/sounds/ringtones/boosted/Third_Eye.ogg b/data/sounds/ringtones/boosted/Third_Eye.ogg
new file mode 100644
index 0000000..e148786
--- /dev/null
+++ b/data/sounds/ringtones/boosted/Third_Eye.ogg
Binary files differ
diff --git a/data/sounds/ringtones/boosted/Thunderfoot.ogg b/data/sounds/ringtones/boosted/Thunderfoot.ogg
new file mode 100644
index 0000000..0f080f2
--- /dev/null
+++ b/data/sounds/ringtones/boosted/Thunderfoot.ogg
Binary files differ
diff --git a/data/sounds/ringtones/boosted/Titania.ogg b/data/sounds/ringtones/boosted/Titania.ogg
new file mode 100644
index 0000000..20714ff
--- /dev/null
+++ b/data/sounds/ringtones/boosted/Titania.ogg
Binary files differ
diff --git a/data/sounds/ringtones/boosted/Triton.ogg b/data/sounds/ringtones/boosted/Triton.ogg
new file mode 100644
index 0000000..cfdf7b9
--- /dev/null
+++ b/data/sounds/ringtones/boosted/Triton.ogg
Binary files differ
diff --git a/data/sounds/ringtones/boosted/TwirlAway.ogg b/data/sounds/ringtones/boosted/TwirlAway.ogg
new file mode 100644
index 0000000..6b00e8e
--- /dev/null
+++ b/data/sounds/ringtones/boosted/TwirlAway.ogg
Binary files differ
diff --git a/data/sounds/ringtones/boosted/Umbriel.ogg b/data/sounds/ringtones/boosted/Umbriel.ogg
new file mode 100644
index 0000000..03d39ef
--- /dev/null
+++ b/data/sounds/ringtones/boosted/Umbriel.ogg
Binary files differ
diff --git a/data/sounds/ringtones/boosted/UrsaMinor.ogg b/data/sounds/ringtones/boosted/UrsaMinor.ogg
new file mode 100644
index 0000000..b642ce7
--- /dev/null
+++ b/data/sounds/ringtones/boosted/UrsaMinor.ogg
Binary files differ
diff --git a/data/sounds/ringtones/boosted/VeryAlarmed.ogg b/data/sounds/ringtones/boosted/VeryAlarmed.ogg
new file mode 100644
index 0000000..bbbff62
--- /dev/null
+++ b/data/sounds/ringtones/boosted/VeryAlarmed.ogg
Binary files differ
diff --git a/data/sounds/ringtones/boosted/Vespa.ogg b/data/sounds/ringtones/boosted/Vespa.ogg
new file mode 100644
index 0000000..b3bbd74
--- /dev/null
+++ b/data/sounds/ringtones/boosted/Vespa.ogg
Binary files differ
diff --git a/data/sounds/ringtones/boosted/World.ogg b/data/sounds/ringtones/boosted/World.ogg
new file mode 100644
index 0000000..76f4eea
--- /dev/null
+++ b/data/sounds/ringtones/boosted/World.ogg
Binary files differ
diff --git a/data/sounds/ringtones/boosted/Zeta.ogg b/data/sounds/ringtones/boosted/Zeta.ogg
new file mode 100644
index 0000000..cf76667
--- /dev/null
+++ b/data/sounds/ringtones/boosted/Zeta.ogg
Binary files differ
diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java
index 3e4d93b..ba2a890 100644
--- a/graphics/java/android/graphics/Bitmap.java
+++ b/graphics/java/android/graphics/Bitmap.java
@@ -96,6 +96,7 @@ public final class Bitmap implements Parcelable {
if (sDefaultDensity >= 0) {
return sDefaultDensity;
}
+ //noinspection deprecation
sDefaultDensity = DisplayMetrics.DENSITY_DEVICE;
return sDefaultDensity;
}
diff --git a/graphics/java/android/graphics/FontListConverter.java b/graphics/java/android/graphics/FontListConverter.java
new file mode 100644
index 0000000..c675c88
--- /dev/null
+++ b/graphics/java/android/graphics/FontListConverter.java
@@ -0,0 +1,220 @@
+/*
+ * Copyright (C) 2014 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.graphics;
+
+import android.graphics.FontListParser;
+import android.graphics.FontListParser.Alias;
+import android.graphics.FontListParser.Font;
+import android.graphics.LegacyFontListParser.Family;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map.Entry;
+
+/**
+ * Converts a list of Family to FontListParser.Config
+ * {@hide}
+ */
+public class FontListConverter {
+ // These array values were determined by the order
+ // of fonts in a fileset. The order is:
+ // "Normal, Bold, Italic, BoldItalic"
+ // Additionally the weight values in L's fonts.xml
+ // are used to determine a generic weight value for each type
+ // e.g The 2nd entry in a fileset is the bold font.
+ protected static final int[] WEIGHTS = { 400, 700, 400, 700 };
+ protected static boolean[] ITALICS = { false, false, true, true };
+ protected static final int DEFAULT_WEIGHT = WEIGHTS[0];
+
+ // Arbitrarily chosen list based on L's fonts.xml.
+ // There could be more out there, but we can't use a generic pattern of "fontName-styleName"
+ // as "sans-serif" would be translated as a font called "sans" with the style "serif".
+ public static final String[] STYLES = {
+ "thin",
+ "light",
+ "medium",
+ "black"
+ };
+
+ // Maps a "normal" family to a list of similar families differing by style
+ // Example: "sans-serif" -> { sans-serif-thin, sans-serif-light, sans-serif-medium }
+ private HashMap<Family, List<Family>> mFamilyVariants = new HashMap<Family, List<Family>>();
+ private List<Family> mFamilies =
+ new ArrayList<Family >();
+ private String mFontDir;
+
+
+ public FontListConverter(List<Family> families, String fontDir) {
+ mFamilies.addAll(families);
+ mFontDir = fontDir;
+ findFamilyVariants();
+ }
+
+ public FontListConverter(Family family, String fontDir) {
+ mFamilies.add(family);
+ mFontDir = fontDir;
+ findFamilyVariants();
+ }
+
+ private void findFamilyVariants() {
+ for(Family family : mFamilies) {
+ if (isNormalStyle(family)) {
+ List<Family> variants = findVariants(family, mFamilies);
+ mFamilyVariants.put(family, variants);
+ }
+ }
+ }
+
+ private List<Family> findVariants(Family normalFamily, List<Family> legacyFamilies) {
+ List<Family> variants = new ArrayList<Family>();
+
+ String normalFamilyName = normalFamily.getName();
+
+ for(Family family : legacyFamilies) {
+ String name = family.getName();
+
+ if (name.startsWith(normalFamilyName) && !isNormalStyle(family)) {
+ variants.add(family);
+ }
+ }
+ return variants;
+ }
+
+ public FontListParser.Config convert() {
+ FontListParser.Config config = new FontListParser.Config();
+ config.families.addAll(convertFamilies());
+ config.aliases.addAll(createAliases());
+ return config;
+ }
+
+ /**
+ * A "normal" style is just standard font,
+ * eg Roboto is normal. Roboto-Thin is styled.
+ */
+ protected boolean isNormalStyle(Family family) {
+ String name = family.getName();
+ if (name == null) return false;
+
+ for(String style : STYLES) {
+ if (name.endsWith('-' + style)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ protected List<FontListParser.Family> convertFamilies() {
+ List<FontListParser.Family> convertedFamilies = new ArrayList<FontListParser.Family>();
+
+ // Only convert normal families. Each normal family will add in its variants
+ for(Family family : mFamilyVariants.keySet()) {
+ convertedFamilies.add(convertFamily(family));
+ }
+
+ return convertedFamilies;
+ }
+
+ protected FontListParser.Family convertFamily(Family legacyFamily) {
+ List<String> nameset = legacyFamily.nameset;
+ List<String> fileset = legacyFamily.fileset;
+
+ // Arbitrarily choose the first entry in the nameset to be the name
+ String name = nameset.isEmpty() ? null : nameset.get(0);
+
+ List<Font> fonts = convertFonts(fileset);
+
+ // Add fonts from other variants
+ for(Family variantFamily : mFamilyVariants.get(legacyFamily)) {
+ fonts.addAll(convertFonts(variantFamily.fileset));
+ }
+
+ return new FontListParser.Family(name, fonts, null, null);
+ }
+
+ protected List<FontListParser.Font> convertFonts(List<String> fileset) {
+ List<Font> fonts = new ArrayList<Font>();
+
+ for(int i=0; i < fileset.size(); i++) {
+ String fullpath = mFontDir + File.separatorChar + fileset.get(i);
+ // fileset should only be 4 entries, but if
+ // its more we can just assign a default.
+ int weight = i < WEIGHTS.length ? WEIGHTS[i] : DEFAULT_WEIGHT;
+ boolean isItalic = i < ITALICS.length ? ITALICS[i] : false;
+
+ Font font = new Font(fullpath, weight, isItalic);
+ fonts.add(font);
+ }
+
+ return fonts;
+ }
+
+ protected List<Alias> createAliases() {
+ List<Alias> aliases = new ArrayList<Alias>();
+
+ for(Family family : mFamilyVariants.keySet()) {
+ // Get any aliases that might be from a normal family's nameset.
+ // eg sans-serif, arial, helvetica, tahoma etc.
+ if (isNormalStyle(family)) {
+ aliases.addAll(adaptNamesetAliases(family.nameset));
+ }
+ }
+
+ aliases.addAll(getAliasesForRelatedFamilies());
+
+ return aliases;
+ }
+
+ private List<Alias> getAliasesForRelatedFamilies() {
+ List<Alias> aliases = new ArrayList<Alias>();
+
+ for(Entry<Family, List<Family>> entry : mFamilyVariants.entrySet()) {
+ String toName = entry.getKey().nameset.get(0);
+ List<Family> relatedFamilies = entry.getValue();
+ for(Family relatedFamily : relatedFamilies) {
+ aliases.addAll(adaptNamesetAliases(relatedFamily.nameset, toName));
+ }
+ }
+ return aliases;
+ }
+
+ private List<Alias> adaptNamesetAliases(List<String> nameset, String toName) {
+ List<Alias> aliases = new ArrayList<Alias>();
+ for(String name : nameset) {
+ Alias alias = new Alias();
+ alias.name = name;
+ alias.toName = toName;
+ aliases.add(alias);
+ }
+ return aliases;
+ }
+
+ private List<Alias> adaptNamesetAliases(List<String> nameset) {
+ List<Alias> aliases = new ArrayList<Alias>();
+ if (nameset.size() < 2) return aliases; // An alias requires a name and toName
+
+ String toName = nameset.get(0);
+ for(int i = 1; i < nameset.size(); i++) {
+ Alias alias = new Alias();
+ alias.name = nameset.get(i);
+ alias.toName = toName;
+ aliases.add(alias);
+ }
+
+ return aliases;
+ }
+}
diff --git a/graphics/java/android/graphics/FontListParser.java b/graphics/java/android/graphics/FontListParser.java
index 97081f9..d789690 100644
--- a/graphics/java/android/graphics/FontListParser.java
+++ b/graphics/java/android/graphics/FontListParser.java
@@ -21,6 +21,9 @@ import android.util.Xml;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
@@ -74,25 +77,83 @@ public class FontListParser {
}
/* Parse fallback list (no names) */
- public static Config parse(InputStream in) throws XmlPullParserException, IOException {
+ public static Config parse(File configFilename, String fontDir)
+ throws XmlPullParserException, IOException {
+ FileInputStream in = null;
+ in = new FileInputStream(configFilename);
+ return FontListParser.parse(in, fontDir);
+ }
+
+ /* Parse fallback list (no names) */
+ public static Config parse(InputStream in, String fontDir)
+ throws XmlPullParserException, IOException {
+ BufferedInputStream bis = null;
try {
- XmlPullParser parser = Xml.newPullParser();
- parser.setInput(in, null);
- parser.nextTag();
- return readFamilies(parser);
+ // wrap input stream in a BufferedInputStream, if it's not already, for mark support
+ if (!(in instanceof BufferedInputStream)) {
+ bis = new BufferedInputStream(in);
+ } else {
+ bis = (BufferedInputStream) in;
+ }
+ // mark the beginning so we can reset to this position after checking format
+ bis.mark(in.available());
+ if (isLegacyFormat(bis)) {
+ return parseLegacyFormat(bis, fontDir);
+ } else {
+ return parseNormalFormat(bis, fontDir);
+ }
+ } finally {
+ if (bis != null) bis.close();
+ }
+ }
+
+ public static boolean isLegacyFormat(InputStream in)
+ throws XmlPullParserException, IOException {
+ if (!in.markSupported()) {
+ throw new IllegalArgumentException("InputStream does not support mark");
+ }
+ boolean isLegacy = false;
+
+ XmlPullParser parser = Xml.newPullParser();
+ parser.setInput(in, null);
+ parser.nextTag();
+ parser.require(XmlPullParser.START_TAG, null, "familyset");
+ String version = parser.getAttributeValue(null, "version");
+ isLegacy = version == null;
+
+ // reset the stream so we can read it
+ in.reset();
+
+ return isLegacy;
+ }
+
+ public static Config parseLegacyFormat(InputStream in, String dirName)
+ throws XmlPullParserException, IOException {
+ try {
+ List<LegacyFontListParser.Family> legacyFamilies = LegacyFontListParser.parse(in);
+ FontListConverter converter = new FontListConverter(legacyFamilies, dirName);
+ return converter.convert();
} finally {
in.close();
}
}
- private static Config readFamilies(XmlPullParser parser)
+ public static Config parseNormalFormat(InputStream in, String dirName)
+ throws XmlPullParserException, IOException {
+ XmlPullParser parser = Xml.newPullParser();
+ parser.setInput(in, null);
+ parser.nextTag();
+ return readFamilies(parser, dirName);
+ }
+
+ private static Config readFamilies(XmlPullParser parser, String dirPath)
throws XmlPullParserException, IOException {
Config config = new Config();
parser.require(XmlPullParser.START_TAG, null, "familyset");
while (parser.next() != XmlPullParser.END_TAG) {
if (parser.getEventType() != XmlPullParser.START_TAG) continue;
if (parser.getName().equals("family")) {
- config.families.add(readFamily(parser));
+ config.families.add(readFamily(parser, dirPath));
} else if (parser.getName().equals("alias")) {
config.aliases.add(readAlias(parser));
} else {
@@ -102,7 +163,7 @@ public class FontListParser {
return config;
}
- private static Family readFamily(XmlPullParser parser)
+ private static Family readFamily(XmlPullParser parser, String dirPath)
throws XmlPullParserException, IOException {
String name = parser.getAttributeValue(null, "name");
String lang = parser.getAttributeValue(null, "lang");
@@ -116,7 +177,7 @@ public class FontListParser {
int weight = weightStr == null ? 400 : Integer.parseInt(weightStr);
boolean isItalic = "italic".equals(parser.getAttributeValue(null, "style"));
String filename = parser.nextText();
- String fullFilename = "/system/fonts/" + filename;
+ String fullFilename = dirPath + File.separatorChar + filename;
fonts.add(new Font(fullFilename, weight, isItalic));
} else {
skip(parser);
diff --git a/graphics/java/android/graphics/LegacyFontListParser.java b/graphics/java/android/graphics/LegacyFontListParser.java
new file mode 100644
index 0000000..22923cb
--- /dev/null
+++ b/graphics/java/android/graphics/LegacyFontListParser.java
@@ -0,0 +1,187 @@
+/*
+ * Copyright (C) 2014 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.graphics;
+
+import android.util.Xml;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Parses an XML font config. Example:
+ *
+ *<familyset>
+ *
+ * <family>
+ * <nameset>
+ * <name>sans-serif</name>
+ * <name>arial</name>
+ * </nameset>
+ * <fileset>
+ * <file>Roboto-Regular.ttf</file>
+ * <file>Roboto-Bold.ttf</file>
+ * <file>Roboto-Italic.ttf</file>
+ * <file>Roboto-BoldItalic.ttf</file>
+ * </fileset>
+ * </family>
+ * <family>
+ * ...
+ * </family>
+ *</familyset>
+ * @hide
+ */
+public class LegacyFontListParser {
+ public static class Family {
+ public List<String> nameset = new ArrayList<String>();
+ public List<String> fileset = new ArrayList<String>();
+
+ public String getName() {
+ if (nameset != null && !nameset.isEmpty()) {
+ return nameset.get(0);
+ }
+ return null;
+ }
+ }
+
+ public static List<Family> parse(InputStream in)
+ throws XmlPullParserException, IOException {
+ try {
+ XmlPullParser parser = Xml.newPullParser();
+ parser.setInput(in, null);
+ parser.nextTag();
+ return readFamilySet(parser);
+ } finally {
+ in.close();
+ }
+ }
+
+ private static List<Family> readFamilySet(XmlPullParser parser)
+ throws XmlPullParserException, IOException {
+ List<Family> families = new ArrayList<Family>();
+ parser.require(XmlPullParser.START_TAG, null, "familyset");
+
+ while (parser.next() != XmlPullParser.END_TAG) {
+ if (parser.getEventType() != XmlPullParser.START_TAG) {
+ continue;
+ }
+ String name = parser.getName();
+
+ // Starts by looking for the entry tag
+ if (name.equals("family")) {
+ Family family = readFamily(parser);
+ families.add(family);
+ }
+ }
+ return families;
+ }
+
+ private static Family readFamily(XmlPullParser parser)
+ throws XmlPullParserException, IOException {
+ Family family = new Family();
+ parser.require(XmlPullParser.START_TAG, null, "family");
+
+ while (parser.next() != XmlPullParser.END_TAG) {
+ if (parser.getEventType() != XmlPullParser.START_TAG) {
+ continue;
+ }
+ String name = parser.getName();
+ if (name.equals("nameset")) {
+ List<String> nameset = readNameset(parser);
+ family.nameset = nameset;
+ } else if (name.equals("fileset")) {
+ List<String> fileset = readFileset(parser);
+ family.fileset = fileset;
+ } else {
+ skip(parser);
+ }
+ }
+ return family;
+ }
+
+ private static List<String> readNameset(XmlPullParser parser)
+ throws XmlPullParserException, IOException {
+ List<String> names = new ArrayList<String>();
+ parser.require(XmlPullParser.START_TAG, null, "nameset");
+
+ while (parser.next() != XmlPullParser.END_TAG) {
+ if (parser.getEventType() != XmlPullParser.START_TAG) {
+ continue;
+ }
+ String tagname = parser.getName();
+ if (tagname.equals("name")) {
+ String name = readText(parser);
+ names.add(name);
+ } else {
+ skip(parser);
+ }
+ }
+ return names;
+ }
+
+ private static List<String> readFileset(XmlPullParser parser)
+ throws XmlPullParserException, IOException {
+ List<String> files = new ArrayList<String>();
+ parser.require(XmlPullParser.START_TAG, null, "fileset");
+
+ while (parser.next() != XmlPullParser.END_TAG) {
+ if (parser.getEventType() != XmlPullParser.START_TAG) {
+ continue;
+ }
+ String name = parser.getName();
+ if (name.equals("file")) {
+ String file = readText(parser);
+ files.add(file);
+ } else {
+ skip(parser);
+ }
+ }
+ return files;
+ }
+
+ // For the tags title and summary, extracts their text values.
+ private static String readText(XmlPullParser parser)
+ throws IOException, XmlPullParserException {
+ String result = "";
+ if (parser.next() == XmlPullParser.TEXT) {
+ result = parser.getText();
+ parser.nextTag();
+ }
+ return result;
+ }
+
+ private static void skip(XmlPullParser parser)
+ throws XmlPullParserException, IOException {
+ if (parser.getEventType() != XmlPullParser.START_TAG) {
+ throw new IllegalStateException();
+ }
+ int depth = 1;
+ while (depth != 0) {
+ switch (parser.next()) {
+ case XmlPullParser.END_TAG:
+ depth--;
+ break;
+ case XmlPullParser.START_TAG:
+ depth++;
+ break;
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java
index db42314..4e9788a 100644
--- a/graphics/java/android/graphics/Typeface.java
+++ b/graphics/java/android/graphics/Typeface.java
@@ -25,7 +25,6 @@ import android.util.SparseArray;
import org.xmlpull.v1.XmlPullParserException;
import java.io.File;
-import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
@@ -68,6 +67,8 @@ public class Typeface {
static final String FONTS_CONFIG = "fonts.xml";
+ static final String SANS_SERIF_FAMILY_NAME = "sans-serif";
+
/**
* @hide
*/
@@ -81,6 +82,13 @@ public class Typeface {
private int mStyle = 0;
+ // Typefaces that we can garbage collect when changing fonts, and so we don't break public APIs
+ private static Typeface DEFAULT_INTERNAL;
+ private static Typeface DEFAULT_BOLD_INTERNAL;
+ private static Typeface SANS_SERIF_INTERNAL;
+ private static Typeface SERIF_INTERNAL;
+ private static Typeface MONOSPACE_INTERNAL;
+
private static void setDefault(Typeface t) {
sDefaultTypeface = t;
nativeSetDefault(t.native_instance);
@@ -228,7 +236,10 @@ public class Typeface {
for (int i = 0; i < families.length; i++) {
ptrArray[i] = families[i].mNativePtr;
}
- return new Typeface(nativeCreateFromArray(ptrArray));
+
+
+ Typeface typeface = new Typeface(nativeCreateFromArray(ptrArray));
+ return typeface;
}
/**
@@ -267,18 +278,111 @@ public class Typeface {
return fontFamily;
}
+ /**
+ * Adds the family from src with the name familyName as a fallback font in dst
+ * @param src Source font config
+ * @param dst Destination font config
+ * @param familyName Name of family to add as a fallback
+ */
+ private static void addFallbackFontsForFamilyName(FontListParser.Config src,
+ FontListParser.Config dst, String familyName) {
+ for (Family srcFamily : src.families) {
+ if (familyName.equals(srcFamily.name)) {
+ // set the name to null so that it will be added as a fallback
+ srcFamily.name = null;
+ dst.families.add(srcFamily);
+ return;
+ }
+ }
+ }
+
+ /**
+ * Adds any font families in src that do not exist in dst
+ * @param src Source font config
+ * @param dst Destination font config
+ */
+ private static void addMissingFontFamilies(FontListParser.Config src,
+ FontListParser.Config dst) {
+ final int N = dst.families.size();
+ // add missing families
+ for (Family srcFamily : src.families) {
+ boolean addFamily = true;
+ for (int i = 0; i < N && addFamily; i++) {
+ final Family dstFamily = dst.families.get(i);
+ final String dstFamilyName = dstFamily.name;
+ if (dstFamilyName != null && dstFamilyName.equals(srcFamily.name)) {
+ addFamily = false;
+ break;
+ }
+ }
+ if (addFamily) {
+ dst.families.add(srcFamily);
+ }
+ }
+ }
+
+ /**
+ * Adds any aliases in src that do not exist in dst
+ * @param src Source font config
+ * @param dst Destination font config
+ */
+ private static void addMissingFontAliases(FontListParser.Config src,
+ FontListParser.Config dst) {
+ final int N = dst.aliases.size();
+ // add missing aliases
+ for (FontListParser.Alias alias : src.aliases) {
+ boolean addAlias = true;
+ for (int i = 0; i < N && addAlias; i++) {
+ final String dstAliasName = dst.aliases.get(i).name;
+ if (dstAliasName != null && dstAliasName.equals(alias.name)) {
+ addAlias = false;
+ break;
+ }
+ }
+ if (addAlias) {
+ dst.aliases.add(alias);
+ }
+ }
+ }
+
/*
* (non-Javadoc)
*
* This should only be called once, from the static class initializer block.
*/
- private static void init() {
+ private static void init(boolean forceSystemFonts) {
// Load font config and initialize Minikin state
File systemFontConfigLocation = getSystemFontConfigLocation();
- File configFilename = new File(systemFontConfigLocation, FONTS_CONFIG);
+ File themeFontConfigLocation = getThemeFontConfigLocation();
+
+ File systemConfigFile = new File(systemFontConfigLocation, FONTS_CONFIG);
+ File themeConfigFile = new File(themeFontConfigLocation, FONTS_CONFIG);
+ File configFile = null;
+ File fontDir;
+
+ if (!forceSystemFonts && themeConfigFile.exists()) {
+ configFile = themeConfigFile;
+ fontDir = getThemeFontDirLocation();
+ } else {
+ configFile = systemConfigFile;
+ fontDir = getSystemFontDirLocation();
+ }
+
try {
- FileInputStream fontsIn = new FileInputStream(configFilename);
- FontListParser.Config fontConfig = FontListParser.parse(fontsIn);
+ FontListParser.Config fontConfig = FontListParser.parse(configFile,
+ fontDir.getAbsolutePath());
+ FontListParser.Config systemFontConfig = null;
+
+ // If the fonts are coming from a theme, we will need to make sure that we include
+ // any font families from the system fonts that the theme did not include.
+ // NOTE: All the system font families without names ALWAYS get added.
+ if (configFile == themeConfigFile) {
+ systemFontConfig = FontListParser.parse(systemConfigFile,
+ getSystemFontDirLocation().getAbsolutePath());
+ addMissingFontFamilies(systemFontConfig, fontConfig);
+ addMissingFontAliases(systemFontConfig, fontConfig);
+ addFallbackFontsForFamilyName(systemFontConfig, fontConfig, SANS_SERIF_FAMILY_NAME);
+ }
List<FontFamily> familyList = new ArrayList<FontFamily>();
// Note that the default typeface is always present in the fallback list;
@@ -289,6 +393,7 @@ public class Typeface {
familyList.add(makeFamilyFromParsed(f));
}
}
+
sFallbackFonts = familyList.toArray(new FontFamily[familyList.size()]);
setDefault(Typeface.createFromFamilies(sFallbackFonts));
@@ -324,22 +429,58 @@ public class Typeface {
Log.w(TAG, "Didn't create default family (most likely, non-Minikin build)", e);
// TODO: normal in non-Minikin case, remove or make error when Minikin-only
} catch (FileNotFoundException e) {
- Log.e(TAG, "Error opening " + configFilename);
+ Log.e(TAG, "Error opening " + configFile, e);
} catch (IOException e) {
- Log.e(TAG, "Error reading " + configFilename);
+ Log.e(TAG, "Error reading " + configFile, e);
} catch (XmlPullParserException e) {
- Log.e(TAG, "XML parse exception for " + configFilename);
+ Log.e(TAG, "XML parse exception for " + configFile, e);
}
}
+ /** @hide */
+ public static void recreateDefaults() {
+ recreateDefaults(false);
+ }
+
+ /**
+ * Clears caches in java and skia.
+ * Skia will then reparse font config
+ * @hide
+ */
+ public static void recreateDefaults(boolean forceSystemFonts) {
+ sTypefaceCache.clear();
+ sSystemFontMap.clear();
+ init(forceSystemFonts);
+
+ DEFAULT_INTERNAL = create((String) null, 0);
+ DEFAULT_BOLD_INTERNAL = create((String) null, Typeface.BOLD);
+ SANS_SERIF_INTERNAL = create("sans-serif", 0);
+ SERIF_INTERNAL = create("serif", 0);
+ MONOSPACE_INTERNAL = create("monospace", 0);
+
+ DEFAULT.native_instance = DEFAULT_INTERNAL.native_instance;
+ DEFAULT_BOLD.native_instance = DEFAULT_BOLD_INTERNAL.native_instance;
+ SANS_SERIF.native_instance = SANS_SERIF_INTERNAL.native_instance;
+ SERIF.native_instance = SERIF_INTERNAL.native_instance;
+ MONOSPACE.native_instance = MONOSPACE_INTERNAL.native_instance;
+ sDefaults[2] = create((String) null, Typeface.ITALIC);
+ sDefaults[3] = create((String) null, Typeface.BOLD_ITALIC);
+ }
+
static {
- init();
+ init(false);
// Set up defaults and typefaces exposed in public API
- DEFAULT = create((String) null, 0);
- DEFAULT_BOLD = create((String) null, Typeface.BOLD);
- SANS_SERIF = create("sans-serif", 0);
- SERIF = create("serif", 0);
- MONOSPACE = create("monospace", 0);
+ DEFAULT_INTERNAL = create((String) null, 0);
+ DEFAULT_BOLD_INTERNAL = create((String) null, Typeface.BOLD);
+ SANS_SERIF_INTERNAL = create("sans-serif", 0);
+ SERIF_INTERNAL = create("serif", 0);
+ MONOSPACE_INTERNAL = create("monospace", 0);
+
+ DEFAULT = new Typeface(DEFAULT_INTERNAL.native_instance);
+ DEFAULT_BOLD = new Typeface(DEFAULT_BOLD_INTERNAL.native_instance);
+ SANS_SERIF = new Typeface(SANS_SERIF_INTERNAL.native_instance);
+ SERIF = new Typeface(SERIF_INTERNAL.native_instance);
+ MONOSPACE = new Typeface(MONOSPACE_INTERNAL.native_instance);
sDefaults = new Typeface[] {
DEFAULT,
@@ -354,6 +495,18 @@ public class Typeface {
return new File("/system/etc/");
}
+ private static File getSystemFontDirLocation() {
+ return new File("/system/fonts/");
+ }
+
+ private static File getThemeFontConfigLocation() {
+ return new File("/data/system/theme/fonts/");
+ }
+
+ private static File getThemeFontDirLocation() {
+ return new File("/data/system/theme/fonts/");
+ }
+
@Override
protected void finalize() throws Throwable {
try {
diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java
index 32af59a..3f1f76a 100644
--- a/graphics/java/android/graphics/drawable/Drawable.java
+++ b/graphics/java/android/graphics/drawable/Drawable.java
@@ -1076,7 +1076,7 @@ public abstract class Drawable {
// drawn to the screen.
if (opts == null) opts = new BitmapFactory.Options();
opts.inScreenDensity = res != null
- ? res.getDisplayMetrics().noncompatDensityDpi : DisplayMetrics.DENSITY_DEVICE;
+ ? res.getDisplayMetrics().noncompatDensityDpi : DisplayMetrics.DENSITY_DEFAULT;
Bitmap bm = BitmapFactory.decodeResourceStream(res, value, is, pad, opts);
if (bm != null) {
byte[] np = bm.getNinePatchChunk();
diff --git a/graphics/tests/localtests/Android.mk b/graphics/tests/localtests/Android.mk
new file mode 100644
index 0000000..0b95ecd
--- /dev/null
+++ b/graphics/tests/localtests/Android.mk
@@ -0,0 +1,18 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+# We only want this apk build for tests.
+LOCAL_MODULE_TAGS := tests
+LOCAL_MODULE := FrameworksGraphicsHostTests
+
+# Include all test java files.
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_JAVA_LIBRARIES := android.test.runner
+#LOCAL_PACKAGE_NAME := FrameworksGraphicsTests
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
+#####################################
+
+
diff --git a/graphics/tests/localtests/src/android/graphics/FontListConverterTest.java b/graphics/tests/localtests/src/android/graphics/FontListConverterTest.java
new file mode 100644
index 0000000..60c9053
--- /dev/null
+++ b/graphics/tests/localtests/src/android/graphics/FontListConverterTest.java
@@ -0,0 +1,280 @@
+/*
+ * Copyright (C) 2014 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.graphics;
+
+import android.graphics.FontListParser.Alias;
+import android.graphics.LegacyFontListParser.Family;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+public class FontListConverterTest extends TestCase {
+ // VALID nameset includes the default name first and
+ // and some other 'aliases' with it.
+ private static final String[] VALID_NAMESET = {
+ "sans-serif",
+ "arial",
+ "helvetica",
+ "tahoma",
+ "verdana"
+ };
+
+ // The correct fileset will have 4 files in
+ // order by type (regular, bold, italic, bolditalic)
+ private static final String[] VALID_FILESET = {
+ "Roboto-Regular.ttf",
+ "Roboto-Bold.ttf",
+ "Roboto-Italic.ttf",
+ "Roboto-BoldItalic.ttf"
+ };
+
+ // The legacy fontlist format considered thin, light, and black styles
+ // each as part of their own familysets. The new format does not, so we need
+ // to provide a test case to adapt this. Note: "condensed" is still considered
+ // to be its own familyset. So we must be careful
+ private static final String[] VALID_ADDITIONAL_STYLE_NAMESET = {
+ "sans-serif-thin"
+ };
+
+ private static final String[] VALID_ADDITIONAL_STYLE_FILESET = {
+ "Roboto-Thin.ttf",
+ "Roboto-ThinItalic.ttf"
+ };
+
+ // thin, light, and black styles are part of the same family but a Roboto "condensed"
+ // or Roboto "slab" would be considered part of a different family. Since the legacy
+ // format would already consider these as a different family, we just have to make sure
+ // they don't get brought back into a common family like thin/light/black
+ private static final String[] VALID_RELATED_FAMILY_NAMESET = {
+ "sans-serif-condensed"
+ };
+
+ private static final String[] VALID_RELATED_FAMILY_FILESET = {
+ "RobotoCondensed-Regular.ttf",
+ "RobotoCondensed-Bold.ttf",
+ "RobotoCondensed-Italic.ttf",
+ "RobotoCondensed-BoldItalic.ttf"
+ };
+
+ // Some typefaces will only have one style.
+ private static final String[] VALID_SINGLE_STYLE_FAMIlY_NAMESET = {
+ "monospace"
+ };
+ private static final String[] VALID_SINGLE_STYLE_FAMIlY_FILESET = {
+ "DroidSansMono.ttf"
+ };
+
+ final String VALID_PATH = "/valid/path/";
+
+ private Family sValidFamily; // eg "sans-serif"
+ private Family sValidAdditionalStyleFamily; // eg "sans-serif-light"
+ private Family sValidRelatedFamily; // eg "sans-serif-condensed"
+ private Family mValidSingleStyleFamily; // eg "monospace" which only uses DroidSansMono.ttf
+
+ protected void setUp() {
+ sValidFamily = new Family();
+ sValidFamily.nameset = new ArrayList<String>(Arrays.asList(VALID_NAMESET));
+ sValidFamily.fileset = new ArrayList<String>(Arrays.asList(VALID_FILESET));
+
+ sValidAdditionalStyleFamily = new Family();
+ sValidAdditionalStyleFamily.nameset =
+ new ArrayList<String>(Arrays.asList(VALID_ADDITIONAL_STYLE_NAMESET));
+ sValidAdditionalStyleFamily.fileset =
+ new ArrayList<String>(Arrays.asList(VALID_ADDITIONAL_STYLE_FILESET));
+
+ sValidRelatedFamily = new Family();
+ sValidRelatedFamily.nameset =
+ new ArrayList<String>(Arrays.asList(VALID_RELATED_FAMILY_NAMESET));
+ sValidRelatedFamily.fileset =
+ new ArrayList<String>(Arrays.asList(VALID_RELATED_FAMILY_FILESET));
+
+ mValidSingleStyleFamily = new Family();
+ }
+
+ @SmallTest
+ public void testValidAdaptedFamilyShouldHaveNameOfNamesetsFirstElement() {
+ FontListConverter adapter = new FontListConverter(sValidFamily, VALID_PATH);
+ FontListParser.Family convertedFamily = adapter.convertFamily(sValidFamily);
+ assertEquals(VALID_NAMESET[0], convertedFamily.name);
+ }
+
+ @SmallTest
+ public void testValidAdaptedFamilyShouldHaveFonts() {
+ FontListConverter adapter = new FontListConverter(sValidFamily, VALID_PATH);
+ FontListParser.Family convertedFamily = adapter.convertFamily(sValidFamily);
+ List<FontListParser.Font> fonts = convertedFamily.fonts;
+ assertEquals(VALID_FILESET.length, fonts.size());
+ }
+
+ @SmallTest
+ public void testValidAdaptedFontsShouldHaveCorrectProperties() {
+ FontListConverter adapter = new FontListConverter(sValidFamily, VALID_PATH);
+ List<FontListParser.Font> fonts = adapter.convertFonts(Arrays.asList(VALID_FILESET));
+
+ assertEquals(VALID_FILESET.length, fonts.size());
+ for(int i=0; i < fonts.size(); i++) {
+ FontListParser.Font font = fonts.get(i);
+ assertEquals(VALID_PATH + VALID_FILESET[i], font.fontName);
+ assertEquals("shouldBeItalic", shouldBeItalic(i), font.isItalic);
+ assertEquals(FontListConverter.WEIGHTS[i], font.weight);
+ }
+ }
+
+ @SmallTest
+ public void testExtraNamesetsShouldConvertToAliases() {
+ List<Family> families = new ArrayList<Family>();
+ families.add(sValidFamily);
+
+ FontListConverter adapter = new FontListConverter(sValidFamily, VALID_PATH);
+ List<FontListParser.Alias> aliases = adapter.createAliases();
+
+ // Be sure the aliases point to the first name in the nameset
+ for(int i = 0; i < aliases.size(); i++) {
+ FontListParser.Alias alias = aliases.get(i);
+ assertEquals(VALID_NAMESET[0], alias.toName);
+ }
+
+ // Be sure the extra namesets are in the alias list
+ for(int i = 1; i < VALID_NAMESET.length; i++) {
+ assertTrue("hasAliasWithName", hasAliasWithName(aliases, VALID_NAMESET[i]));
+ }
+ }
+
+ /**
+ * The legacy format treats thin, light, and black fonts to be different families
+ * The new format treats these as all part of the original
+ * eg sans-serif and sans-serif-thin become one family
+ */
+ @SmallTest
+ public void testAdditionalStylesShouldConvertToSameFamily() {
+ List<Family> families = new ArrayList<Family>();
+ families.add(sValidFamily); //eg "sans-serif"
+ families.add(sValidAdditionalStyleFamily); //eg "sans-serif-light"
+
+ FontListConverter adapter = new FontListConverter(families, VALID_PATH);
+ List<FontListParser.Family> convertedFamilies = adapter.convertFamilies();
+
+ // We started with two similiar families, and now should have one
+ assertEquals(1, convertedFamilies.size());
+
+ // The name of the family should be the base name, no style modifiers
+ // ie "sans-serif" not "sans-serif-light"
+ FontListParser.Family convertedFamily = convertedFamilies.get(0);
+ assertEquals(sValidFamily.nameset.get(0), convertedFamily.name);
+
+ // Verify all the fonts from both families exist now in the converted Family
+ List<String> combinedFileSet = new ArrayList<String>();
+ combinedFileSet.addAll(sValidFamily.fileset);
+ combinedFileSet.addAll(sValidAdditionalStyleFamily.fileset);
+ for(String filename : combinedFileSet) {
+ String fontName = VALID_PATH + filename;
+ assertTrue("hasFontWithName", hasFontWithName(convertedFamily, fontName));
+ }
+ }
+
+ /**
+ * When two families combine, the "varied" family (ie light, light, black) should
+ * have their namesets converted to aliases.
+ * IE sans-serif-light should point to sans-serif because the light family
+ * gets merged to sans-serif
+ */
+ @SmallTest
+ public void testAdditionalStylesNamesShouldBecomeAliases() {
+ List<Family> families = new ArrayList<Family>();
+ families.add(sValidFamily); //eg "sans-serif"
+ families.add(sValidAdditionalStyleFamily); //eg "sans-serif-light"
+
+ FontListConverter adapter = new FontListConverter(families, VALID_PATH);
+ List<Alias> aliases = adapter.createAliases();
+
+ // Subtract 1 from the total length since VALID_NAMESET[0] will be the family name
+ int expectedSize = VALID_NAMESET.length + VALID_ADDITIONAL_STYLE_NAMESET.length - 1;
+ assertEquals(expectedSize, aliases.size());
+
+ // All aliases should point at the base family
+ for(Alias alias : aliases) {
+ assertEquals(VALID_NAMESET[0], alias.toName);
+ }
+
+ // There should be an alias for every name in the merged in family
+ for(String name : VALID_ADDITIONAL_STYLE_NAMESET) {
+ assertTrue("hasAliasWithName", hasAliasWithName(aliases, name));
+ }
+ }
+
+ /**
+ * sans-serif-condensed should not get merged in with sans-serif
+ */
+ @SmallTest
+ public void testSimiliarFontsShouldKeepSameFamily() {
+ List<Family> families = new ArrayList<Family>();
+ families.add(sValidFamily); //eg "sans-serif"
+ families.add(sValidRelatedFamily); //eg "sans-serif-condensed"
+
+ FontListConverter adapter = new FontListConverter(families, VALID_PATH);
+ List<FontListParser.Family> convertedFamilies = adapter.convertFamilies();
+ FontListParser.Family convertedValidFamily =
+ getFontListFamilyWithName(convertedFamilies, VALID_NAMESET[0]);
+ FontListParser.Family convertedRelatedFamily =
+ getFontListFamilyWithName(convertedFamilies, VALID_RELATED_FAMILY_NAMESET[0]);
+
+
+ // Valid family should only have its own fonts. Will fail if these were merged
+ for(String filename : sValidFamily.fileset) {
+ String fontName = VALID_PATH + filename;
+ assertTrue("hasFontWithName", hasFontWithName(convertedValidFamily, fontName));
+ assertFalse("hasFontWIthName", hasFontWithName(convertedRelatedFamily, fontName));
+ }
+
+ // Related family should also only have have its own fonts. Will fail if these were merged
+ for(String filename : sValidRelatedFamily.fileset) {
+ String fontName = VALID_PATH + filename;
+ assertTrue("hasFontWithName", hasFontWithName(convertedRelatedFamily, fontName));
+ assertFalse("hasFontWIthName", hasFontWithName(convertedValidFamily, fontName));
+ }
+ }
+
+ private static boolean hasAliasWithName(List<Alias> aliases, String name) {
+ for (Alias alias : aliases) if (name.equals(alias.name)) return true;
+ return false;
+ }
+
+ private static boolean hasFontWithName(FontListParser.Family family, String name) {
+ for (FontListParser.Font font : family.fonts) {
+ if(font.fontName != null && font.fontName.equals(name)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private static FontListParser.Family getFontListFamilyWithName(
+ List<FontListParser.Family> families, String name) {
+ for(FontListParser.Family family : families) {
+ if (name.equals(family.name)) return family;
+ }
+ return null;
+ }
+
+ private boolean shouldBeItalic(int index) {
+ // Since the fileset format is regular, bold, italic, bolditalic, anything >= 2 is italic
+ return index >= 2;
+ }
+}
diff --git a/graphics/tests/localtests/src/android/graphics/TypefaceTestSuite.java b/graphics/tests/localtests/src/android/graphics/TypefaceTestSuite.java
new file mode 100644
index 0000000..9ef8421
--- /dev/null
+++ b/graphics/tests/localtests/src/android/graphics/TypefaceTestSuite.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.graphics;
+
+import junit.framework.TestSuite;
+
+public class TypefaceTestSuite {
+ public static TestSuite suite() {
+ TestSuite suite = new TestSuite(TypefaceTestSuite.class.getName());
+ suite.addTestSuite(FontListConverterTest.class);
+ return suite;
+ }
+}
diff --git a/include/SeempLog.h b/include/SeempLog.h
new file mode 100644
index 0000000..30ae338
--- /dev/null
+++ b/include/SeempLog.h
@@ -0,0 +1,51 @@
+/*
+
+Copyright (c) 2015, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#include <dlfcn.h>
+
+#define SEEMPLOG_RECORD(api, params) \
+ static bool shouldTryLoad = true; \
+ static void (*seemp_log_record_func)(int type, const char* msg) = NULL; \
+ \
+ if (shouldTryLoad) { \
+ shouldTryLoad = false; \
+ void* libhandle = dlopen("libSeemplog.so", RTLD_NOW); \
+ if (libhandle != NULL) { \
+ *(void**)(&seemp_log_record_func) = \
+ dlsym(libhandle, "seemp_log_record"); \
+ } \
+ } \
+ if (seemp_log_record_func) \
+ seemp_log_record_func(api, params);
+
+
+
diff --git a/include/androidfw/AssetManager.h b/include/androidfw/AssetManager.h
index 0cfd2b1..de10600 100644
--- a/include/androidfw/AssetManager.h
+++ b/include/androidfw/AssetManager.h
@@ -75,6 +75,7 @@ public:
static const char* TARGET_PACKAGE_NAME;
static const char* TARGET_APK_PATH;
static const char* IDMAP_DIR;
+ static const char* APK_EXTENSION;
typedef enum CacheMode {
CACHE_UNKNOWN = 0,
@@ -100,7 +101,14 @@ public:
* newly-added asset source.
*/
bool addAssetPath(const String8& path, int32_t* cookie);
- bool addOverlayPath(const String8& path, int32_t* cookie);
+ bool addOverlayPath(const String8& idmapPath, const String8& overlayApkpath, int32_t* cookie,
+ const String8& resApkPath, const String8& targetPkgPath,
+ const String8& prefixPath);
+ bool addCommonOverlayPath(const String8& path, int32_t* cookie,
+ const String8& resApkPath, const String8& prefixPath);
+ bool addIconPath(const String8& path, int32_t* cookie,
+ const String8& resApkPath, const String8& prefixPath, uint32_t pkgIdOverride);
+ bool removeOverlayPath(const String8& path, int32_t cookie);
/*
* Convenience for adding the standard system assets. Uses the
@@ -230,22 +238,33 @@ public:
* Generate idmap data to translate resources IDs between a package and a
* corresponding overlay package.
*/
- bool createIdmap(const char* targetApkPath, const char* overlayApkPath,
- uint32_t targetCrc, uint32_t overlayCrc, uint32_t** outData, size_t* outSize);
+ bool createIdmap(const char* targetApkPath, const char* overlayApkPath, const char* cache_path,
+ uint32_t targetCrc, uint32_t overlayCrc,
+ time_t targetMtime, time_t overlayMtime,
+ uint32_t** outData, size_t* outSize);
+
+ String8 getBasePackageName(uint32_t index);
private:
struct asset_path
{
- asset_path() : path(""), type(kFileTypeRegular), idmap(""), isSystemOverlay(false) {}
+ asset_path() : path(""), type(kFileTypeRegular), idmap(""), isSystemOverlay(false),
+ pkgIdOverride(0) {}
String8 path;
FileType type;
String8 idmap;
bool isSystemOverlay;
+ String8 prefixPath;
+ String8 resfilePath;
+ String8 resApkPath;
+ uint32_t pkgIdOverride;
};
Asset* openInPathLocked(const char* fileName, AccessMode mode,
const asset_path& path);
Asset* openNonAssetInPathLocked(const char* fileName, AccessMode mode,
+ const asset_path& path, bool usePrefix = true);
+ Asset* openNonAssetInExactPathLocked(const char* fileName, AccessMode mode,
const asset_path& path);
Asset* openInLocaleVendorLocked(const char* fileName, AccessMode mode,
const asset_path& path, const char* locale, const char* vendor);
@@ -256,6 +275,7 @@ private:
const String8& dirName, const String8& fileName);
ZipFileRO* getZipFileLocked(const asset_path& path);
+ ZipFileRO* getZipFileLocked(const String8& path);
Asset* openAssetFromFileLocked(const String8& fileName, AccessMode mode);
Asset* openAssetFromZipLocked(const ZipFileRO* pZipFile,
const ZipEntryRO entry, AccessMode mode, const String8& entryName);
@@ -280,13 +300,17 @@ private:
const ResTable* getResTable(bool required = true) const;
void setLocaleLocked(const char* locale);
void updateResourceParamsLocked() const;
- bool appendPathToResTable(const asset_path& ap) const;
+ bool appendPathToResTable(const asset_path& ap, size_t* entryIdx) const;
Asset* openIdmapLocked(const struct asset_path& ap) const;
void addSystemOverlays(const char* pathOverlaysList, const String8& targetPackagePath,
ResTable* sharedRes, size_t offset) const;
+ String8 getPkgName(const char *apkPath);
+
+ String8 getOverlayResPath(const char* cachePath);
+
class SharedZip : public RefBase {
public:
static sp<SharedZip> get(const String8& path, bool createIfNotPresent = true);
@@ -355,6 +379,8 @@ private:
void addOverlay(const String8& path, const asset_path& overlay);
bool getOverlay(const String8& path, size_t idx, asset_path* out) const;
+
+ void closeZip(const String8& zip);
private:
void closeZip(int idx);
@@ -376,6 +402,9 @@ private:
mutable ResTable* mResources;
ResTable_config* mConfig;
+ String8 mBasePackageName;
+ uint32_t mBasePackageIndex;
+
/*
* Cached data for "loose" files. This lets us avoid poking at the
* filesystem when searching for loose assets. Each entry is the
diff --git a/include/androidfw/AttributeFinder.h b/include/androidfw/AttributeFinder.h
index acf7056..be0f1bd 100644
--- a/include/androidfw/AttributeFinder.h
+++ b/include/androidfw/AttributeFinder.h
@@ -74,6 +74,7 @@ private:
// Package Offsets (best-case, fast look-up).
Iterator mFrameworkStart;
+ Iterator mCMFrameworkStart;
Iterator mAppStart;
// Worst case, we have shared-library resources.
@@ -99,6 +100,9 @@ void BackTrackingAttributeFinder<Derived, Iterator>::jumpToClosestAttribute(cons
case 0x01:
mCurrent = mFrameworkStart;
break;
+ case 0x3f:
+ mCurrent = mCMFrameworkStart;
+ break;
case 0x7f:
mCurrent = mAppStart;
break;
@@ -132,6 +136,9 @@ void BackTrackingAttributeFinder<Derived, Iterator>::markCurrentPackageId(const
case 0x01:
mFrameworkStart = mCurrent;
break;
+ case 0x3f:
+ mCMFrameworkStart = mCurrent;
+ break;
case 0x7f:
mAppStart = mCurrent;
break;
diff --git a/include/androidfw/ResourceTypes.h b/include/androidfw/ResourceTypes.h
index 5130e6c..ae955c6 100644
--- a/include/androidfw/ResourceTypes.h
+++ b/include/androidfw/ResourceTypes.h
@@ -1547,10 +1547,11 @@ public:
status_t add(const void* data, size_t size, const int32_t cookie=-1, bool copyData=false);
status_t add(const void* data, size_t size, const void* idmapData, size_t idmapDataSize,
- const int32_t cookie=-1, bool copyData=false);
+ const int32_t cookie=-1, bool copyData=false, const uint32_t pkgIdOverride=0);
status_t add(Asset* asset, const int32_t cookie=-1, bool copyData=false);
- status_t add(Asset* asset, Asset* idmapAsset, const int32_t cookie=-1, bool copyData=false);
+ status_t add(Asset* asset, Asset* idmapAsset, const int32_t cookie=-1, bool copyData=false,
+ const uint32_t pkgIdOverride=0);
status_t add(ResTable* src);
status_t addEmpty(const int32_t cookie);
@@ -1637,7 +1638,7 @@ public:
void lock() const;
ssize_t getBagLocked(uint32_t resID, const bag_entry** outBag,
- uint32_t* outTypeSpecFlags=NULL) const;
+ uint32_t* outTypeSpecFlags=NULL, bool performMapping=true) const;
void unlock() const;
@@ -1830,10 +1831,11 @@ public:
// NO_ERROR; the caller should not free outData.
status_t createIdmap(const ResTable& overlay,
uint32_t targetCrc, uint32_t overlayCrc,
+ time_t targetMtime, time_t overlayMtime,
const char* targetPath, const char* overlayPath,
void** outData, size_t* outSize) const;
- static const size_t IDMAP_HEADER_SIZE_BYTES = 4 * sizeof(uint32_t) + 2 * 256;
+ static const size_t IDMAP_HEADER_SIZE_BYTES = 6 * sizeof(uint32_t) + 2 * 256;
// Retrieve idmap meta-data.
//
@@ -1844,6 +1846,8 @@ public:
uint32_t* pTargetCrc, uint32_t* pOverlayCrc,
String8* pTargetPath, String8* pOverlayPath);
+ void removeAssetsByCookie(const String8 &packageName, int32_t cookie);
+
void print(bool inclValues) const;
static String8 normalizeForOutput(const char* input);
@@ -1857,20 +1861,26 @@ private:
typedef Vector<Type*> TypeList;
status_t addInternal(const void* data, size_t size, const void* idmapData, size_t idmapDataSize,
- const int32_t cookie, bool copyData);
+ const int32_t cookie, bool copyData, const uint32_t pkgIdOverride);
ssize_t getResourcePackageIndex(uint32_t resID) const;
status_t getEntry(
const PackageGroup* packageGroup, int typeIndex, int entryIndex,
const ResTable_config* config,
- Entry* outEntry) const;
+ Entry* outEntry, const bool performMapping=true) const;
uint32_t findEntry(const PackageGroup* group, ssize_t typeIndex, const char16_t* name,
size_t nameLen, uint32_t* outTypeSpecFlags) const;
status_t parsePackage(
- const ResTable_package* const pkg, const Header* const header);
+ const ResTable_package* const pkg, const Header* const header,
+ const uint32_t pkgIdOverride);
+
+ bool isResTypeAllowed(const char* type) const;
+ bool isDynamicPackageId(const uint32_t pkgId) const;
+ bool isProtectedAttr(uint32_t resID) const;
+ status_t removeIdmappedTypesFromPackageGroup(PackageGroup* packageGroup) const;
void print_value(const Package* pkg, const Res_value& value) const;
diff --git a/include/private/time_genoff.h b/include/private/time_genoff.h
new file mode 100644
index 0000000..4df5680
--- /dev/null
+++ b/include/private/time_genoff.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __TIME_GENOFF_H__
+#define __TIME_GENOFF_H__
+
+/*
+ * Time genoff base -- To be used by the time setter
+ * Reserved bases to be supported later.
+ */
+typedef enum time_bases {
+ ATS_RTC = 0,
+ ATS_TOD,
+ ATS_USER,
+ ATS_SECURE,
+ ATS_RESERVED_1,
+ ATS_RESERVED_2,
+ ATS_RESERVED_3,
+ ATS_GPS,
+ ATS_1X,
+ ATS_RESERVED_4,
+ ATS_WCDMA,
+ ATS_SNTP,
+ ATS_UTC,
+ ATS_MFLO,
+ ATS_INVALID
+} time_bases_type;
+
+/* Time unit -- Unit in which time is set/get */
+typedef enum time_unit {
+ TIME_STAMP, /* Not supported */
+ TIME_MSEC,
+ TIME_SECS,
+ TIME_JULIAN,
+ TIME_20MS_FRAME, /* Not supported */
+ TIME_INVALID
+} time_unit_type;
+
+/* Operation to be done */
+typedef enum time_genoff_opr {
+ T_SET,
+ T_GET,
+ T_MAX
+} time_genoff_opr_type;
+
+/* Structure to be passed as argument to time_genoff_operation() */
+/*
+ * In set/get: ts_val should be assigned memory and then passed.
+ * if time_unit = TIME_MSEC, TIME_SECS then ts_val = (uint64_t *)
+ * if time_unit = TIME_JULIAN then ts_val = (struct tm *)
+ */
+typedef struct time_genoff_info {
+ time_bases_type base; /* Genoff in consideration */
+ void *ts_val; /* Time to be set/get */
+ time_unit_type unit; /* Time unit */
+ time_genoff_opr_type operation; /* Time operation to be done */
+}time_genoff_info_type;
+
+/* API to be called for time get/set operation */
+int time_genoff_operation(time_genoff_info_type *pargs);
+
+#endif /* __TIME_GENOFF_H__ */
diff --git a/include/storage/IMountService.h b/include/storage/IMountService.h
index c3d34d8..b04be8a 100644
--- a/include/storage/IMountService.h
+++ b/include/storage/IMountService.h
@@ -71,6 +71,7 @@ public:
virtual bool getMountedObbPath(const String16& filename, String16& path) = 0;
virtual int32_t decryptStorage(const String16& password) = 0;
virtual int32_t encryptStorage(const String16& password) = 0;
+ virtual int32_t encryptWipeStorage(const String16& password) = 0;
};
// ----------------------------------------------------------------------------
diff --git a/libs/androidfw/AssetManager.cpp b/libs/androidfw/AssetManager.cpp
index 2dc1c96..1add6c3 100644
--- a/libs/androidfw/AssetManager.cpp
+++ b/libs/androidfw/AssetManager.cpp
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2006 The Android Open Source Project
+ * This code has been modified. Portions copyright (C) 2010, T-Mobile USA, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -75,8 +76,13 @@ static const char* kDefaultVendor = "default";
static const char* kAssetsRoot = "assets";
static const char* kAppZipName = NULL; //"classes.jar";
static const char* kSystemAssets = "framework/framework-res.apk";
-static const char* kResourceCache = "resource-cache";
+static const char* kCMSDKAssets = "framework/org.cyanogenmod.platform-res.apk";
static const char* kAndroidManifest = "AndroidManifest.xml";
+static const int kComposedIconAsset = 128;
+
+#ifdef HAVE_ANDROID_OS
+static const char* kResourceCache = "resource-cache";
+#endif
static const char* kExcludeExtension = ".EXCLUDE";
@@ -90,35 +96,9 @@ const char* AssetManager::OVERLAY_DIR = "/vendor/overlay";
const char* AssetManager::TARGET_PACKAGE_NAME = "android";
const char* AssetManager::TARGET_APK_PATH = "/system/framework/framework-res.apk";
const char* AssetManager::IDMAP_DIR = "/data/resource-cache";
+const char* AssetManager::APK_EXTENSION = ".apk";
namespace {
- String8 idmapPathForPackagePath(const String8& pkgPath)
- {
- const char* root = getenv("ANDROID_DATA");
- LOG_ALWAYS_FATAL_IF(root == NULL, "ANDROID_DATA not set");
- String8 path(root);
- path.appendPath(kResourceCache);
-
- char buf[256]; // 256 chars should be enough for anyone...
- strncpy(buf, pkgPath.string(), 255);
- buf[255] = '\0';
- char* filename = buf;
- while (*filename && *filename == '/') {
- ++filename;
- }
- char* p = filename;
- while (*p) {
- if (*p == '/') {
- *p = '@';
- }
- ++p;
- }
- path.appendPath(filename);
- path.append("@idmap");
-
- return path;
- }
-
/*
* Like strdup(), but uses C++ "new" operator instead of malloc.
*/
@@ -152,7 +132,8 @@ int32_t AssetManager::getGlobalCount()
AssetManager::AssetManager(CacheMode cacheMode)
: mLocale(NULL), mVendor(NULL),
mResources(NULL), mConfig(new ResTable_config),
- mCacheMode(cacheMode), mCacheValid(false)
+ mBasePackageIndex(-1), mCacheMode(cacheMode),
+ mCacheValid(false)
{
int count = android_atomic_inc(&gCount) + 1;
if (kIsDebug) {
@@ -224,6 +205,11 @@ bool AssetManager::addAssetPath(const String8& path, int32_t* cookie)
mAssetPaths.add(ap);
+ if (mResources != NULL) {
+ size_t index = mAssetPaths.size() - 1;
+ appendPathToResTable(ap, &index);
+ }
+
// new paths are always added at the end
if (cookie) {
*cookie = static_cast<int32_t>(mAssetPaths.size());
@@ -237,19 +223,37 @@ bool AssetManager::addAssetPath(const String8& path, int32_t* cookie)
}
#endif
- if (mResources != NULL) {
- appendPathToResTable(ap);
- }
-
return true;
}
-bool AssetManager::addOverlayPath(const String8& packagePath, int32_t* cookie)
+/**
+ * packagePath: Path to the APK that contains our overlay
+ * cookie: Set by this method. The caller can use this cookie to refer to the asset path that has
+ * been added.
+ * resApkPath: Path to the overlay's processed and cached resources.
+ * targetPkgPath: Path to the APK we are trying to overlay
+ * prefixPath: This is the base path internal to the overlay APK.
+ * For example, if we have theme "com.redtheme.apk"
+ * with a launcher overlay then this theme will have a structure like this:
+ * assets/
+ * com.android.launcher/
+ * res/
+ * drawable/
+ * foo.png
+ * Our resources.arsc will reference foo.png's path as "res/drawable/foo.png"
+ * so we need "assets/com.android.launcher/" as a prefix
+ */
+bool AssetManager::addOverlayPath(const String8& idmapPath, const String8& overlayPackagePath,
+ int32_t* cookie, const String8& resApkPath, const String8& targetPkgPath,
+ const String8& prefixPath)
{
- const String8 idmapPath = idmapPathForPackagePath(packagePath);
-
AutoMutex _l(mLock);
+ ALOGV("overlayApkPath: %s, idmap Path: %s, resApkPath %s, targetPkgPath: %s",
+ overlayPackagePath.string(), idmapPath.string(),
+ resApkPath.string(),
+ targetPkgPath.string());
+
for (size_t i = 0; i < mAssetPaths.size(); ++i) {
if (mAssetPaths[i].idmap == idmapPath) {
*cookie = static_cast<int32_t>(i + 1);
@@ -273,9 +277,9 @@ bool AssetManager::addOverlayPath(const String8& packagePath, int32_t* cookie)
}
delete idmap;
- if (overlayPath != packagePath) {
+ if (overlayPath != overlayPackagePath) {
ALOGW("idmap file %s inconcistent: expected path %s does not match actual path %s\n",
- idmapPath.string(), packagePath.string(), overlayPath.string());
+ idmapPath.string(), overlayPackagePath.string(), overlayPath.string());
return false;
}
if (access(targetPath.string(), R_OK) != 0) {
@@ -295,32 +299,196 @@ bool AssetManager::addOverlayPath(const String8& packagePath, int32_t* cookie)
oap.path = overlayPath;
oap.type = ::getFileType(overlayPath.string());
oap.idmap = idmapPath;
+ oap.resApkPath = resApkPath;
#if 0
ALOGD("Overlay added: targetPath=%s overlayPath=%s idmapPath=%s\n",
targetPath.string(), overlayPath.string(), idmapPath.string());
#endif
+ oap.prefixPath = prefixPath; //ex: assets/com.foo.bar
mAssetPaths.add(oap);
*cookie = static_cast<int32_t>(mAssetPaths.size());
if (mResources != NULL) {
- appendPathToResTable(oap);
+ size_t index = mAssetPaths.size() - 1;
+ appendPathToResTable(oap, &index);
}
return true;
}
+bool AssetManager::addCommonOverlayPath(const String8& themePackagePath, int32_t* cookie,
+ const String8& resApkPath, const String8& prefixPath)
+{
+ AutoMutex _l(mLock);
+
+ ALOGV("themePackagePath: %s, resApkPath %s, prefixPath %s",
+ themePackagePath.string(), resApkPath.string(), prefixPath.string());
+
+ // Skip if we have it already.
+ for (size_t i = 0; i < mAssetPaths.size(); ++i) {
+ if (mAssetPaths[i].path == themePackagePath && mAssetPaths[i].resApkPath == resApkPath) {
+ *cookie = static_cast<int32_t>(i + 1);
+ return true;
+ }
+ }
+
+ if (access(themePackagePath.string(), R_OK) != 0) {
+ ALOGW("failed to access file %s: %s\n", themePackagePath.string(), strerror(errno));
+ return false;
+ }
+
+ if (access(resApkPath.string(), R_OK) != 0) {
+ ALOGW("failed to access file %s: %s\n", resApkPath.string(), strerror(errno));
+ return false;
+ }
+
+ asset_path oap;
+ oap.path = themePackagePath;
+ oap.type = ::getFileType(themePackagePath.string());
+ oap.resApkPath = resApkPath;
+ oap.prefixPath = prefixPath;
+ mAssetPaths.add(oap);
+ *cookie = static_cast<int32_t>(mAssetPaths.size());
+
+ if (mResources != NULL) {
+ size_t index = mAssetPaths.size() - 1;
+ appendPathToResTable(oap, &index);
+ }
+
+ return true;
+}
+
+/*
+ * packagePath: Path to the APK that contains our icon assets
+ * cookie: Set by this method. The caller can use this cookie to refer to the added asset path.
+ * resApkPath: Path to the icon APK's processed and cached resources.
+ * prefixPath: This is the base path internal to the icon APK.
+ For example, if we have theme "com.redtheme.apk"
+ * assets/
+ * icons/
+ * res/
+ * drawable/
+ * foo.png
+ * Our restable will reference foo.png's path as "res/drawable/foo.png"
+ * so we need "assets/com.android.launcher/" as a prefix
+ * pkgIdOverride: The package id we want to give. This will overridet the id in the res table.
+ * This is necessary for legacy icon packs because they are compiled with the
+ * standard 7F package id.
+*/
+bool AssetManager::addIconPath(const String8& packagePath, int32_t* cookie,
+ const String8& resApkPath, const String8& prefixPath,
+ uint32_t pkgIdOverride)
+{
+ AutoMutex _l(mLock);
+
+ ALOGV("package path: %s, resApkPath %s, prefixPath %s",
+ packagePath.string(),
+ resApkPath.string(), prefixPath.string());
+
+ // Skip if we have it already.
+ for (size_t i = 0; i < mAssetPaths.size(); i++) {
+ if (mAssetPaths[i].path == packagePath && mAssetPaths[i].resApkPath == resApkPath) {
+ *cookie = static_cast<int32_t>(i + 1);
+ return true;
+ }
+ }
+
+ asset_path oap;
+ oap.path = packagePath;
+ oap.type = ::getFileType(packagePath.string());
+ oap.resApkPath = resApkPath;
+ oap.prefixPath = prefixPath;
+ oap.pkgIdOverride = pkgIdOverride;
+ mAssetPaths.add(oap);
+ *cookie = static_cast<int32_t>(mAssetPaths.size());
+
+ if (mResources != NULL) {
+ size_t index = mAssetPaths.size() - 1;
+ appendPathToResTable(oap, &index);
+ }
+
+ return true;
+}
+
+String8 AssetManager::getPkgName(const char *apkPath) {
+ String8 pkgName;
+
+ asset_path ap;
+ ap.type = kFileTypeRegular;
+ ap.path = String8(apkPath);
+
+ ResXMLTree tree;
+
+ Asset* manifestAsset = openNonAssetInPathLocked(kAndroidManifest, Asset::ACCESS_BUFFER, ap);
+ tree.setTo(manifestAsset->getBuffer(true),
+ manifestAsset->getLength());
+ tree.restart();
+
+ size_t len;
+ ResXMLTree::event_code_t code;
+ while ((code=tree.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
+ if (code != ResXMLTree::START_TAG) {
+ continue;
+ }
+ String8 tag(tree.getElementName(&len));
+ if (tag != "manifest") break; //Manifest does not start with <manifest>
+ size_t len;
+ ssize_t idx = tree.indexOfAttribute(NULL, "package");
+ const char16_t* str = tree.getAttributeStringValue(idx, &len);
+ pkgName = (str ? String8(str, len) : String8());
+
+ }
+
+ manifestAsset->close();
+ return pkgName;
+ }
+
+/**
+ * Returns the base package name as defined in the AndroidManifest.xml
+ */
+String8 AssetManager::getBasePackageName(uint32_t index)
+{
+ if (index >= mAssetPaths.size()) return String8::empty();
+
+ if (mBasePackageName.isEmpty() || mBasePackageIndex != index) {
+ mBasePackageName = getPkgName(mAssetPaths[index].path.string());
+ mBasePackageIndex = index;
+ }
+ return mBasePackageName;
+}
+
+String8 AssetManager::getOverlayResPath(const char* cachePath)
+{
+ String8 resPath(cachePath);
+ resPath.append("/");
+ resPath.append("resources");
+ resPath.append(AssetManager::APK_EXTENSION);
+ return resPath;
+}
+
bool AssetManager::createIdmap(const char* targetApkPath, const char* overlayApkPath,
- uint32_t targetCrc, uint32_t overlayCrc, uint32_t** outData, size_t* outSize)
+ const char *cache_path, uint32_t targetCrc, uint32_t overlayCrc,
+ time_t targetMtime, time_t overlayMtime,
+ uint32_t** outData, size_t* outSize)
{
AutoMutex _l(mLock);
const String8 paths[2] = { String8(targetApkPath), String8(overlayApkPath) };
ResTable tables[2];
+ //Our overlay APK might use an external restable
+ String8 resPath = getOverlayResPath(cache_path);
+
for (int i = 0; i < 2; ++i) {
asset_path ap;
ap.type = kFileTypeRegular;
ap.path = paths[i];
- Asset* ass = openNonAssetInPathLocked("resources.arsc", Asset::ACCESS_BUFFER, ap);
+ Asset* ass;
+ if (i == 1 && access(resPath.string(), R_OK) != -1) {
+ ap.path = resPath;
+ ass = openNonAssetInPathLocked("resources.arsc", Asset::ACCESS_BUFFER, ap);
+ } else {
+ ass = openNonAssetInPathLocked("resources.arsc", Asset::ACCESS_BUFFER, ap);
+ }
if (ass == NULL) {
ALOGW("failed to find resources.arsc in %s\n", ap.path.string());
return false;
@@ -328,7 +496,7 @@ bool AssetManager::createIdmap(const char* targetApkPath, const char* overlayApk
tables[i].add(ass);
}
- return tables[0].createIdmap(tables[1], targetCrc, overlayCrc,
+ return tables[0].createIdmap(tables[1], targetCrc, overlayCrc, targetMtime, overlayMtime,
targetApkPath, overlayApkPath, (void**)outData, outSize) == NO_ERROR;
}
@@ -340,7 +508,10 @@ bool AssetManager::addDefaultAssets()
String8 path(root);
path.appendPath(kSystemAssets);
- return addAssetPath(path, NULL);
+ String8 pathCM(root);
+ pathCM.appendPath(kCMSDKAssets);
+
+ return addAssetPath(path, NULL) & addAssetPath(pathCM, NULL);
}
int32_t AssetManager::nextAssetPath(const int32_t cookie) const
@@ -518,6 +689,10 @@ Asset* AssetManager::open(const char* fileName, AccessMode mode)
i--;
ALOGV("Looking for asset '%s' in '%s'\n",
assetName.string(), mAssetPaths.itemAt(i).path.string());
+
+ // Skip theme/icon attached assets
+ if (mAssetPaths.itemAt(i).prefixPath.length() > 0) continue;
+
Asset* pAsset = openNonAssetInPathLocked(assetName.string(), mode, mAssetPaths.itemAt(i));
if (pAsset != NULL) {
return pAsset != kExcludedAsset ? pAsset : NULL;
@@ -551,6 +726,10 @@ Asset* AssetManager::openNonAsset(const char* fileName, AccessMode mode, int32_t
while (i > 0) {
i--;
ALOGV("Looking for non-asset '%s' in '%s'\n", fileName, mAssetPaths.itemAt(i).path.string());
+
+ // Skip theme/icon attached assets
+ if (mAssetPaths.itemAt(i).prefixPath.length() > 0) continue;
+
Asset* pAsset = openNonAssetInPathLocked(
fileName, mode, mAssetPaths.itemAt(i));
if (pAsset != NULL) {
@@ -581,6 +760,16 @@ Asset* AssetManager::openNonAsset(const int32_t cookie, const char* fileName, Ac
if (pAsset != NULL) {
return pAsset != kExcludedAsset ? pAsset : NULL;
}
+ } else if ((size_t)cookie == kComposedIconAsset) {
+ asset_path ap;
+ String8 path(fileName);
+ ap.type = kFileTypeDirectory;
+ ap.path = path.getPathDir();
+ Asset* pAsset = openNonAssetInPathLocked(
+ path.getPathLeaf().string(), mode, ap);
+ if (pAsset != NULL) {
+ return pAsset;
+ }
}
return NULL;
@@ -610,7 +799,7 @@ FileType AssetManager::getFileType(const char* fileName)
return kFileTypeRegular;
}
-bool AssetManager::appendPathToResTable(const asset_path& ap) const {
+bool AssetManager::appendPathToResTable(const asset_path& ap, size_t* entryIdx) const {
// skip those ap's that correspond to system overlays
if (ap.isSystemOverlay) {
return true;
@@ -622,17 +811,20 @@ bool AssetManager::appendPathToResTable(const asset_path& ap) const {
bool onlyEmptyResources = true;
MY_TRACE_BEGIN(ap.path.string());
Asset* idmap = openIdmapLocked(ap);
- size_t nextEntryIdx = mResources->getTableCount();
ALOGV("Looking for resource asset in '%s'\n", ap.path.string());
- if (ap.type != kFileTypeDirectory) {
- if (nextEntryIdx == 0) {
+ if (!ap.resApkPath.isEmpty()) {
+ // Avoid using prefix path in this case since the compiled resApk will simply have resources.arsc in it
+ ass = const_cast<AssetManager*>(this)->openNonAssetInPathLocked("resources.arsc", Asset::ACCESS_BUFFER, ap, false);
+ shared = false;
+ } else if (ap.type != kFileTypeDirectory) {
+ if (*entryIdx == 0) {
// The first item is typically the framework resources,
// which we want to avoid parsing every time.
sharedRes = const_cast<AssetManager*>(this)->
mZipSet.getZipResourceTable(ap.path);
if (sharedRes != NULL) {
// skip ahead the number of system overlay packages preloaded
- nextEntryIdx = sharedRes->getTableCount();
+ *entryIdx += sharedRes->getTableCount() - 1;
}
}
if (sharedRes == NULL) {
@@ -650,20 +842,20 @@ bool AssetManager::appendPathToResTable(const asset_path& ap) const {
}
}
- if (nextEntryIdx == 0 && ass != NULL) {
+ if (*entryIdx == 0 && ass != NULL) {
// If this is the first resource table in the asset
// manager, then we are going to cache it so that we
// can quickly copy it out for others.
ALOGV("Creating shared resources for %s", ap.path.string());
sharedRes = new ResTable();
- sharedRes->add(ass, idmap, nextEntryIdx + 1, false);
+ sharedRes->add(ass, idmap, *entryIdx + 1, false, ap.pkgIdOverride);
#ifdef HAVE_ANDROID_OS
const char* data = getenv("ANDROID_DATA");
LOG_ALWAYS_FATAL_IF(data == NULL, "ANDROID_DATA not set");
String8 overlaysListPath(data);
overlaysListPath.appendPath(kResourceCache);
overlaysListPath.appendPath("overlays.list");
- addSystemOverlays(overlaysListPath.string(), ap.path, sharedRes, nextEntryIdx);
+ addSystemOverlays(overlaysListPath.string(), ap.path, sharedRes, *entryIdx);
#endif
sharedRes = const_cast<AssetManager*>(this)->
mZipSet.setZipResourceTable(ap.path, sharedRes);
@@ -685,7 +877,7 @@ bool AssetManager::appendPathToResTable(const asset_path& ap) const {
mResources->add(sharedRes);
} else {
ALOGV("Parsing resources for %s", ap.path.string());
- mResources->add(ass, idmap, nextEntryIdx + 1, !shared);
+ mResources->add(ass, idmap, *entryIdx + 1, !shared, ap.pkgIdOverride);
}
onlyEmptyResources = false;
@@ -694,7 +886,7 @@ bool AssetManager::appendPathToResTable(const asset_path& ap) const {
}
} else {
ALOGV("Installing empty resources in to table %p\n", mResources);
- mResources->addEmpty(nextEntryIdx + 1);
+ mResources->addEmpty(*entryIdx + 1);
}
if (idmap != NULL) {
@@ -734,7 +926,7 @@ const ResTable* AssetManager::getResTable(bool required) const
bool onlyEmptyResources = true;
const size_t N = mAssetPaths.size();
for (size_t i=0; i<N; i++) {
- bool empty = appendPathToResTable(mAssetPaths.itemAt(i));
+ bool empty = appendPathToResTable(mAssetPaths.itemAt(i), &i);
onlyEmptyResources = onlyEmptyResources && empty;
}
@@ -811,7 +1003,7 @@ void AssetManager::addSystemOverlays(const char* pathOverlaysList,
if (oass != NULL) {
Asset* oidmap = openIdmapLocked(oap);
offset++;
- sharedRes->add(oass, oidmap, offset + 1, false);
+ sharedRes->add(oass, oidmap, offset + 1, false, oap.pkgIdOverride);
const_cast<AssetManager*>(this)->mAssetPaths.add(oap);
const_cast<AssetManager*>(this)->mZipSet.addOverlay(targetPackagePath, oap);
}
@@ -819,6 +1011,32 @@ void AssetManager::addSystemOverlays(const char* pathOverlaysList,
fclose(fin);
}
+bool AssetManager::removeOverlayPath(const String8& packageName, int32_t cookie)
+{
+ AutoMutex _l(mLock);
+
+ const size_t which = ((size_t)cookie)-1;
+ if (which >= mAssetPaths.size()) {
+ ALOGE("cookie was larger than paths size");
+ return false;
+ }
+
+ const asset_path& oap = mAssetPaths.itemAt(which);
+ mZipSet.closeZip(oap.resApkPath);
+
+ mAssetPaths.removeAt(which);
+
+ ResTable* rt = mResources;
+ if (rt == NULL) {
+ ALOGE("Unable to remove overlayPath, ResTable must not be NULL");
+ return false;
+ }
+
+ rt->removeAssetsByCookie(packageName, cookie);
+
+ return true;
+}
+
const ResTable& AssetManager::getResources(bool required) const
{
const ResTable* rt = getResTable(required);
@@ -853,18 +1071,28 @@ void AssetManager::getLocales(Vector<String8>* locales) const
* Open a non-asset file as if it were an asset, searching for it in the
* specified app.
*
+ *
* Pass in a NULL values for "appName" if the common app directory should
* be used.
*/
Asset* AssetManager::openNonAssetInPathLocked(const char* fileName, AccessMode mode,
- const asset_path& ap)
+ const asset_path& ap, bool usePrefix)
{
Asset* pAsset = NULL;
+ // Append asset_path prefix if needed
+ const char* fileNameFinal = fileName;
+ String8 fileNameWithPrefix;
+ if (usePrefix && ap.prefixPath.length() > 0) {
+ fileNameWithPrefix.append(ap.prefixPath);
+ fileNameWithPrefix.append(fileName);
+ fileNameFinal = fileNameWithPrefix.string();
+ }
+
/* look at the filesystem on disk */
if (ap.type == kFileTypeDirectory) {
String8 path(ap.path);
- path.appendPath(fileName);
+ path.appendPath(fileNameFinal);
pAsset = openAssetFromFileLocked(path, mode);
@@ -882,24 +1110,45 @@ Asset* AssetManager::openNonAssetInPathLocked(const char* fileName, AccessMode m
/* look inside the zip file */
} else {
String8 path(fileName);
+ const char* zipPath;
/* check the appropriate Zip file */
- ZipFileRO* pZip = getZipFileLocked(ap);
- if (pZip != NULL) {
- //printf("GOT zip, checking NA '%s'\n", (const char*) path);
- ZipEntryRO entry = pZip->findEntryByName(path.string());
- if (entry != NULL) {
- //printf("FOUND NA in Zip file for %s\n", appName ? appName : kAppCommon);
- pAsset = openAssetFromZipLocked(pZip, entry, mode, path);
- pZip->releaseEntry(entry);
+ ZipFileRO* pZip;
+ ZipEntryRO entry;
+
+ if (!ap.resApkPath.isEmpty()) {
+ pZip = getZipFileLocked(ap.resApkPath);
+ if (pZip != NULL) {
+ //printf("GOT zip, checking NA '%s'\n", (const char*) path);
+ entry = pZip->findEntryByName(path.string());
+ if (entry != NULL) {
+ //printf("FOUND NA in Zip file for %s\n", appName ? appName : kAppCommon);
+ pAsset = openAssetFromZipLocked(pZip, entry, mode, path);
+ zipPath = ap.resApkPath.string();
+ }
+ }
+ }
+
+ if (pAsset == NULL) {
+ path.setTo(fileNameFinal);
+ pZip = getZipFileLocked(ap);
+ if (pZip != NULL) {
+ //printf("GOT zip, checking NA '%s'\n", (const char*) path);
+ ZipEntryRO entry = pZip->findEntryByName(path.string());
+ if (entry != NULL) {
+ //printf("FOUND NA in Zip file for %s\n", appName ? appName : kAppCommon);
+ pAsset = openAssetFromZipLocked(pZip, entry, mode, path);
+ pZip->releaseEntry(entry);
+ zipPath = ap.path.string();
+ }
}
}
if (pAsset != NULL) {
/* create a "source" name, for debug/display */
pAsset->setAssetSource(
- createZipSourceNameLocked(ZipSet::getPathName(ap.path.string()), String8(""),
- String8(fileName)));
+ createZipSourceNameLocked(ZipSet::getPathName(zipPath), String8(""),
+ String8(path.string())));
}
}
@@ -1111,9 +1360,14 @@ String8 AssetManager::createPathNameLocked(const asset_path& ap, const char* roo
*/
ZipFileRO* AssetManager::getZipFileLocked(const asset_path& ap)
{
+ return getZipFileLocked(ap.path);
+}
+
+ZipFileRO* AssetManager::getZipFileLocked(const String8& path)
+{
ALOGV("getZipFileLocked() in %p\n", this);
- return mZipSet.getZip(ap.path);
+ return mZipSet.getZip(path);
}
/*
@@ -1235,6 +1489,10 @@ AssetDir* AssetManager::openDir(const char* dirName)
while (i > 0) {
i--;
const asset_path& ap = mAssetPaths.itemAt(i);
+
+ // Skip theme/icon attached assets
+ if (ap.prefixPath.length() > 0) continue;
+
if (ap.type == kFileTypeRegular) {
ALOGV("Adding directory %s from zip %s", dirName, ap.path.string());
scanAndMergeZipLocked(pMergedInfo, ap, kAssetsRoot, dirName);
@@ -1776,6 +2034,10 @@ void AssetManager::fncScanLocked(SortedVector<AssetDir::FileInfo>* pMergedInfo,
while (i > 0) {
i--;
const asset_path& ap = mAssetPaths.itemAt(i);
+
+ // Skip theme/icon attached assets
+ if (ap.prefixPath.length() > 0) continue;
+
fncScanAndMergeDirLocked(pMergedInfo, ap, NULL, NULL, dirName);
if (mLocale != NULL)
fncScanAndMergeDirLocked(pMergedInfo, ap, mLocale, NULL, dirName);
@@ -2035,6 +2297,10 @@ ZipFileRO* AssetManager::ZipSet::getZip(const String8& path)
return zip->getZip();
}
+void AssetManager::ZipSet::closeZip(const String8& zip) {
+ closeZip(getIndex(zip));
+}
+
Asset* AssetManager::ZipSet::getZipResourceTableAsset(const String8& path)
{
int idx = getIndex(path);
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index 62aabb1..818e1c5 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -60,7 +60,15 @@ namespace android {
#define IDMAP_CURRENT_VERSION 0x00000001
#define APP_PACKAGE_ID 0x7f
+#define CMSDK_PACKAGE_ID 0x3f
#define SYS_PACKAGE_ID 0x01
+#define OVERLAY_APP_PACKAGE_ID 0x61
+#define OVERLAY_SYS_PACKAGE_ID 0x60
+#define OVERLAY_COMMON_PACKAGE_ID 0x5f
+
+// Define attributes from android.R.attr to protect from theme changes
+#define ATTR_WINDOW_NO_TITLE 0x01010056 // windowNoTitle
+#define ATTR_WINDOW_ACTION_BAR 0x010102cd // windowActionBar
static const bool kDebugStringPoolNoisy = false;
static const bool kDebugXMLNoisy = false;
@@ -734,7 +742,7 @@ const char16_t* ResStringPool::stringAt(size_t idx, size_t* u16len) const
}
#else
// We do not want to be in this case when actually running Android.
- ALOGW("CREATING STRING CACHE OF %zu bytes",
+ ALOGV("CREATING STRING CACHE OF %zu bytes",
static_cast<size_t>(mHeader->stringCount*sizeof(char16_t**)));
#endif
mCache = (char16_t**)calloc(mHeader->stringCount, sizeof(char16_t**));
@@ -3038,6 +3046,8 @@ struct ResTable::Entry {
StringPoolRef typeStr;
StringPoolRef keyStr;
+
+ bool isFromOverlay;
};
struct ResTable::Type
@@ -3057,7 +3067,8 @@ struct ResTable::Type
struct ResTable::Package
{
Package(ResTable* _owner, const Header* _header, const ResTable_package* _package)
- : owner(_owner), header(_header), package(_package), typeIdOffset(0) {
+ : owner(_owner), header(_header), package(_package), typeIdOffset(0),
+ pkgIdOverride(0) {
if (dtohs(package->header.headerSize) == sizeof(package)) {
// The package structure is the same size as the definition.
// This means it contains the typeIdOffset field.
@@ -3073,6 +3084,7 @@ struct ResTable::Package
ResStringPool keyStrings;
size_t typeIdOffset;
+ uint32_t pkgIdOverride;
};
// A group of objects describing a particular resource package.
@@ -3087,6 +3099,7 @@ struct ResTable::PackageGroup
, largestTypeId(0)
, bags(NULL)
, dynamicRefTable(static_cast<uint8_t>(_id))
+ , overlayPackage(NULL)
{ }
~PackageGroup() {
@@ -3178,6 +3191,8 @@ struct ResTable::PackageGroup
// by having these tables in a per-package scope rather than
// per-package-group.
DynamicRefTable dynamicRefTable;
+
+ Package* overlayPackage;
};
struct ResTable::bag_set
@@ -3532,7 +3547,7 @@ ResTable::ResTable(const void* data, size_t size, const int32_t cookie, bool cop
{
memset(&mParams, 0, sizeof(mParams));
memset(mPackageMap, 0, sizeof(mPackageMap));
- addInternal(data, size, NULL, 0, cookie, copyData);
+ addInternal(data, size, NULL, 0, cookie, copyData, 0);
LOG_FATAL_IF(mError != NO_ERROR, "Error parsing resource table");
if (kDebugTableSuperNoisy) {
ALOGI("Creating ResTable %p\n", this);
@@ -3553,12 +3568,12 @@ inline ssize_t ResTable::getResourcePackageIndex(uint32_t resID) const
}
status_t ResTable::add(const void* data, size_t size, const int32_t cookie, bool copyData) {
- return addInternal(data, size, NULL, 0, cookie, copyData);
+ return addInternal(data, size, NULL, 0, cookie, copyData, 0);
}
status_t ResTable::add(const void* data, size_t size, const void* idmapData, size_t idmapDataSize,
- const int32_t cookie, bool copyData) {
- return addInternal(data, size, idmapData, idmapDataSize, cookie, copyData);
+ const int32_t cookie, bool copyData, const uint32_t pkgIdOverride) {
+ return addInternal(data, size, idmapData, idmapDataSize, cookie, copyData, pkgIdOverride);
}
status_t ResTable::add(Asset* asset, const int32_t cookie, bool copyData) {
@@ -3568,10 +3583,11 @@ status_t ResTable::add(Asset* asset, const int32_t cookie, bool copyData) {
return UNKNOWN_ERROR;
}
- return addInternal(data, static_cast<size_t>(asset->getLength()), NULL, 0, cookie, copyData);
+ return addInternal(data, static_cast<size_t>(asset->getLength()), NULL, 0, cookie, copyData, 0);
}
-status_t ResTable::add(Asset* asset, Asset* idmapAsset, const int32_t cookie, bool copyData) {
+status_t ResTable::add(Asset* asset, Asset* idmapAsset, const int32_t cookie, bool copyData,
+ const uint32_t pkgIdOverride) {
const void* data = asset->getBuffer(true);
if (data == NULL) {
ALOGW("Unable to get buffer of resource asset file");
@@ -3590,7 +3606,7 @@ status_t ResTable::add(Asset* asset, Asset* idmapAsset, const int32_t cookie, bo
}
return addInternal(data, static_cast<size_t>(asset->getLength()),
- idmapData, idmapSize, cookie, copyData);
+ idmapData, idmapSize, cookie, copyData, pkgIdOverride);
}
status_t ResTable::add(ResTable* src)
@@ -3644,7 +3660,7 @@ status_t ResTable::addEmpty(const int32_t cookie) {
}
status_t ResTable::addInternal(const void* data, size_t dataSize, const void* idmapData, size_t idmapDataSize,
- const int32_t cookie, bool copyData)
+ const int32_t cookie, bool copyData, const uint32_t pkgIdOverride)
{
if (!data) {
return NO_ERROR;
@@ -3747,7 +3763,11 @@ status_t ResTable::addInternal(const void* data, size_t dataSize, const void* id
return (mError=BAD_TYPE);
}
- if (parsePackage((ResTable_package*)chunk, header) != NO_ERROR) {
+ // Warning: If the pkg id will be overriden and there is more than one package in the
+ // resource table then the caller should make sure there are enough unique ids above
+ // pkgIdOverride.
+ uint32_t idOverride = (pkgIdOverride == 0) ? 0 : pkgIdOverride + curPackage;
+ if (parsePackage((ResTable_package*)chunk, header, idOverride) != NO_ERROR) {
return mError;
}
curPackage++;
@@ -4033,8 +4053,27 @@ void ResTable::unlock() const
mLock.unlock();
}
+// Protected attributes are not permitted to be themed. If a theme
+// does try to change a protected attribute it will be overriden
+// by the app's original value.
+const static uint32_t PROTECTED_ATTRS[] = {
+ ATTR_WINDOW_NO_TITLE,
+ ATTR_WINDOW_ACTION_BAR
+};
+
+bool ResTable::isProtectedAttr(uint32_t resID) const
+{
+ int length = sizeof(PROTECTED_ATTRS) / sizeof(PROTECTED_ATTRS[0]);
+ for(int i=0; i < length; i++) {
+ if (PROTECTED_ATTRS[i] == resID) {
+ return true;
+ }
+ }
+ return false;
+}
+
ssize_t ResTable::getBagLocked(uint32_t resID, const bag_entry** outBag,
- uint32_t* outTypeSpecFlags) const
+ uint32_t* outTypeSpecFlags, bool performMapping) const
{
if (mError != NO_ERROR) {
return mError;
@@ -4074,7 +4113,7 @@ ssize_t ResTable::getBagLocked(uint32_t resID, const bag_entry** outBag,
}
// First see if we've already computed this bag...
- if (grp->bags) {
+ if (grp->bags && performMapping) {
bag_set** typeSet = grp->bags->get(t);
if (typeSet) {
bag_set* set = typeSet[e];
@@ -4118,7 +4157,7 @@ ssize_t ResTable::getBagLocked(uint32_t resID, const bag_entry** outBag,
// Now collect all bag attributes
Entry entry;
- status_t err = getEntry(grp, t, e, &mParams, &entry);
+ status_t err = getEntry(grp, t, e, &mParams, &entry, performMapping);
if (err != NO_ERROR) {
return err;
}
@@ -4157,7 +4196,8 @@ ssize_t ResTable::getBagLocked(uint32_t resID, const bag_entry** outBag,
const bag_entry* parentBag;
uint32_t parentTypeSpecFlags = 0;
- const ssize_t NP = getBagLocked(resolvedParent, &parentBag, &parentTypeSpecFlags);
+ const ssize_t NP = getBagLocked(resolvedParent, &parentBag, &parentTypeSpecFlags,
+ (resolvedParent != resID || !entry.isFromOverlay));
const size_t NT = ((NP >= 0) ? NP : 0) + N;
set = (bag_set*)malloc(sizeof(bag_set)+sizeof(bag_entry)*NT);
if (set == NULL) {
@@ -4295,6 +4335,68 @@ ssize_t ResTable::getBagLocked(uint32_t resID, const bag_entry** outBag,
set->numAttrs = curEntry;
}
+ if (entry.isFromOverlay) {
+ const bag_entry* originalBag;
+ uint32_t originalTypeSpecFlags = 0;
+ const ssize_t NO = getBagLocked(resID, &originalBag,
+ &originalTypeSpecFlags, false);
+ if (NO <= 0) {
+ ALOGW("Failed to retrieve original bag for 0x%08x", resID);
+ }
+
+ // Now merge in the original attributes...
+ bag_entry* entries = (bag_entry*)(set+1);
+ size_t curEntry = 0;
+ for (int i = 0; i < NO; i++) {
+ const uint32_t newName = originalBag[i].map.name.ident;
+ bool isInside;
+ uint32_t oldName = 0;
+ curEntry = 0;
+
+ while ((isInside=(curEntry < set->numAttrs))
+ && (oldName=entries[curEntry].map.name.ident) < newName) {
+ curEntry++;
+ }
+
+ if ((!isInside) || oldName != newName) {
+ // This is a new attribute... figure out what to do with it.
+ // Need to alloc more memory...
+ size_t prevEntry = curEntry;
+ curEntry = set->availAttrs;
+ set->availAttrs++;
+ const size_t newAvail = set->availAttrs;
+ set = (bag_set*)realloc(set,
+ sizeof(bag_set)
+ + sizeof(bag_entry)*newAvail);
+ if (set == NULL) {
+ return NO_MEMORY;
+ }
+ entries = (bag_entry*)(set+1);
+ if (isInside) {
+ // Going in the middle, need to make space.
+ memmove(entries+prevEntry+1, entries+prevEntry,
+ sizeof(bag_entry)*(set->numAttrs-prevEntry));
+ }
+
+ bag_entry* cur = entries+curEntry;
+
+ cur->stringBlock = originalBag[i].stringBlock;
+ cur->map.name.ident = originalBag[i].map.name.ident;
+ cur->map.value = originalBag[i].map.value;
+ set->typeSpecFlags |= originalTypeSpecFlags;
+ set->numAttrs = set->availAttrs;
+ } else if (isProtectedAttr(newName)) {
+ // The attribute exists in both the original and the new theme bags,
+ // furthermore it is an attribute we don't wish themers to theme, so
+ // give our current themed bag the same value as the original
+ bag_entry* cur = entries+curEntry;
+ cur->stringBlock = originalBag[i].stringBlock;
+ cur->map.name.ident = originalBag[i].map.name.ident;
+ cur->map.value = originalBag[i].map.value;
+ }
+ }
+ }
+
// And this is it...
typeSet[e] = set;
if (set) {
@@ -5038,7 +5140,7 @@ bool ResTable::stringToValue(Res_value* outValue, String16* outString,
}
uint32_t packageId = Res_GETPACKAGE(rid) + 1;
- if (packageId != APP_PACKAGE_ID && packageId != SYS_PACKAGE_ID) {
+ if (isDynamicPackageId(packageId)) {
outValue->dataType = Res_value::TYPE_DYNAMIC_REFERENCE;
}
outValue->data = rid;
@@ -5059,7 +5161,7 @@ bool ResTable::stringToValue(Res_value* outValue, String16* outString,
outValue->data = rid;
outValue->dataType = Res_value::TYPE_DYNAMIC_REFERENCE;
return true;
- } else if (packageId == APP_PACKAGE_ID || packageId == SYS_PACKAGE_ID) {
+ } else if (!isDynamicPackageId(packageId)) {
// We accept packageId's generated as 0x01 in order to support
// building the android system resources
outValue->data = rid;
@@ -5792,7 +5894,8 @@ bool ResTable::getResourceFlags(uint32_t resID, uint32_t* outFlags) const {
status_t ResTable::getEntry(
const PackageGroup* packageGroup, int typeIndex, int entryIndex,
const ResTable_config* config,
- Entry* outEntry) const
+ Entry* outEntry,
+ const bool performMapping) const
{
const TypeList& typeList = packageGroup->types[typeIndex];
if (typeList.isEmpty()) {
@@ -5808,6 +5911,8 @@ status_t ResTable::getEntry(
ResTable_config bestConfig;
memset(&bestConfig, 0, sizeof(bestConfig));
+ bool currentTypeIsOverlay = false;
+
// Iterate over the Types of each package.
const size_t typeCount = typeList.size();
for (size_t i = 0; i < typeCount; i++) {
@@ -5815,11 +5920,11 @@ status_t ResTable::getEntry(
int realEntryIndex = entryIndex;
int realTypeIndex = typeIndex;
- bool currentTypeIsOverlay = false;
+ currentTypeIsOverlay = false;
// Runtime overlay packages provide a mapping of app resource
// ID to package resource ID.
- if (typeSpec->idmapEntries.hasEntries()) {
+ if (performMapping && typeSpec->idmapEntries.hasEntries()) {
uint16_t overlayEntryIndex;
if (typeSpec->idmapEntries.lookup(entryIndex, &overlayEntryIndex) != NO_ERROR) {
// No such mapping exists
@@ -5831,7 +5936,7 @@ status_t ResTable::getEntry(
}
if (static_cast<size_t>(realEntryIndex) >= typeSpec->entryCount) {
- ALOGW("For resource 0x%08x, entry index(%d) is beyond type entryCount(%d)",
+ ALOGV("For resource 0x%08x, entry index(%d) is beyond type entryCount(%d)",
Res_MAKEID(packageGroup->id - 1, typeIndex, entryIndex),
entryIndex, static_cast<int>(typeSpec->entryCount));
// We should normally abort here, but some legacy apps declare
@@ -5875,7 +5980,7 @@ status_t ResTable::getEntry(
// Check if this one is less specific than the last found. If so,
// we will skip it. We check starting with things we most care
// about to those we least care about.
- if (!thisConfig.isBetterThan(bestConfig, config)) {
+ if (!currentTypeIsOverlay && !thisConfig.isBetterThan(bestConfig, config)) {
if (!currentTypeIsOverlay || thisConfig.compare(bestConfig) != 0) {
continue;
}
@@ -5926,12 +6031,13 @@ status_t ResTable::getEntry(
outEntry->package = bestPackage;
outEntry->typeStr = StringPoolRef(&bestPackage->typeStrings, actualTypeIndex - bestPackage->typeIdOffset);
outEntry->keyStr = StringPoolRef(&bestPackage->keyStrings, dtohl(entry->key.index));
+ outEntry->isFromOverlay = currentTypeIsOverlay;
}
return NO_ERROR;
}
status_t ResTable::parsePackage(const ResTable_package* const pkg,
- const Header* const header)
+ const Header* const header, const uint32_t pkgIdOverride)
{
const uint8_t* base = (const uint8_t*)pkg;
status_t err = validate_chunk(&pkg->header, sizeof(*pkg) - sizeof(pkg->typeIdOffset),
@@ -5965,15 +6071,14 @@ status_t ResTable::parsePackage(const ResTable_package* const pkg,
uint32_t id = dtohl(pkg->id);
KeyedVector<uint8_t, IdmapEntries> idmapEntries;
+ uint8_t targetPackageId = 0;
if (header->resourceIDMap != NULL) {
- uint8_t targetPackageId = 0;
status_t err = parseIdmap(header->resourceIDMap, header->resourceIDMapSize, &targetPackageId, &idmapEntries);
if (err != NO_ERROR) {
ALOGW("Overlay is broken");
return (mError=err);
}
- id = targetPackageId;
}
if (id >= 256) {
@@ -5984,11 +6089,17 @@ status_t ResTable::parsePackage(const ResTable_package* const pkg,
id = mNextPackageId++;
}
+ if (pkgIdOverride != 0) {
+ ALOGV("Overriding pkg id %d with %d", id, pkgIdOverride);
+ id = pkgIdOverride;
+ }
+
PackageGroup* group = NULL;
Package* package = new Package(this, header, pkg);
if (package == NULL) {
return (mError=NO_MEMORY);
}
+ package->pkgIdOverride = pkgIdOverride;
err = package->typeStrings.setTo(base+dtohl(pkg->typeStrings),
header->dataEnd-(base+dtohl(pkg->typeStrings)));
@@ -6043,6 +6154,15 @@ status_t ResTable::parsePackage(const ResTable_package* const pkg,
return (mError=err);
}
+ // Get the target group if this is an overlay
+ PackageGroup* targetGroup = NULL;
+ if (header->resourceIDMap != NULL) {
+ targetGroup = mPackageGroups.itemAt(mPackageMap[targetPackageId] - 1);
+ if (targetGroup != NULL) {
+ targetGroup->overlayPackage = package;
+ }
+ }
+
// Iterate through all chunks.
const ResChunk_header* chunk =
(const ResChunk_header*)(((const uint8_t*)pkg)
@@ -6092,16 +6212,12 @@ status_t ResTable::parsePackage(const ResTable_package* const pkg,
if (newEntryCount > 0) {
uint8_t typeIndex = typeSpec->id - 1;
- ssize_t idmapIndex = idmapEntries.indexOfKey(typeSpec->id);
- if (idmapIndex >= 0) {
- typeIndex = idmapEntries[idmapIndex].targetTypeId() - 1;
- }
TypeList& typeList = group->types.editItemAt(typeIndex);
if (!typeList.isEmpty()) {
const Type* existingType = typeList[0];
- if (existingType->entryCount != newEntryCount && idmapIndex < 0) {
- ALOGW("ResTable_typeSpec entry count inconsistent: given %d, previously %d",
+ if (existingType->entryCount != newEntryCount) {
+ ALOGV("ResTable_typeSpec entry count inconsistent: given %d, previously %d",
(int) newEntryCount, (int) existingType->entryCount);
// We should normally abort here, but some legacy apps declare
// resources in the 'android' package (old bug in AAPT).
@@ -6112,11 +6228,23 @@ status_t ResTable::parsePackage(const ResTable_package* const pkg,
t->typeSpec = typeSpec;
t->typeSpecFlags = (const uint32_t*)(
((const uint8_t*)typeSpec) + dtohs(typeSpec->header.headerSize));
- if (idmapIndex >= 0) {
- t->idmapEntries = idmapEntries[idmapIndex];
- }
typeList.add(t);
group->largestTypeId = max(group->largestTypeId, typeSpec->id);
+
+ // Add this type spec to the targetGroup
+ if (targetGroup != NULL) {
+ ssize_t idmapIndex = idmapEntries.indexOfKey(typeSpec->id);
+ if (idmapIndex >= 0) {
+ typeIndex = idmapEntries[idmapIndex].targetTypeId() - 1;
+ TypeList& typeList = targetGroup->types.editItemAt(typeIndex);
+ Type* t = new Type(header, package, newEntryCount);
+ t->idmapEntries = idmapEntries[idmapIndex];
+ t->typeSpec = typeSpec;
+ t->typeSpecFlags = (const uint32_t*)(
+ ((const uint8_t*)typeSpec) + dtohs(typeSpec->header.headerSize));
+ typeList.add(t);
+ }
+ }
} else {
ALOGV("Skipping empty ResTable_typeSpec for type %d", typeSpec->id);
}
@@ -6160,10 +6288,6 @@ status_t ResTable::parsePackage(const ResTable_package* const pkg,
if (newEntryCount > 0) {
uint8_t typeIndex = type->id - 1;
- ssize_t idmapIndex = idmapEntries.indexOfKey(type->id);
- if (idmapIndex >= 0) {
- typeIndex = idmapEntries[idmapIndex].targetTypeId() - 1;
- }
TypeList& typeList = group->types.editItemAt(typeIndex);
if (typeList.isEmpty()) {
@@ -6191,6 +6315,30 @@ status_t ResTable::parsePackage(const ResTable_package* const pkg,
ALOGI("Adding config to type %d: %s\n", type->id,
thisConfig.toString().string());
}
+
+ // Add this type to the targetGroup
+ if (targetGroup != NULL) {
+ ssize_t idmapIndex = idmapEntries.indexOfKey(type->id);
+ if (idmapIndex >= 0) {
+ typeIndex = idmapEntries[idmapIndex].targetTypeId() - 1;
+ TypeList& typeList = targetGroup->types.editItemAt(typeIndex);
+ if (typeList.isEmpty()) {
+ ALOGE("No TypeSpec for type %d", type->id);
+ return (mError=BAD_TYPE);
+ }
+ Type* t = typeList.editItemAt(typeList.size() - 1);
+ if (newEntryCount != t->entryCount) {
+ ALOGE("ResTable_type entry count inconsistent: given %d, previously %d",
+ (int)newEntryCount, (int)t->entryCount);
+ return (mError=BAD_TYPE);
+ }
+ if (t->package != package) {
+ ALOGE("No TypeSpec for type %d", type->id);
+ return (mError=BAD_TYPE);
+ }
+ t->configs.add(type);
+ }
+ }
} else {
ALOGV("Skipping empty ResTable_type for type %d", type->id);
}
@@ -6232,6 +6380,10 @@ DynamicRefTable::DynamicRefTable(uint8_t packageId)
// Reserved package ids
mLookupTable[APP_PACKAGE_ID] = APP_PACKAGE_ID;
mLookupTable[SYS_PACKAGE_ID] = SYS_PACKAGE_ID;
+ mLookupTable[CMSDK_PACKAGE_ID] = CMSDK_PACKAGE_ID;
+ mLookupTable[OVERLAY_APP_PACKAGE_ID] = OVERLAY_APP_PACKAGE_ID;
+ mLookupTable[OVERLAY_SYS_PACKAGE_ID] = OVERLAY_SYS_PACKAGE_ID;
+ mLookupTable[OVERLAY_COMMON_PACKAGE_ID] = OVERLAY_COMMON_PACKAGE_ID;
}
status_t DynamicRefTable::load(const ResTable_lib_header* const header)
@@ -6310,7 +6462,8 @@ status_t DynamicRefTable::lookupResourceId(uint32_t* resId) const {
uint32_t res = *resId;
size_t packageId = Res_GETPACKAGE(res) + 1;
- if (packageId == APP_PACKAGE_ID) {
+ if (packageId == APP_PACKAGE_ID || packageId == OVERLAY_APP_PACKAGE_ID ||
+ packageId == OVERLAY_SYS_PACKAGE_ID || packageId == OVERLAY_COMMON_PACKAGE_ID) {
// No lookup needs to be done, app package IDs are absolute.
return NO_ERROR;
}
@@ -6362,6 +6515,7 @@ struct IdmapTypeMap {
status_t ResTable::createIdmap(const ResTable& overlay,
uint32_t targetCrc, uint32_t overlayCrc,
+ time_t targetMtime, time_t overlayMtime,
const char* targetPath, const char* overlayPath,
void** outData, size_t* outSize) const
{
@@ -6379,8 +6533,10 @@ status_t ResTable::createIdmap(const ResTable& overlay,
KeyedVector<uint8_t, IdmapTypeMap> map;
- // overlaid packages are assumed to contain only one package group
- const PackageGroup* pg = mPackageGroups[0];
+ // Overlaid packages are assumed to contain only one package group or two package group
+ // as one is "system package(android)", and another is "application package". So we need
+ // to use the last package group to create idmap.
+ const PackageGroup* pg = mPackageGroups[mPackageGroups.size() - 1];
// starting size is header
*outSize = ResTable::IDMAP_HEADER_SIZE_BYTES;
@@ -6393,77 +6549,103 @@ status_t ResTable::createIdmap(const ResTable& overlay,
char16_t tmpName[sizeof(overlayPackageStruct->name)/sizeof(overlayPackageStruct->name[0])];
strcpy16_dtoh(tmpName, overlayPackageStruct->name, sizeof(overlayPackageStruct->name)/sizeof(overlayPackageStruct->name[0]));
const String16 overlayPackage(tmpName);
+ Package* pkg;
+ size_t typeCount;
+ uint32_t pkg_id;
+
+ const uint32_t groupCount = mPackageGroups.size();
+ for (int groupIdx = groupCount - 1; groupIdx >= 0; groupIdx--) {
+ pg = mPackageGroups[groupIdx];
+ pkg = pg->packages[0];
+ typeCount = pg->types.size();
+ pkg_id = pkg->package->id << 24;
+
+ for (size_t typeIndex = 0; typeIndex < typeCount; ++typeIndex) {
+ const TypeList& typeList = pg->types[typeIndex];
+ if (typeList.isEmpty()) {
+ continue;
+ }
- for (size_t typeIndex = 0; typeIndex < pg->types.size(); ++typeIndex) {
- const TypeList& typeList = pg->types[typeIndex];
- if (typeList.isEmpty()) {
- continue;
- }
+ const Type* typeConfigs = typeList[0];
- const Type* typeConfigs = typeList[0];
+ IdmapTypeMap typeMap;
+ typeMap.overlayTypeId = -1;
+ typeMap.entryOffset = 0;
- IdmapTypeMap typeMap;
- typeMap.overlayTypeId = -1;
- typeMap.entryOffset = 0;
+ for (size_t entryIndex = 0; entryIndex < typeConfigs->entryCount; ++entryIndex) {
+ uint32_t resID = Res_MAKEID(pg->id - 1, typeIndex, entryIndex);
+ resource_name resName;
+ if (!this->getResourceName(resID, false, &resName)) {
+ if (typeMap.entryMap.isEmpty()) {
+ typeMap.entryOffset++;
+ }
+ continue;
+ }
- for (size_t entryIndex = 0; entryIndex < typeConfigs->entryCount; ++entryIndex) {
- uint32_t resID = Res_MAKEID(pg->id - 1, typeIndex, entryIndex);
- resource_name resName;
- if (!this->getResourceName(resID, false, &resName)) {
- if (typeMap.entryMap.isEmpty()) {
- typeMap.entryOffset++;
+ // check if resource type is "allowed", if not continue
+ String8 type8;
+ if (resName.type8 != NULL) {
+ type8 = String8(resName.type8, resName.typeLen);
+ } else {
+ type8 = String8(resName.type, resName.typeLen);
+ }
+ if (!isResTypeAllowed(type8.string())) {
+ if (typeMap.entryMap.isEmpty()) {
+ typeMap.entryOffset++;
+ }
+ continue;
}
- continue;
- }
- const String16 overlayType(resName.type, resName.typeLen);
- const String16 overlayName(resName.name, resName.nameLen);
- uint32_t overlayResID = overlay.identifierForName(overlayName.string(),
- overlayName.size(),
- overlayType.string(),
- overlayType.size(),
- overlayPackage.string(),
- overlayPackage.size());
- if (overlayResID == 0) {
- if (typeMap.entryMap.isEmpty()) {
- typeMap.entryOffset++;
+ const String16 overlayType(resName.type, resName.typeLen);
+ const String16 overlayName(resName.name, resName.nameLen);
+ uint32_t overlayResID = overlay.identifierForName(overlayName.string(),
+ overlayName.size(),
+ overlayType.string(),
+ overlayType.size(),
+ overlayPackage.string(),
+ overlayPackage.size());
+ if (overlayResID == 0) {
+ if (typeMap.entryMap.isEmpty()) {
+ typeMap.entryOffset++;
+ }
+ continue;
+ } else {
+ overlayResID = pkg_id | (0x00ffffff & overlayResID);
}
- continue;
- }
- if (typeMap.overlayTypeId == -1) {
- typeMap.overlayTypeId = Res_GETTYPE(overlayResID) + 1;
- }
+ if (typeMap.overlayTypeId == -1) {
+ typeMap.overlayTypeId = Res_GETTYPE(overlayResID) + 1;
+ }
- if (Res_GETTYPE(overlayResID) + 1 != static_cast<size_t>(typeMap.overlayTypeId)) {
- ALOGE("idmap: can't mix type ids in entry map. Resource 0x%08x maps to 0x%08x"
- " but entries should map to resources of type %02zx",
- resID, overlayResID, typeMap.overlayTypeId);
- return BAD_TYPE;
- }
+ if (Res_GETTYPE(overlayResID) + 1 != static_cast<size_t>(typeMap.overlayTypeId)) {
+ ALOGE("idmap: can't mix type ids in entry map. Resource 0x%08x maps to 0x%08x"
+ " but entries should map to resources of type %02zx",
+ resID, overlayResID, typeMap.overlayTypeId);
+ return BAD_TYPE;
+ }
- if (typeMap.entryOffset + typeMap.entryMap.size() < entryIndex) {
- // pad with 0xffffffff's (indicating non-existing entries) before adding this entry
- size_t index = typeMap.entryMap.size();
- size_t numItems = entryIndex - (typeMap.entryOffset + index);
- if (typeMap.entryMap.insertAt(0xffffffff, index, numItems) < 0) {
- return NO_MEMORY;
+ if (typeMap.entryOffset + typeMap.entryMap.size() < entryIndex) {
+ // pad with 0xffffffff's (indicating non-existing entries) before adding this entry
+ size_t index = typeMap.entryMap.size();
+ size_t numItems = entryIndex - (typeMap.entryOffset + index);
+ if (typeMap.entryMap.insertAt(0xffffffff, index, numItems) < 0) {
+ return NO_MEMORY;
+ }
}
+ typeMap.entryMap.add(Res_GETENTRY(overlayResID));
}
- typeMap.entryMap.add(Res_GETENTRY(overlayResID));
- }
- if (!typeMap.entryMap.isEmpty()) {
- if (map.add(static_cast<uint8_t>(typeIndex), typeMap) < 0) {
- return NO_MEMORY;
+ if (!typeMap.entryMap.isEmpty()) {
+ if (map.add(static_cast<uint8_t>(typeIndex), typeMap) < 0) {
+ return NO_MEMORY;
+ }
+ *outSize += (4 * sizeof(uint16_t)) + (typeMap.entryMap.size() * sizeof(uint32_t));
}
- *outSize += (4 * sizeof(uint16_t)) + (typeMap.entryMap.size() * sizeof(uint32_t));
}
}
if (map.isEmpty()) {
ALOGW("idmap: no resources in overlay package present in base package");
- return UNKNOWN_ERROR;
}
if ((*outData = malloc(*outSize)) == NULL) {
@@ -6475,6 +6657,8 @@ status_t ResTable::createIdmap(const ResTable& overlay,
*data++ = htodl(IDMAP_CURRENT_VERSION);
*data++ = htodl(targetCrc);
*data++ = htodl(overlayCrc);
+ *data++ = htodl(targetMtime);
+ *data++ = htodl(overlayMtime);
const char* paths[] = { targetPath, overlayPath };
for (int j = 0; j < 2; ++j) {
char* p = (char*)data;
@@ -6531,14 +6715,107 @@ bool ResTable::getIdmapInfo(const void* idmap, size_t sizeBytes,
*pOverlayCrc = dtohl(map[3]);
}
if (pTargetPath) {
- pTargetPath->setTo(reinterpret_cast<const char*>(map + 4));
+ pTargetPath->setTo(reinterpret_cast<const char*>(map + 6));
}
if (pOverlayPath) {
- pOverlayPath->setTo(reinterpret_cast<const char*>(map + 4 + 256 / sizeof(uint32_t)));
+ pOverlayPath->setTo(reinterpret_cast<const char*>(map + 6 + 256 / sizeof(uint32_t)));
}
return true;
}
+void ResTable::removeAssetsByCookie(const String8& /* packageName */, int32_t cookie)
+{
+ mError = NO_ERROR;
+ size_t pgCount = mPackageGroups.size();
+ for (size_t pgIndex = 0; pgIndex < pgCount; pgIndex++) {
+ PackageGroup* pg = mPackageGroups[pgIndex];
+ size_t pkgCount = pg->packages.size();
+ size_t index = pkgCount;
+ for (size_t pkgIndex = 0; pkgIndex < pkgCount; pkgIndex++) {
+ const Package* pkg = pg->packages[pkgIndex];
+ if (pkg->header->cookie == cookie) {
+ index = pkgIndex;
+ break;
+ }
+ }
+ if (index < pkgCount) {
+ const Package* pkg = pg->packages[index];
+ uint32_t id = dtohl(pkg->package->id);
+ if (pkg->pkgIdOverride != 0) {
+ id = pkg->pkgIdOverride;
+ }
+ if (id != 0 && id < 256 && pkgCount == 1) {
+ mPackageMap[id] = 0;
+ }
+ // Check if this package is being reference in any other groups and remove it
+ size_t N = mPackageGroups.size();
+ for (size_t i = 0; i < N; i++) {
+ PackageGroup* grp = mPackageGroups.itemAt(i);
+ if (grp->overlayPackage == pkg) {
+ removeIdmappedTypesFromPackageGroup(grp);
+ grp->clearBagCache();
+ grp->overlayPackage = NULL;
+ }
+ }
+ if (pkgCount == 1) {
+ mPackageGroups.removeAt(pgIndex);
+ delete pg;
+ } else {
+ pg->packages.removeAt(index);
+ delete pkg;
+ }
+ break;
+ }
+ }
+ size_t N = mHeaders.size();
+ for (size_t i = 0; i < N; i++) {
+ Header* header = mHeaders[i];
+ if (header->cookie == cookie) {
+ if (header->ownedData != NULL) {
+ free(header->ownedData);
+ }
+ mHeaders.removeAt(i);
+ break;
+ }
+ }
+}
+
+bool ResTable::isResTypeAllowed(const char* type) const {
+ if (type == NULL) return false;
+ const char* allowedResources[] = { "color", "dimen", "drawable", "mipmap", "style", "anim" };
+ // ALLOWED_RESOURCE_COUNT should match the number of elements in allowedResources
+ const uint32_t ALLOWED_RESOURCE_COUNT = 6;
+ for (uint32_t i = 0; i < ALLOWED_RESOURCE_COUNT; i++) {
+ if (strstr(type, allowedResources[i]) != NULL) return true;
+ }
+ return false;
+}
+
+bool ResTable::isDynamicPackageId(const uint32_t pkgId) const {
+ return pkgId != APP_PACKAGE_ID && pkgId != SYS_PACKAGE_ID
+ && pkgId != OVERLAY_APP_PACKAGE_ID && pkgId != OVERLAY_SYS_PACKAGE_ID
+ && pkgId != OVERLAY_COMMON_PACKAGE_ID && pkgId != CMSDK_PACKAGE_ID;
+}
+
+status_t ResTable::removeIdmappedTypesFromPackageGroup(PackageGroup* packageGroup) const {
+ for (size_t idx = 0; idx < Res_MAXTYPE; idx++) {
+ const TypeList& typeList = packageGroup->types[idx];
+ if (!typeList.isEmpty()) {
+ TypeList& editTypeList = packageGroup->types.editItemAt(idx);
+ // Iterate over the Types of each package.
+ for (Vector<Type*>::iterator iter = editTypeList.begin();
+ iter != editTypeList.end();) {
+ Type* type = *iter;
+ if (type->idmapEntries.hasEntries()) {
+ iter = editTypeList.erase(iter);
+ } else {
+ ++iter;
+ }
+ }
+ }
+ }
+ return NO_ERROR;
+}
#define CHAR16_TO_CSTR(c16, len) (String8(String16(c16,len)).string())
diff --git a/libs/androidfw/tests/Android.mk b/libs/androidfw/tests/Android.mk
index a353575..2896af6 100644
--- a/libs/androidfw/tests/Android.mk
+++ b/libs/androidfw/tests/Android.mk
@@ -25,11 +25,13 @@ testFiles := \
ByteBucketArray_test.cpp \
Config_test.cpp \
ConfigLocale_test.cpp \
- Idmap_test.cpp \
+ PackageIdOverride_test.cpp \
ResTable_test.cpp \
Split_test.cpp \
TestHelpers.cpp \
Theme_test.cpp \
+ ThemesBags_test.cpp \
+ ThemesIdmap_test.cpp \
TypeWrappers_test.cpp \
ZipUtils_test.cpp
diff --git a/libs/androidfw/tests/Idmap_test.cpp b/libs/androidfw/tests/Idmap_test.cpp
index f50c178..181a7cc 100644
--- a/libs/androidfw/tests/Idmap_test.cpp
+++ b/libs/androidfw/tests/Idmap_test.cpp
@@ -50,7 +50,7 @@ protected:
ASSERT_EQ(NO_ERROR, mTargetTable.add(basic_arsc, basic_arsc_len));
ASSERT_EQ(NO_ERROR, mOverlayTable.add(overlay_arsc, overlay_arsc_len));
char targetName[256] = "com.android.test.basic";
- ASSERT_EQ(NO_ERROR, mTargetTable.createIdmap(mOverlayTable, 0, 0,
+ ASSERT_EQ(NO_ERROR, mTargetTable.createIdmap(mOverlayTable, 0, 0, 0, 0,
targetName, targetName, &mData, &mDataSize));
}
diff --git a/libs/androidfw/tests/PackageIdOverride_test.cpp b/libs/androidfw/tests/PackageIdOverride_test.cpp
new file mode 100644
index 0000000..c1d645f
--- /dev/null
+++ b/libs/androidfw/tests/PackageIdOverride_test.cpp
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (C) 2014 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.
+ */
+
+#include <androidfw/ResourceTypes.h>
+
+#include <utils/String8.h>
+#include <utils/String16.h>
+#include "TestHelpers.h"
+#include "data/cm/override/R.h"
+
+#include <gtest/gtest.h>
+
+using namespace android;
+
+namespace {
+
+#include "data/cm/override/override_arsc.h"
+
+TEST(PackageIdOverrideTest, shouldOverridePackageId) {
+ const uint32_t pkgIdOverride = 0x42;
+ ResTable table;
+ ASSERT_EQ(NO_ERROR, table.add(override_arsc, override_arsc_len, NULL, 0, -1, false,
+ pkgIdOverride));
+
+ Res_value val;
+ // we should not be able to retrieve the resource using the build time package id
+ uint32_t resId = override::R::string::string1;
+ ssize_t block = table.getResource(resId, &val, false);
+ ASSERT_LT(block, 0);
+
+ // now make sure we can access the resource using the runtime package id
+ resId = (override::R::string::string1 & 0x00ffffff) | (pkgIdOverride << 24);
+ block = table.getResource(resId, &val, false);
+ ASSERT_GE(block, 0);
+ ASSERT_EQ(Res_value::TYPE_STRING, val.dataType);
+ const ResStringPool* pool = table.getTableStringBlock(block);
+ ASSERT_TRUE(pool != NULL);
+ ASSERT_LT(val.data, pool->size());
+
+ size_t strLen;
+ const char16_t* targetStr16 = pool->stringAt(val.data, &strLen);
+ ASSERT_TRUE(targetStr16 != NULL);
+ ASSERT_EQ(String16("string1"), String16(targetStr16, strLen));
+}
+
+}
diff --git a/libs/androidfw/tests/ThemesBags_test.cpp b/libs/androidfw/tests/ThemesBags_test.cpp
new file mode 100644
index 0000000..b1d7c19
--- /dev/null
+++ b/libs/androidfw/tests/ThemesBags_test.cpp
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2014 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.
+ */
+
+#include <androidfw/ResourceTypes.h>
+
+#include <utils/String8.h>
+#include <utils/String16.h>
+#include "TestHelpers.h"
+#include "data/cm/system/R.h"
+#include "data/cm/app/R.h"
+#include "data/cm/bags/R.h"
+
+#include <gtest/gtest.h>
+
+using namespace android;
+
+namespace {
+
+/**
+ * Include a binary resource table.
+ *
+ * Package: android
+ */
+#include "data/cm/system/system_arsc.h"
+
+/**
+ * Include a binary resource table.
+ *
+ * Package: com.android.app
+ */
+#include "data/cm/app/app_arsc.h"
+
+/**
+ * Include a binary resource table.
+ * This table is an overlay.
+ *
+ * Package: com.android.test.bags
+ */
+#include "data/cm/bags/bags_arsc.h"
+
+enum { MAY_NOT_BE_BAG = false };
+
+class BagsTest : public ::testing::Test {
+protected:
+ virtual void SetUp() {
+ ASSERT_EQ(NO_ERROR, mTargetTable.add(app_arsc, app_arsc_len));
+ ASSERT_EQ(NO_ERROR, mOverlayTable.add(bags_arsc, bags_arsc_len));
+ char targetName[256] = "com.android.app";
+ ASSERT_EQ(NO_ERROR, mTargetTable.createIdmap(mOverlayTable, 0, 0, 0, 0,
+ targetName, targetName, &mData, &mDataSize));
+ ASSERT_EQ(NO_ERROR, mTargetTable.add(system_arsc, system_arsc_len));
+ }
+
+ virtual void TearDown() {
+ free(mData);
+ }
+
+ ResTable mTargetTable;
+ ResTable mOverlayTable;
+ void* mData;
+ size_t mDataSize;
+};
+
+TEST_F(BagsTest, canLoadIdmap) {
+ ASSERT_EQ(NO_ERROR, mTargetTable.add(bags_arsc, bags_arsc_len, mData, mDataSize));
+}
+
+TEST_F(BagsTest, overlayOverridesStyleAttribute) {
+ ASSERT_EQ(NO_ERROR, mTargetTable.add(bags_arsc, bags_arsc_len, mData, mDataSize));
+
+ ResTable::Theme theme2(mTargetTable);
+ ASSERT_EQ(NO_ERROR, theme2.applyStyle(app::R::style::Theme_Two));
+
+ Res_value val;
+ ASSERT_GE(theme2.getAttribute(android::R::attr::background, &val), 0);
+ ASSERT_EQ(Res_value::TYPE_INT_COLOR_RGB8, val.dataType);
+ ASSERT_EQ(uint32_t(0xff0000ff), val.data);
+}
+
+TEST_F(BagsTest, overlayCanResolveReferencesToOwnPackage) {
+ ASSERT_EQ(NO_ERROR, mTargetTable.add(bags_arsc, bags_arsc_len, mData, mDataSize));
+
+ ResTable::Theme theme2(mTargetTable);
+ ASSERT_EQ(NO_ERROR, theme2.applyStyle(app::R::style::Theme_Two));
+
+ Res_value attr;
+ ssize_t block = theme2.getAttribute(android::R::attr::foreground, &attr);
+ ASSERT_GE(block, 0);
+ ASSERT_EQ(Res_value::TYPE_REFERENCE, attr.dataType);
+ ASSERT_EQ(uint32_t(bags::R::color::magenta), attr.data);
+ Res_value val;
+ block = mTargetTable.getResource(attr.data, &val, false);
+ ASSERT_GE(block, 0);
+ ASSERT_EQ(Res_value::TYPE_INT_COLOR_RGB8, val.dataType);
+ ASSERT_EQ(uint32_t(0xffff00ff), val.data);
+}
+
+TEST_F(BagsTest, overlayCanReferenceOwnStyle) {
+ ASSERT_EQ(NO_ERROR, mTargetTable.add(bags_arsc, bags_arsc_len, mData, mDataSize));
+
+ ResTable::Theme theme3(mTargetTable);
+ ASSERT_EQ(NO_ERROR, theme3.applyStyle(app::R::style::Theme_Three));
+
+ Res_value attr;
+ ssize_t block = theme3.getAttribute(android::R::attr::foreground, &attr);
+ ASSERT_GE(block, 0);
+ ASSERT_EQ(Res_value::TYPE_REFERENCE, attr.dataType);
+ ASSERT_EQ(uint32_t(bags::R::color::cyan), attr.data);
+ Res_value val;
+ block = mTargetTable.getResource(attr.data, &val, false);
+ ASSERT_GE(block, 0);
+ ASSERT_EQ(Res_value::TYPE_INT_COLOR_RGB8, val.dataType);
+ ASSERT_EQ(uint32_t(0xff00ffff), val.data);
+
+ // verify that we still get the parent attribute for background
+ block = theme3.getAttribute(android::R::attr::background, &attr);
+ ASSERT_GE(block, 0);
+ ASSERT_EQ(Res_value::TYPE_INT_COLOR_RGB8, attr.dataType);
+ ASSERT_EQ(uint32_t(0xffff0000), attr.data);
+}
+
+TEST_F(BagsTest, overlaidStyleContainsMissingAttributes) {
+ const uint32_t SOME_DIMEN_VALUE = 0x00003001;
+
+ ASSERT_EQ(NO_ERROR, mTargetTable.add(bags_arsc, bags_arsc_len, mData, mDataSize));
+
+ ResTable::Theme theme(mTargetTable);
+ ASSERT_EQ(NO_ERROR, theme.applyStyle(app::R::style::Theme_Four));
+
+ // First let's make sure we have the themed style by checking the background attribute
+ Res_value attr;
+ ssize_t block = theme.getAttribute(android::R::attr::background, &attr);
+ ASSERT_GE(block, 0);
+ ASSERT_EQ(Res_value::TYPE_INT_COLOR_RGB8, attr.dataType);
+ ASSERT_EQ(uint32_t(0xffaabbcc), attr.data);
+
+ // Now check if the someDimen attribute in the parent was merged in correctly since the theme
+ // does not contain this attribute in the overlaid style
+ block = theme.getAttribute(android::R::attr::some_dimen, &attr);
+ ASSERT_GE(block, 0);
+ ASSERT_EQ(Res_value::TYPE_DIMENSION, attr.dataType);
+ ASSERT_EQ(SOME_DIMEN_VALUE, attr.data);
+}
+
+TEST_F(BagsTest, protectedAttributeNotOverlaid) {
+ ASSERT_EQ(NO_ERROR, mTargetTable.add(bags_arsc, bags_arsc_len, mData, mDataSize));
+
+ ResTable::Theme theme(mTargetTable);
+ ASSERT_EQ(NO_ERROR, theme.applyStyle(app::R::style::Theme_Two));
+ Res_value val;
+ ASSERT_GE(theme.getAttribute(android::R::attr::windowNoTitle, &val), 0);
+ ASSERT_EQ(Res_value::TYPE_INT_BOOLEAN, val.dataType);
+ ASSERT_NE(0, val.data);
+}
+
+}
diff --git a/libs/androidfw/tests/ThemesIdmap_test.cpp b/libs/androidfw/tests/ThemesIdmap_test.cpp
new file mode 100644
index 0000000..50f16c8
--- /dev/null
+++ b/libs/androidfw/tests/ThemesIdmap_test.cpp
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2014 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.
+ */
+
+#include <androidfw/ResourceTypes.h>
+
+#include <utils/String8.h>
+#include <utils/String16.h>
+#include "TestHelpers.h"
+#include "data/cm/basic/R.h"
+
+#include <gtest/gtest.h>
+
+using namespace android;
+
+namespace {
+
+/**
+ * Include a binary resource table.
+ *
+ * Package: com.android.test.basic
+ */
+#include "data/cm/basic/basic_arsc.h"
+
+/**
+ * Include a binary resource table.
+ * This table is an overlay.
+ *
+ * Package: com.android.test.basic
+ */
+#include "data/cm/overlay/overlay_arsc.h"
+
+enum { MAY_NOT_BE_BAG = false };
+
+class IdmapTest : public ::testing::Test {
+protected:
+ virtual void SetUp() {
+ ASSERT_EQ(NO_ERROR, mTargetTable.add(basic_arsc, basic_arsc_len));
+ ASSERT_EQ(NO_ERROR, mOverlayTable.add(overlay_arsc, overlay_arsc_len));
+ char targetName[256] = "com.android.test.basic";
+ ASSERT_EQ(NO_ERROR, mTargetTable.createIdmap(mOverlayTable, 0, 0, 0, 0,
+ targetName, targetName, &mData, &mDataSize));
+ }
+
+ virtual void TearDown() {
+ free(mData);
+ }
+
+ ResTable mTargetTable;
+ ResTable mOverlayTable;
+ void* mData;
+ size_t mDataSize;
+};
+
+TEST_F(IdmapTest, canLoadIdmap) {
+ ASSERT_EQ(NO_ERROR, mTargetTable.add(overlay_arsc, overlay_arsc_len, mData, mDataSize));
+}
+
+TEST_F(IdmapTest, overlayOverridesResourceValue) {
+ Res_value val;
+ ssize_t block = mTargetTable.getResource(base::R::dimen::dimen1, &val, false);
+ ASSERT_GE(block, 0);
+ ASSERT_EQ(Res_value::TYPE_DIMENSION, val.dataType);
+ ASSERT_NE(val.data, 0);
+
+ ASSERT_EQ(NO_ERROR, mTargetTable.add(overlay_arsc, overlay_arsc_len, mData, mDataSize));
+
+ Res_value newVal;
+ ssize_t newBlock = mTargetTable.getResource(base::R::dimen::dimen1, &newVal, false);
+ ASSERT_GE(newBlock, 0);
+ ASSERT_NE(block, newBlock);
+ ASSERT_EQ(Res_value::TYPE_DIMENSION, newVal.dataType);
+ ASSERT_NE(val.data, newVal.data);
+}
+
+TEST_F(IdmapTest, overlaidResourceHasSameName) {
+ ASSERT_EQ(NO_ERROR, mTargetTable.add(overlay_arsc, overlay_arsc_len, mData, mDataSize));
+
+ ResTable::resource_name resName;
+ ASSERT_TRUE(mTargetTable.getResourceName(base::R::drawable::drawable1, false, &resName));
+
+ ASSERT_TRUE(resName.package != NULL);
+ ASSERT_TRUE(resName.type != NULL);
+ ASSERT_TRUE(resName.name != NULL);
+
+ EXPECT_EQ(String16("com.android.test.basic"), String16(resName.package, resName.packageLen));
+ EXPECT_EQ(String16("drawable"), String16(resName.type, resName.typeLen));
+ EXPECT_EQ(String16("drawable1"), String16(resName.name, resName.nameLen));
+}
+
+TEST_F(IdmapTest, overlayDoesNotOverlayStringResource) {
+ Res_value val;
+ ssize_t block = mTargetTable.getResource(base::R::string::test2, &val, false);
+ ASSERT_GE(block, 0);
+ ASSERT_EQ(Res_value::TYPE_STRING, val.dataType);
+ const ResStringPool* pool = mTargetTable.getTableStringBlock(block);
+ ASSERT_TRUE(pool != NULL);
+ ASSERT_LT(val.data, pool->size());
+
+ size_t strLen;
+ const char16_t* targetStr16 = pool->stringAt(val.data, &strLen);
+ ASSERT_TRUE(targetStr16 != NULL);
+ ASSERT_EQ(String16("test2"), String16(targetStr16, strLen));
+
+ ASSERT_EQ(NO_ERROR, mTargetTable.add(overlay_arsc, overlay_arsc_len, mData, mDataSize));
+
+ ssize_t newBlock = mTargetTable.getResource(base::R::string::test2, &val, false);
+ ASSERT_GE(newBlock, 0);
+ ASSERT_EQ(block, newBlock);
+ // the above check should be enough but just to be sure we'll check the string
+ ASSERT_EQ(Res_value::TYPE_STRING, val.dataType);
+ pool = mTargetTable.getTableStringBlock(newBlock);
+ ASSERT_TRUE(pool != NULL);
+ ASSERT_LT(val.data, pool->size());
+
+ targetStr16 = pool->stringAt(val.data, &strLen);
+ ASSERT_TRUE(targetStr16 != NULL);
+ ASSERT_EQ(String16("test2"), String16(targetStr16, strLen));
+}
+
+} // namespace
diff --git a/libs/androidfw/tests/data/app/R.h b/libs/androidfw/tests/data/app/R.h
index 23e68e3..dfae98e 100644
--- a/libs/androidfw/tests/data/app/R.h
+++ b/libs/androidfw/tests/data/app/R.h
@@ -29,6 +29,15 @@ namespace attr {
namespace style {
enum {
Theme_One = 0x7f020000, // default
+ Theme_Two = 0x7f020001, // default
+ Theme_Three = 0x7f020002, // default
+ Theme_Four = 0x7f020003, // default
+ };
+}
+
+namespace color {
+ enum {
+ app_color = 0x7f030000, // default
};
}
diff --git a/libs/androidfw/tests/data/app/app_arsc.h b/libs/androidfw/tests/data/app/app_arsc.h
index d5d9a3b..be8a79a 100644
--- a/libs/androidfw/tests/data/app/app_arsc.h
+++ b/libs/androidfw/tests/data/app/app_arsc.h
@@ -1,8 +1,8 @@
unsigned char app_arsc[] = {
- 0x02, 0x00, 0x0c, 0x00, 0xc4, 0x02, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x0c, 0x00, 0x18, 0x04, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x01, 0x00, 0x1c, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x01, 0x9c, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x01, 0xf0, 0x03, 0x00, 0x00,
0x7f, 0x00, 0x00, 0x00, 0x63, 0x00, 0x6f, 0x00, 0x6d, 0x00, 0x2e, 0x00,
0x61, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x72, 0x00, 0x6f, 0x00, 0x69, 0x00,
0x64, 0x00, 0x2e, 0x00, 0x61, 0x00, 0x70, 0x00, 0x70, 0x00, 0x00, 0x00,
@@ -25,38 +25,67 @@ unsigned char app_arsc[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00,
- 0x02, 0x00, 0x00, 0x00, 0x60, 0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1c, 0x00, 0x40, 0x00, 0x00, 0x00,
- 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x0c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x61, 0x00, 0x74, 0x00, 0x74, 0x00,
- 0x72, 0x00, 0x00, 0x00, 0x05, 0x00, 0x73, 0x00, 0x74, 0x00, 0x79, 0x00,
- 0x6c, 0x00, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1c, 0x00,
- 0x4c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x06, 0x00, 0x6e, 0x00,
- 0x75, 0x00, 0x6d, 0x00, 0x62, 0x00, 0x65, 0x00, 0x72, 0x00, 0x00, 0x00,
- 0x09, 0x00, 0x54, 0x00, 0x68, 0x00, 0x65, 0x00, 0x6d, 0x00, 0x65, 0x00,
- 0x2e, 0x00, 0x4f, 0x00, 0x6e, 0x00, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x02, 0x02, 0x10, 0x00, 0x14, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
- 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x44, 0x00,
- 0x64, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
- 0x48, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10, 0x04, 0x00, 0x00, 0x00,
- 0x02, 0x02, 0x10, 0x00, 0x14, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
- 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x44, 0x00,
- 0x64, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
- 0x48, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00,
- 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x01, 0x7f, 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00
+ 0x03, 0x00, 0x00, 0x00, 0x70, 0x01, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1c, 0x00, 0x50, 0x00, 0x00, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x0c, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x04, 0x00, 0x61, 0x00,
+ 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x00, 0x00, 0x05, 0x00, 0x73, 0x00,
+ 0x74, 0x00, 0x79, 0x00, 0x6c, 0x00, 0x65, 0x00, 0x00, 0x00, 0x05, 0x00,
+ 0x63, 0x00, 0x6f, 0x00, 0x6c, 0x00, 0x6f, 0x00, 0x72, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x1c, 0x00, 0xb8, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x26, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00,
+ 0x6e, 0x00, 0x00, 0x00, 0x06, 0x00, 0x6e, 0x00, 0x75, 0x00, 0x6d, 0x00,
+ 0x62, 0x00, 0x65, 0x00, 0x72, 0x00, 0x00, 0x00, 0x09, 0x00, 0x54, 0x00,
+ 0x68, 0x00, 0x65, 0x00, 0x6d, 0x00, 0x65, 0x00, 0x2e, 0x00, 0x4f, 0x00,
+ 0x6e, 0x00, 0x65, 0x00, 0x00, 0x00, 0x09, 0x00, 0x54, 0x00, 0x68, 0x00,
+ 0x65, 0x00, 0x6d, 0x00, 0x65, 0x00, 0x2e, 0x00, 0x54, 0x00, 0x77, 0x00,
+ 0x6f, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x54, 0x00, 0x68, 0x00, 0x65, 0x00,
+ 0x6d, 0x00, 0x65, 0x00, 0x2e, 0x00, 0x54, 0x00, 0x68, 0x00, 0x72, 0x00,
+ 0x65, 0x00, 0x65, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x54, 0x00, 0x68, 0x00,
+ 0x65, 0x00, 0x6d, 0x00, 0x65, 0x00, 0x2e, 0x00, 0x46, 0x00, 0x6f, 0x00,
+ 0x75, 0x00, 0x72, 0x00, 0x00, 0x00, 0x09, 0x00, 0x61, 0x00, 0x70, 0x00,
+ 0x70, 0x00, 0x5f, 0x00, 0x63, 0x00, 0x6f, 0x00, 0x6c, 0x00, 0x6f, 0x00,
+ 0x72, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x14, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x02, 0x44, 0x00, 0x64, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10,
+ 0x04, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x20, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x02, 0x44, 0x00, 0xc4, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x1c, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x01,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x7f, 0x08, 0x00, 0x00, 0x10,
+ 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x7f,
+ 0x08, 0x00, 0x00, 0x10, 0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x01, 0x7f, 0x08, 0x00, 0x00, 0x10, 0x03, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x01,
+ 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x01, 0x08, 0x00, 0x00, 0x05,
+ 0x01, 0x30, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x14, 0x00, 0x00, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x02, 0x44, 0x00, 0x58, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x08, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x1d,
+ 0xff, 0xff, 0xff, 0xff
};
-unsigned int app_arsc_len = 708;
+unsigned int app_arsc_len = 1048;
diff --git a/libs/androidfw/tests/data/app/res/values/values.xml b/libs/androidfw/tests/data/app/res/values/values.xml
index c1cf64c..a31e65b 100644
--- a/libs/androidfw/tests/data/app/res/values/values.xml
+++ b/libs/androidfw/tests/data/app/res/values/values.xml
@@ -16,7 +16,22 @@
<resources>
<attr name="number" format="integer"/>
+
<style name="Theme.One" parent="@android:style/Theme.One">
<item name="number">1</item>
</style>
+
+ <style name="Theme.Two" parent="@android:style/Theme.One">
+ <item name="number">2</item>
+ </style>
+
+ <style name="Theme.Three" parent="@android:style/Theme.One">
+ <item name="number">3</item>
+ </style>
+
+ <style name="Theme.Four" parent="@android:style/Theme.One">
+ <item name="android:someDimen">48dp</item>
+ </style>
+
+ <color name="app_color">#ffffff</color>
</resources>
diff --git a/libs/androidfw/tests/data/bags/AndroidManifest.xml b/libs/androidfw/tests/data/bags/AndroidManifest.xml
new file mode 100644
index 0000000..69cf30a
--- /dev/null
+++ b/libs/androidfw/tests/data/bags/AndroidManifest.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.test.bags">
+ <application>
+ </application>
+</manifest>
diff --git a/libs/androidfw/tests/data/bags/R.h b/libs/androidfw/tests/data/bags/R.h
new file mode 100644
index 0000000..bdb9254
--- /dev/null
+++ b/libs/androidfw/tests/data/bags/R.h
@@ -0,0 +1,26 @@
+#ifndef __BAGS_R_H
+#define __BAGS_R_H
+
+namespace bags {
+namespace R {
+
+namespace style {
+ enum {
+ Theme_Two = 0x61020000, // default
+ Theme_Three = 0x61020001, // default
+ Overlay = 0x61020002, // default
+ };
+}
+
+namespace color {
+ enum {
+ app_color = 0x61030000, // default
+ magenta = 0x61030001, // default
+ cyan = 0x61030002, // default
+ };
+}
+
+} // namespace R
+} // namespace bags
+
+#endif // __BAGS_R_H
diff --git a/libs/androidfw/tests/data/bags/bags_arsc.h b/libs/androidfw/tests/data/bags/bags_arsc.h
new file mode 100644
index 0000000..324cd9c
--- /dev/null
+++ b/libs/androidfw/tests/data/bags/bags_arsc.h
@@ -0,0 +1,88 @@
+unsigned char bags_arsc[] = {
+ 0x02, 0x00, 0x0c, 0x00, 0xfc, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x1c, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x01, 0xd4, 0x03, 0x00, 0x00,
+ 0x61, 0x00, 0x00, 0x00, 0x63, 0x00, 0x6f, 0x00, 0x6d, 0x00, 0x2e, 0x00,
+ 0x61, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x72, 0x00, 0x6f, 0x00, 0x69, 0x00,
+ 0x64, 0x00, 0x2e, 0x00, 0x74, 0x00, 0x65, 0x00, 0x73, 0x00, 0x74, 0x00,
+ 0x2e, 0x00, 0x62, 0x00, 0x61, 0x00, 0x67, 0x00, 0x73, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0x70, 0x01, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1c, 0x00, 0x50, 0x00, 0x00, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x0c, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x04, 0x00, 0x61, 0x00,
+ 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x00, 0x00, 0x05, 0x00, 0x73, 0x00,
+ 0x74, 0x00, 0x79, 0x00, 0x6c, 0x00, 0x65, 0x00, 0x00, 0x00, 0x05, 0x00,
+ 0x63, 0x00, 0x6f, 0x00, 0x6c, 0x00, 0x6f, 0x00, 0x72, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x1c, 0x00, 0xc8, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00,
+ 0x30, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x5a, 0x00, 0x00, 0x00,
+ 0x70, 0x00, 0x00, 0x00, 0x82, 0x00, 0x00, 0x00, 0x09, 0x00, 0x54, 0x00,
+ 0x68, 0x00, 0x65, 0x00, 0x6d, 0x00, 0x65, 0x00, 0x2e, 0x00, 0x54, 0x00,
+ 0x77, 0x00, 0x6f, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x54, 0x00, 0x68, 0x00,
+ 0x65, 0x00, 0x6d, 0x00, 0x65, 0x00, 0x2e, 0x00, 0x54, 0x00, 0x68, 0x00,
+ 0x72, 0x00, 0x65, 0x00, 0x65, 0x00, 0x00, 0x00, 0x07, 0x00, 0x4f, 0x00,
+ 0x76, 0x00, 0x65, 0x00, 0x72, 0x00, 0x6c, 0x00, 0x61, 0x00, 0x79, 0x00,
+ 0x00, 0x00, 0x0a, 0x00, 0x54, 0x00, 0x68, 0x00, 0x65, 0x00, 0x6d, 0x00,
+ 0x65, 0x00, 0x2e, 0x00, 0x46, 0x00, 0x6f, 0x00, 0x75, 0x00, 0x72, 0x00,
+ 0x00, 0x00, 0x09, 0x00, 0x61, 0x00, 0x70, 0x00, 0x70, 0x00, 0x5f, 0x00,
+ 0x63, 0x00, 0x6f, 0x00, 0x6c, 0x00, 0x6f, 0x00, 0x72, 0x00, 0x00, 0x00,
+ 0x07, 0x00, 0x6d, 0x00, 0x61, 0x00, 0x67, 0x00, 0x65, 0x00, 0x6e, 0x00,
+ 0x74, 0x00, 0x61, 0x00, 0x00, 0x00, 0x04, 0x00, 0x63, 0x00, 0x79, 0x00,
+ 0x61, 0x00, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x02, 0x02, 0x10, 0x00, 0x20, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x44, 0x00,
+ 0xd0, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x54, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00,
+ 0x44, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x01, 0x03, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x01, 0x01, 0x08, 0x00, 0x00, 0x1d, 0xff, 0x00, 0x00, 0xff,
+ 0x01, 0x00, 0x01, 0x01, 0x08, 0x00, 0x00, 0x01, 0x01, 0x00, 0x03, 0x61,
+ 0x56, 0x00, 0x01, 0x01, 0x08, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x61,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x01,
+ 0x08, 0x00, 0x00, 0x01, 0x02, 0x00, 0x03, 0x61, 0x10, 0x00, 0x01, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x01, 0x01, 0x08, 0x00, 0x00, 0x1d, 0xcc, 0xbb, 0xaa, 0xff,
+ 0x02, 0x02, 0x10, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x44, 0x00, 0x80, 0x00, 0x00, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00,
+ 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
+ 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x1d,
+ 0x00, 0x00, 0x00, 0xff, 0x08, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x08, 0x00, 0x00, 0x1d, 0xff, 0x00, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00,
+ 0x06, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x1d, 0xff, 0xff, 0x00, 0xff
+};
+unsigned int bags_arsc_len = 1020;
diff --git a/libs/androidfw/tests/data/bags/build b/libs/androidfw/tests/data/bags/build
new file mode 100755
index 0000000..9047b18
--- /dev/null
+++ b/libs/androidfw/tests/data/bags/build
@@ -0,0 +1,6 @@
+#!/bin/bash
+
+aapt package -M AndroidManifest.xml -I ../system/bundle.apk -S res -x 97 -F bundle.apk -f && \
+unzip bundle.apk resources.arsc && \
+mv resources.arsc bags.arsc && \
+xxd -i bags.arsc > bags_arsc.h
diff --git a/libs/androidfw/tests/data/bags/res/values/values.xml b/libs/androidfw/tests/data/bags/res/values/values.xml
new file mode 100644
index 0000000..32bcf74
--- /dev/null
+++ b/libs/androidfw/tests/data/bags/res/values/values.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <style name="Theme.Two" parent="@android:style/Theme.One">
+ <item name="android:background">#0000ff</item>
+ <item name="android:foreground">@color/magenta</item>
+ <item name="android:windowNoTitle">false</item>
+ </style>
+
+ <style name="Theme.Three" parent="@style/Overlay"/>
+
+ <style name="Overlay" parent="@android:style/Theme.One">
+ <item name="android:foreground">@color/cyan</item>
+ </style>
+
+ <style name="Theme.Four" parent="@android:style/Theme.One">
+ <item name="android:background">#aabbcc</item>
+ </style>
+
+ <color name="app_color">#000000</color>
+ <color name="magenta">#ff00ff</color>
+ <color name="cyan">#00ffff</color>
+
+</resources>
diff --git a/libs/androidfw/tests/data/basic/basic_arsc.h b/libs/androidfw/tests/data/basic/basic_arsc.h
index 13ab4fa..04712e0 100644
--- a/libs/androidfw/tests/data/basic/basic_arsc.h
+++ b/libs/androidfw/tests/data/basic/basic_arsc.h
@@ -1,9 +1,22 @@
unsigned char basic_arsc[] = {
+<<<<<<< HEAD
0x02, 0x00, 0x0c, 0x00, 0x68, 0x07, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x01, 0x00, 0x1c, 0x00, 0xbc, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00,
0x72, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x13, 0x00, 0x72, 0x00,
+=======
+ 0x02, 0x00, 0x0c, 0x00, 0xf4, 0x08, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x1c, 0x00, 0xf8, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00,
+ 0x62, 0x00, 0x00, 0x00, 0xaa, 0x00, 0x00, 0x00, 0xb8, 0x00, 0x00, 0x00,
+ 0x1a, 0x00, 0x72, 0x00, 0x65, 0x00, 0x73, 0x00, 0x2f, 0x00, 0x64, 0x00,
+ 0x72, 0x00, 0x61, 0x00, 0x77, 0x00, 0x61, 0x00, 0x62, 0x00, 0x6c, 0x00,
+ 0x65, 0x00, 0x2f, 0x00, 0x64, 0x00, 0x72, 0x00, 0x61, 0x00, 0x77, 0x00,
+ 0x61, 0x00, 0x62, 0x00, 0x6c, 0x00, 0x65, 0x00, 0x31, 0x00, 0x2e, 0x00,
+ 0x70, 0x00, 0x6e, 0x00, 0x67, 0x00, 0x00, 0x00, 0x13, 0x00, 0x72, 0x00,
+>>>>>>> 6e133f1... Themes: Port to CM12 [1/6]
0x65, 0x00, 0x73, 0x00, 0x2f, 0x00, 0x6c, 0x00, 0x61, 0x00, 0x79, 0x00,
0x6f, 0x00, 0x75, 0x00, 0x74, 0x00, 0x2f, 0x00, 0x6d, 0x00, 0x61, 0x00,
0x69, 0x00, 0x6e, 0x00, 0x2e, 0x00, 0x78, 0x00, 0x6d, 0x00, 0x6c, 0x00,
@@ -16,7 +29,11 @@ unsigned char basic_arsc[] = {
0x00, 0x00, 0x05, 0x00, 0x74, 0x00, 0x65, 0x00, 0x73, 0x00, 0x74, 0x00,
0x31, 0x00, 0x00, 0x00, 0x05, 0x00, 0x74, 0x00, 0x65, 0x00, 0x73, 0x00,
0x74, 0x00, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x01,
+<<<<<<< HEAD
0xa0, 0x06, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x63, 0x00, 0x6f, 0x00,
+=======
+ 0xf0, 0x07, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x63, 0x00, 0x6f, 0x00,
+>>>>>>> 6e133f1... Themes: Port to CM12 [1/6]
0x6d, 0x00, 0x2e, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x72, 0x00,
0x6f, 0x00, 0x69, 0x00, 0x64, 0x00, 0x2e, 0x00, 0x74, 0x00, 0x65, 0x00,
0x73, 0x00, 0x74, 0x00, 0x2e, 0x00, 0x62, 0x00, 0x61, 0x00, 0x73, 0x00,
@@ -38,76 +55,129 @@ unsigned char basic_arsc[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x20, 0x01, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0xb0, 0x01, 0x00, 0x00,
- 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1c, 0x00,
- 0x90, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00,
- 0x2c, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00,
- 0x04, 0x00, 0x61, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x00, 0x00,
- 0x06, 0x00, 0x6c, 0x00, 0x61, 0x00, 0x79, 0x00, 0x6f, 0x00, 0x75, 0x00,
- 0x74, 0x00, 0x00, 0x00, 0x06, 0x00, 0x73, 0x00, 0x74, 0x00, 0x72, 0x00,
- 0x69, 0x00, 0x6e, 0x00, 0x67, 0x00, 0x00, 0x00, 0x07, 0x00, 0x69, 0x00,
- 0x6e, 0x00, 0x74, 0x00, 0x65, 0x00, 0x67, 0x00, 0x65, 0x00, 0x72, 0x00,
- 0x00, 0x00, 0x05, 0x00, 0x73, 0x00, 0x74, 0x00, 0x79, 0x00, 0x6c, 0x00,
- 0x65, 0x00, 0x00, 0x00, 0x05, 0x00, 0x61, 0x00, 0x72, 0x00, 0x72, 0x00,
- 0x61, 0x00, 0x79, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1c, 0x00,
- 0xec, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00,
- 0x28, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00,
- 0x56, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00,
- 0x88, 0x00, 0x00, 0x00, 0x05, 0x00, 0x61, 0x00, 0x74, 0x00, 0x74, 0x00,
- 0x72, 0x00, 0x31, 0x00, 0x00, 0x00, 0x05, 0x00, 0x61, 0x00, 0x74, 0x00,
- 0x74, 0x00, 0x72, 0x00, 0x32, 0x00, 0x00, 0x00, 0x04, 0x00, 0x6d, 0x00,
- 0x61, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x00, 0x00, 0x05, 0x00, 0x74, 0x00,
- 0x65, 0x00, 0x73, 0x00, 0x74, 0x00, 0x31, 0x00, 0x00, 0x00, 0x05, 0x00,
- 0x74, 0x00, 0x65, 0x00, 0x73, 0x00, 0x74, 0x00, 0x32, 0x00, 0x00, 0x00,
- 0x07, 0x00, 0x6e, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x62, 0x00, 0x65, 0x00,
- 0x72, 0x00, 0x31, 0x00, 0x00, 0x00, 0x07, 0x00, 0x6e, 0x00, 0x75, 0x00,
- 0x6d, 0x00, 0x62, 0x00, 0x65, 0x00, 0x72, 0x00, 0x32, 0x00, 0x00, 0x00,
- 0x06, 0x00, 0x54, 0x00, 0x68, 0x00, 0x65, 0x00, 0x6d, 0x00, 0x65, 0x00,
- 0x31, 0x00, 0x00, 0x00, 0x06, 0x00, 0x54, 0x00, 0x68, 0x00, 0x65, 0x00,
- 0x6d, 0x00, 0x65, 0x00, 0x32, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x69, 0x00,
- 0x6e, 0x00, 0x74, 0x00, 0x65, 0x00, 0x67, 0x00, 0x65, 0x00, 0x72, 0x00,
- 0x41, 0x00, 0x72, 0x00, 0x72, 0x00, 0x61, 0x00, 0x79, 0x00, 0x31, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00,
- 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x44, 0x00, 0x84, 0x00, 0x00, 0x00,
- 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00,
- 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x20, 0x01, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0xd8, 0x01, 0x00, 0x00,
+ 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1c, 0x00,
+ 0xb8, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
+ 0x30, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00,
+ 0x60, 0x00, 0x00, 0x00, 0x6e, 0x00, 0x00, 0x00, 0x04, 0x00, 0x61, 0x00,
+ 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x00, 0x00, 0x08, 0x00, 0x64, 0x00,
+ 0x72, 0x00, 0x61, 0x00, 0x77, 0x00, 0x61, 0x00, 0x62, 0x00, 0x6c, 0x00,
+ 0x65, 0x00, 0x00, 0x00, 0x06, 0x00, 0x6c, 0x00, 0x61, 0x00, 0x79, 0x00,
+ 0x6f, 0x00, 0x75, 0x00, 0x74, 0x00, 0x00, 0x00, 0x06, 0x00, 0x73, 0x00,
+ 0x74, 0x00, 0x72, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x67, 0x00, 0x00, 0x00,
+ 0x07, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x74, 0x00, 0x65, 0x00, 0x67, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x00, 0x00, 0x05, 0x00, 0x73, 0x00, 0x74, 0x00,
+ 0x79, 0x00, 0x6c, 0x00, 0x65, 0x00, 0x00, 0x00, 0x05, 0x00, 0x61, 0x00,
+ 0x72, 0x00, 0x72, 0x00, 0x61, 0x00, 0x79, 0x00, 0x00, 0x00, 0x05, 0x00,
+ 0x64, 0x00, 0x69, 0x00, 0x6d, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x1c, 0x00, 0x2c, 0x01, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00,
+ 0x1c, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00,
+ 0x4c, 0x00, 0x00, 0x00, 0x5a, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00,
+ 0x7e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x00, 0x00,
+ 0xbc, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0x05, 0x00, 0x61, 0x00,
+ 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x31, 0x00, 0x00, 0x00, 0x05, 0x00,
+ 0x61, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x32, 0x00, 0x00, 0x00,
+ 0x09, 0x00, 0x64, 0x00, 0x72, 0x00, 0x61, 0x00, 0x77, 0x00, 0x61, 0x00,
+ 0x62, 0x00, 0x6c, 0x00, 0x65, 0x00, 0x31, 0x00, 0x00, 0x00, 0x04, 0x00,
+ 0x6d, 0x00, 0x61, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x00, 0x00, 0x05, 0x00,
+ 0x74, 0x00, 0x65, 0x00, 0x73, 0x00, 0x74, 0x00, 0x31, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x74, 0x00, 0x65, 0x00, 0x73, 0x00, 0x74, 0x00, 0x32, 0x00,
+ 0x00, 0x00, 0x07, 0x00, 0x6e, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x62, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x31, 0x00, 0x00, 0x00, 0x07, 0x00, 0x6e, 0x00,
+ 0x75, 0x00, 0x6d, 0x00, 0x62, 0x00, 0x65, 0x00, 0x72, 0x00, 0x32, 0x00,
+ 0x00, 0x00, 0x06, 0x00, 0x54, 0x00, 0x68, 0x00, 0x65, 0x00, 0x6d, 0x00,
+ 0x65, 0x00, 0x31, 0x00, 0x00, 0x00, 0x06, 0x00, 0x54, 0x00, 0x68, 0x00,
+ 0x65, 0x00, 0x6d, 0x00, 0x65, 0x00, 0x32, 0x00, 0x00, 0x00, 0x0d, 0x00,
+ 0x69, 0x00, 0x6e, 0x00, 0x74, 0x00, 0x65, 0x00, 0x67, 0x00, 0x65, 0x00,
+ 0x72, 0x00, 0x41, 0x00, 0x72, 0x00, 0x72, 0x00, 0x61, 0x00, 0x79, 0x00,
+ 0x31, 0x00, 0x00, 0x00, 0x06, 0x00, 0x64, 0x00, 0x69, 0x00, 0x6d, 0x00,
+ 0x65, 0x00, 0x6e, 0x00, 0x31, 0x00, 0x00, 0x00, 0x06, 0x00, 0x64, 0x00,
+ 0x69, 0x00, 0x6d, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x32, 0x00, 0x00, 0x00,
+ 0x02, 0x02, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x02, 0x44, 0x00, 0x84, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x1c, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x08, 0x00, 0x00, 0x10, 0x05, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10, 0x05, 0x00, 0x00, 0x00,
- 0x10, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10,
- 0x05, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x14, 0x00, 0x00, 0x00,
- 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x24, 0x00, 0x00,
- 0x01, 0x02, 0x44, 0x00, 0x58, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x02, 0x02, 0x10, 0x00, 0x14, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x44, 0x00,
+ 0x58, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x48, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00,
+ 0x02, 0x02, 0x10, 0x00, 0x14, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x04, 0x24, 0x00, 0x00, 0x01, 0x02, 0x44, 0x00,
+ 0x58, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x48, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x03, 0x01, 0x00, 0x00, 0x00,
+ 0x01, 0x02, 0x44, 0x00, 0x58, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x66, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x58, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x03,
+ 0x02, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x44, 0x00, 0x6c, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00,
+ 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x08, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x03,
- 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x44, 0x00, 0x58, 0x00, 0x00, 0x00,
- 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00,
- 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x72, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x03, 0x03, 0x00, 0x00, 0x00,
+ 0x08, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x03,
+ 0x04, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x44, 0x00, 0x6c, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00,
+ 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0x02, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+<<<<<<< HEAD
0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
0x08, 0x00, 0x00, 0x03, 0x01, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00,
0x1c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 0x02, 0x44, 0x00, 0x70, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
0x03, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
+=======
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+ 0x06, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x10, 0xc8, 0x00, 0x00, 0x00,
+ 0x08, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x07, 0x7f, 0x01, 0x02, 0x44, 0x00, 0x5c, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00,
+ 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x73, 0x76, 0x00, 0x00,
+>>>>>>> 6e133f1... Themes: Port to CM12 [1/6]
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00,
+ 0x06, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x10, 0x90, 0x01, 0x00, 0x00,
+ 0x02, 0x02, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x02, 0x44, 0x00, 0x90, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x10, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00,
0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x03, 0x02, 0x00, 0x00, 0x00,
@@ -120,6 +190,7 @@ unsigned char basic_arsc[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+<<<<<<< HEAD
0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
0x05, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x10, 0xc8, 0x00, 0x00, 0x00,
0x08, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x01,
@@ -138,6 +209,30 @@ unsigned char basic_arsc[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+=======
+ 0x28, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00, 0x08, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x7f,
+ 0x08, 0x00, 0x00, 0x10, 0x64, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x7f,
+ 0x08, 0x00, 0x00, 0x01, 0x00, 0x00, 0x05, 0x7f, 0x10, 0x00, 0x01, 0x00,
+ 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x7f, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x01, 0x7f, 0x08, 0x00, 0x00, 0x10, 0x2c, 0x01, 0x00, 0x00,
+ 0x02, 0x02, 0x10, 0x00, 0x14, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x44, 0x00,
+ 0x7c, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x48, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00,
+ 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x02, 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x02, 0x08, 0x00, 0x00, 0x10, 0x02, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x02, 0x08, 0x00, 0x00, 0x10, 0x03, 0x00, 0x00, 0x00,
+ 0x02, 0x02, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x02, 0x44, 0x00, 0x6c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
+>>>>>>> 6e133f1... Themes: Port to CM12 [1/6]
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x28, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00, 0x07, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x7f,
@@ -152,6 +247,7 @@ unsigned char basic_arsc[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+<<<<<<< HEAD
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00,
0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x02, 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00,
@@ -159,3 +255,10 @@ unsigned char basic_arsc[] = {
0x02, 0x00, 0x00, 0x02, 0x08, 0x00, 0x00, 0x10, 0x03, 0x00, 0x00, 0x00
};
unsigned int basic_arsc_len = 1896;
+=======
+ 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00,
+ 0x08, 0x00, 0x00, 0x05, 0x01, 0x30, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+ 0x0c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x05, 0x00, 0x10, 0x00, 0x00
+};
+unsigned int basic_arsc_len = 2292;
+>>>>>>> 6e133f1... Themes: Port to CM12 [1/6]
diff --git a/libs/androidfw/tests/data/basic/res/drawable/drawable1.png b/libs/androidfw/tests/data/basic/res/drawable/drawable1.png
new file mode 100644
index 0000000..94660d3
--- /dev/null
+++ b/libs/androidfw/tests/data/basic/res/drawable/drawable1.png
Binary files differ
diff --git a/libs/androidfw/tests/data/basic/res/values/values.xml b/libs/androidfw/tests/data/basic/res/values/values.xml
index a010cca..cc41f9b 100644
--- a/libs/androidfw/tests/data/basic/res/values/values.xml
+++ b/libs/androidfw/tests/data/basic/res/values/values.xml
@@ -38,4 +38,7 @@
<item>2</item>
<item>3</item>
</integer-array>
+
+ <dimen name="dimen1">48dp</dimen>
+ <dimen name="dimen2">16px</dimen>
</resources>
diff --git a/libs/androidfw/tests/data/cm/app/AndroidManifest.xml b/libs/androidfw/tests/data/cm/app/AndroidManifest.xml
new file mode 100644
index 0000000..bfa3a39
--- /dev/null
+++ b/libs/androidfw/tests/data/cm/app/AndroidManifest.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.app">
+</manifest>
diff --git a/libs/androidfw/tests/data/cm/app/R.h b/libs/androidfw/tests/data/cm/app/R.h
new file mode 100644
index 0000000..fd91728
--- /dev/null
+++ b/libs/androidfw/tests/data/cm/app/R.h
@@ -0,0 +1,31 @@
+#ifndef __APP_R_H
+#define __APP_R_H
+
+namespace app {
+namespace R {
+
+namespace attr {
+ enum {
+ number = 0x7f010000, // default
+ };
+}
+
+namespace style {
+ enum {
+ Theme_One = 0x7f020000, // default
+ Theme_Two = 0x7f020001, // default
+ Theme_Three = 0x7f020002, // default
+ Theme_Four = 0x7f020003, // default
+ };
+}
+
+namespace color {
+ enum {
+ app_color = 0x7f030000, // default
+ };
+}
+
+} // namespace R
+} // namespace app
+
+#endif // __APP_R_H
diff --git a/libs/androidfw/tests/data/cm/app/app_arsc.h b/libs/androidfw/tests/data/cm/app/app_arsc.h
new file mode 100644
index 0000000..be8a79a
--- /dev/null
+++ b/libs/androidfw/tests/data/cm/app/app_arsc.h
@@ -0,0 +1,91 @@
+unsigned char app_arsc[] = {
+ 0x02, 0x00, 0x0c, 0x00, 0x18, 0x04, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x1c, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x01, 0xf0, 0x03, 0x00, 0x00,
+ 0x7f, 0x00, 0x00, 0x00, 0x63, 0x00, 0x6f, 0x00, 0x6d, 0x00, 0x2e, 0x00,
+ 0x61, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x72, 0x00, 0x6f, 0x00, 0x69, 0x00,
+ 0x64, 0x00, 0x2e, 0x00, 0x61, 0x00, 0x70, 0x00, 0x70, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0x70, 0x01, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1c, 0x00, 0x50, 0x00, 0x00, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x0c, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x04, 0x00, 0x61, 0x00,
+ 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x00, 0x00, 0x05, 0x00, 0x73, 0x00,
+ 0x74, 0x00, 0x79, 0x00, 0x6c, 0x00, 0x65, 0x00, 0x00, 0x00, 0x05, 0x00,
+ 0x63, 0x00, 0x6f, 0x00, 0x6c, 0x00, 0x6f, 0x00, 0x72, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x1c, 0x00, 0xb8, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x26, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00,
+ 0x6e, 0x00, 0x00, 0x00, 0x06, 0x00, 0x6e, 0x00, 0x75, 0x00, 0x6d, 0x00,
+ 0x62, 0x00, 0x65, 0x00, 0x72, 0x00, 0x00, 0x00, 0x09, 0x00, 0x54, 0x00,
+ 0x68, 0x00, 0x65, 0x00, 0x6d, 0x00, 0x65, 0x00, 0x2e, 0x00, 0x4f, 0x00,
+ 0x6e, 0x00, 0x65, 0x00, 0x00, 0x00, 0x09, 0x00, 0x54, 0x00, 0x68, 0x00,
+ 0x65, 0x00, 0x6d, 0x00, 0x65, 0x00, 0x2e, 0x00, 0x54, 0x00, 0x77, 0x00,
+ 0x6f, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x54, 0x00, 0x68, 0x00, 0x65, 0x00,
+ 0x6d, 0x00, 0x65, 0x00, 0x2e, 0x00, 0x54, 0x00, 0x68, 0x00, 0x72, 0x00,
+ 0x65, 0x00, 0x65, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x54, 0x00, 0x68, 0x00,
+ 0x65, 0x00, 0x6d, 0x00, 0x65, 0x00, 0x2e, 0x00, 0x46, 0x00, 0x6f, 0x00,
+ 0x75, 0x00, 0x72, 0x00, 0x00, 0x00, 0x09, 0x00, 0x61, 0x00, 0x70, 0x00,
+ 0x70, 0x00, 0x5f, 0x00, 0x63, 0x00, 0x6f, 0x00, 0x6c, 0x00, 0x6f, 0x00,
+ 0x72, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x14, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x02, 0x44, 0x00, 0x64, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10,
+ 0x04, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x20, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x02, 0x44, 0x00, 0xc4, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x1c, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x01,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x7f, 0x08, 0x00, 0x00, 0x10,
+ 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x7f,
+ 0x08, 0x00, 0x00, 0x10, 0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x01, 0x7f, 0x08, 0x00, 0x00, 0x10, 0x03, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x01,
+ 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x01, 0x08, 0x00, 0x00, 0x05,
+ 0x01, 0x30, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x14, 0x00, 0x00, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x02, 0x44, 0x00, 0x58, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x08, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x1d,
+ 0xff, 0xff, 0xff, 0xff
+};
+unsigned int app_arsc_len = 1048;
diff --git a/libs/androidfw/tests/data/cm/app/build b/libs/androidfw/tests/data/cm/app/build
new file mode 100755
index 0000000..89c4641
--- /dev/null
+++ b/libs/androidfw/tests/data/cm/app/build
@@ -0,0 +1,6 @@
+#!/bin/bash
+
+aapt package -v -I ../system/bundle.apk -M AndroidManifest.xml -S res -F bundle.apk -f && \
+unzip bundle.apk resources.arsc && \
+mv resources.arsc app.arsc && \
+xxd -i app.arsc > app_arsc.h
diff --git a/libs/androidfw/tests/data/cm/app/res/values/values.xml b/libs/androidfw/tests/data/cm/app/res/values/values.xml
new file mode 100644
index 0000000..6f11070
--- /dev/null
+++ b/libs/androidfw/tests/data/cm/app/res/values/values.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <attr name="number" format="integer"/>
+
+ <style name="Theme.One" parent="@android:style/Theme.One">
+ <item name="number">1</item>
+ </style>
+
+ <style name="Theme.Two" parent="@android:style/Theme.One">
+ <item name="number">2</item>
+ </style>
+
+ <style name="Theme.Three" parent="@android:style/Theme.One">
+ <item name="number">3</item>
+ </style>
+
+ <style name="Theme.Four" parent="@android:style/Theme.One">
+ <item name="android:someDimen">48dp</item>
+ </style>
+
+ <color name="app_color">#ffffff</color>
+</resources>
diff --git a/libs/androidfw/tests/data/cm/bags/AndroidManifest.xml b/libs/androidfw/tests/data/cm/bags/AndroidManifest.xml
new file mode 100644
index 0000000..69cf30a
--- /dev/null
+++ b/libs/androidfw/tests/data/cm/bags/AndroidManifest.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.test.bags">
+ <application>
+ </application>
+</manifest>
diff --git a/libs/androidfw/tests/data/cm/bags/R.h b/libs/androidfw/tests/data/cm/bags/R.h
new file mode 100644
index 0000000..bdb9254
--- /dev/null
+++ b/libs/androidfw/tests/data/cm/bags/R.h
@@ -0,0 +1,26 @@
+#ifndef __BAGS_R_H
+#define __BAGS_R_H
+
+namespace bags {
+namespace R {
+
+namespace style {
+ enum {
+ Theme_Two = 0x61020000, // default
+ Theme_Three = 0x61020001, // default
+ Overlay = 0x61020002, // default
+ };
+}
+
+namespace color {
+ enum {
+ app_color = 0x61030000, // default
+ magenta = 0x61030001, // default
+ cyan = 0x61030002, // default
+ };
+}
+
+} // namespace R
+} // namespace bags
+
+#endif // __BAGS_R_H
diff --git a/libs/androidfw/tests/data/cm/bags/bags_arsc.h b/libs/androidfw/tests/data/cm/bags/bags_arsc.h
new file mode 100644
index 0000000..324cd9c
--- /dev/null
+++ b/libs/androidfw/tests/data/cm/bags/bags_arsc.h
@@ -0,0 +1,88 @@
+unsigned char bags_arsc[] = {
+ 0x02, 0x00, 0x0c, 0x00, 0xfc, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x1c, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x01, 0xd4, 0x03, 0x00, 0x00,
+ 0x61, 0x00, 0x00, 0x00, 0x63, 0x00, 0x6f, 0x00, 0x6d, 0x00, 0x2e, 0x00,
+ 0x61, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x72, 0x00, 0x6f, 0x00, 0x69, 0x00,
+ 0x64, 0x00, 0x2e, 0x00, 0x74, 0x00, 0x65, 0x00, 0x73, 0x00, 0x74, 0x00,
+ 0x2e, 0x00, 0x62, 0x00, 0x61, 0x00, 0x67, 0x00, 0x73, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0x70, 0x01, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1c, 0x00, 0x50, 0x00, 0x00, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x0c, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x04, 0x00, 0x61, 0x00,
+ 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x00, 0x00, 0x05, 0x00, 0x73, 0x00,
+ 0x74, 0x00, 0x79, 0x00, 0x6c, 0x00, 0x65, 0x00, 0x00, 0x00, 0x05, 0x00,
+ 0x63, 0x00, 0x6f, 0x00, 0x6c, 0x00, 0x6f, 0x00, 0x72, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x1c, 0x00, 0xc8, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00,
+ 0x30, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x5a, 0x00, 0x00, 0x00,
+ 0x70, 0x00, 0x00, 0x00, 0x82, 0x00, 0x00, 0x00, 0x09, 0x00, 0x54, 0x00,
+ 0x68, 0x00, 0x65, 0x00, 0x6d, 0x00, 0x65, 0x00, 0x2e, 0x00, 0x54, 0x00,
+ 0x77, 0x00, 0x6f, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x54, 0x00, 0x68, 0x00,
+ 0x65, 0x00, 0x6d, 0x00, 0x65, 0x00, 0x2e, 0x00, 0x54, 0x00, 0x68, 0x00,
+ 0x72, 0x00, 0x65, 0x00, 0x65, 0x00, 0x00, 0x00, 0x07, 0x00, 0x4f, 0x00,
+ 0x76, 0x00, 0x65, 0x00, 0x72, 0x00, 0x6c, 0x00, 0x61, 0x00, 0x79, 0x00,
+ 0x00, 0x00, 0x0a, 0x00, 0x54, 0x00, 0x68, 0x00, 0x65, 0x00, 0x6d, 0x00,
+ 0x65, 0x00, 0x2e, 0x00, 0x46, 0x00, 0x6f, 0x00, 0x75, 0x00, 0x72, 0x00,
+ 0x00, 0x00, 0x09, 0x00, 0x61, 0x00, 0x70, 0x00, 0x70, 0x00, 0x5f, 0x00,
+ 0x63, 0x00, 0x6f, 0x00, 0x6c, 0x00, 0x6f, 0x00, 0x72, 0x00, 0x00, 0x00,
+ 0x07, 0x00, 0x6d, 0x00, 0x61, 0x00, 0x67, 0x00, 0x65, 0x00, 0x6e, 0x00,
+ 0x74, 0x00, 0x61, 0x00, 0x00, 0x00, 0x04, 0x00, 0x63, 0x00, 0x79, 0x00,
+ 0x61, 0x00, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x02, 0x02, 0x10, 0x00, 0x20, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x44, 0x00,
+ 0xd0, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x54, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00,
+ 0x44, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x01, 0x03, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x01, 0x01, 0x08, 0x00, 0x00, 0x1d, 0xff, 0x00, 0x00, 0xff,
+ 0x01, 0x00, 0x01, 0x01, 0x08, 0x00, 0x00, 0x01, 0x01, 0x00, 0x03, 0x61,
+ 0x56, 0x00, 0x01, 0x01, 0x08, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x61,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x01,
+ 0x08, 0x00, 0x00, 0x01, 0x02, 0x00, 0x03, 0x61, 0x10, 0x00, 0x01, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x01, 0x01, 0x08, 0x00, 0x00, 0x1d, 0xcc, 0xbb, 0xaa, 0xff,
+ 0x02, 0x02, 0x10, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x44, 0x00, 0x80, 0x00, 0x00, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00,
+ 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
+ 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x1d,
+ 0x00, 0x00, 0x00, 0xff, 0x08, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x08, 0x00, 0x00, 0x1d, 0xff, 0x00, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00,
+ 0x06, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x1d, 0xff, 0xff, 0x00, 0xff
+};
+unsigned int bags_arsc_len = 1020;
diff --git a/libs/androidfw/tests/data/cm/bags/build b/libs/androidfw/tests/data/cm/bags/build
new file mode 100755
index 0000000..9047b18
--- /dev/null
+++ b/libs/androidfw/tests/data/cm/bags/build
@@ -0,0 +1,6 @@
+#!/bin/bash
+
+aapt package -M AndroidManifest.xml -I ../system/bundle.apk -S res -x 97 -F bundle.apk -f && \
+unzip bundle.apk resources.arsc && \
+mv resources.arsc bags.arsc && \
+xxd -i bags.arsc > bags_arsc.h
diff --git a/libs/androidfw/tests/data/cm/bags/res/values/values.xml b/libs/androidfw/tests/data/cm/bags/res/values/values.xml
new file mode 100644
index 0000000..32bcf74
--- /dev/null
+++ b/libs/androidfw/tests/data/cm/bags/res/values/values.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <style name="Theme.Two" parent="@android:style/Theme.One">
+ <item name="android:background">#0000ff</item>
+ <item name="android:foreground">@color/magenta</item>
+ <item name="android:windowNoTitle">false</item>
+ </style>
+
+ <style name="Theme.Three" parent="@style/Overlay"/>
+
+ <style name="Overlay" parent="@android:style/Theme.One">
+ <item name="android:foreground">@color/cyan</item>
+ </style>
+
+ <style name="Theme.Four" parent="@android:style/Theme.One">
+ <item name="android:background">#aabbcc</item>
+ </style>
+
+ <color name="app_color">#000000</color>
+ <color name="magenta">#ff00ff</color>
+ <color name="cyan">#00ffff</color>
+
+</resources>
diff --git a/libs/androidfw/tests/data/cm/basic/AndroidManifest.xml b/libs/androidfw/tests/data/cm/basic/AndroidManifest.xml
new file mode 100644
index 0000000..a56ac18
--- /dev/null
+++ b/libs/androidfw/tests/data/cm/basic/AndroidManifest.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.test.basic">
+ <application>
+ </application>
+</manifest>
diff --git a/libs/androidfw/tests/data/cm/basic/R.h b/libs/androidfw/tests/data/cm/basic/R.h
new file mode 100644
index 0000000..36bb1de
--- /dev/null
+++ b/libs/androidfw/tests/data/cm/basic/R.h
@@ -0,0 +1,68 @@
+#ifndef __BASE_R_H
+#define __BASE_R_H
+
+namespace base {
+namespace R {
+
+namespace attr {
+ enum {
+ attr1 = 0x7f010000, // default
+ attr2 = 0x7f010001, // default
+ };
+}
+
+namespace drawable {
+ enum {
+ drawable1 = 0x7f020000, // default
+ };
+}
+
+namespace layout {
+ enum {
+ main = 0x7f030000, // default, fr-sw600dp-v13
+ };
+}
+
+namespace string {
+ enum {
+ test1 = 0x7f040000, // default
+ test2 = 0x7f040001, // default
+
+ test3 = 0x7f0a0000, // default (in feature)
+ test4 = 0x7f0a0001, // default (in feature)
+ };
+}
+
+namespace integer {
+ enum {
+ number1 = 0x7f050000, // default, sv
+ number2 = 0x7f050001, // default
+
+ test3 = 0x7f0b0000, // default (in feature)
+ };
+}
+
+namespace style {
+ enum {
+ Theme1 = 0x7f060000, // default
+ Theme2 = 0x7f060001, // default
+ };
+}
+
+namespace array {
+ enum {
+ integerArray1 = 0x7f070000, // default
+ };
+}
+
+namespace dimen {
+ enum {
+ dimen1 = 0x7f080000, // default
+ dimen2 = 0x7f080001, // default
+ };
+}
+
+} // namespace R
+} // namespace base
+
+#endif // __BASE_R_H
diff --git a/libs/androidfw/tests/data/cm/basic/basic_arsc.h b/libs/androidfw/tests/data/cm/basic/basic_arsc.h
new file mode 100644
index 0000000..370c77c
--- /dev/null
+++ b/libs/androidfw/tests/data/cm/basic/basic_arsc.h
@@ -0,0 +1,194 @@
+unsigned char basic_arsc[] = {
+ 0x02, 0x00, 0x0c, 0x00, 0xf4, 0x08, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x1c, 0x00, 0xf8, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00,
+ 0x62, 0x00, 0x00, 0x00, 0xaa, 0x00, 0x00, 0x00, 0xb8, 0x00, 0x00, 0x00,
+ 0x1a, 0x00, 0x72, 0x00, 0x65, 0x00, 0x73, 0x00, 0x2f, 0x00, 0x64, 0x00,
+ 0x72, 0x00, 0x61, 0x00, 0x77, 0x00, 0x61, 0x00, 0x62, 0x00, 0x6c, 0x00,
+ 0x65, 0x00, 0x2f, 0x00, 0x64, 0x00, 0x72, 0x00, 0x61, 0x00, 0x77, 0x00,
+ 0x61, 0x00, 0x62, 0x00, 0x6c, 0x00, 0x65, 0x00, 0x31, 0x00, 0x2e, 0x00,
+ 0x70, 0x00, 0x6e, 0x00, 0x67, 0x00, 0x00, 0x00, 0x13, 0x00, 0x72, 0x00,
+ 0x65, 0x00, 0x73, 0x00, 0x2f, 0x00, 0x6c, 0x00, 0x61, 0x00, 0x79, 0x00,
+ 0x6f, 0x00, 0x75, 0x00, 0x74, 0x00, 0x2f, 0x00, 0x6d, 0x00, 0x61, 0x00,
+ 0x69, 0x00, 0x6e, 0x00, 0x2e, 0x00, 0x78, 0x00, 0x6d, 0x00, 0x6c, 0x00,
+ 0x00, 0x00, 0x22, 0x00, 0x72, 0x00, 0x65, 0x00, 0x73, 0x00, 0x2f, 0x00,
+ 0x6c, 0x00, 0x61, 0x00, 0x79, 0x00, 0x6f, 0x00, 0x75, 0x00, 0x74, 0x00,
+ 0x2d, 0x00, 0x66, 0x00, 0x72, 0x00, 0x2d, 0x00, 0x73, 0x00, 0x77, 0x00,
+ 0x36, 0x00, 0x30, 0x00, 0x30, 0x00, 0x64, 0x00, 0x70, 0x00, 0x2d, 0x00,
+ 0x76, 0x00, 0x31, 0x00, 0x33, 0x00, 0x2f, 0x00, 0x6d, 0x00, 0x61, 0x00,
+ 0x69, 0x00, 0x6e, 0x00, 0x2e, 0x00, 0x78, 0x00, 0x6d, 0x00, 0x6c, 0x00,
+ 0x00, 0x00, 0x05, 0x00, 0x74, 0x00, 0x65, 0x00, 0x73, 0x00, 0x74, 0x00,
+ 0x31, 0x00, 0x00, 0x00, 0x05, 0x00, 0x74, 0x00, 0x65, 0x00, 0x73, 0x00,
+ 0x74, 0x00, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x01,
+ 0xf0, 0x07, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x63, 0x00, 0x6f, 0x00,
+ 0x6d, 0x00, 0x2e, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x72, 0x00,
+ 0x6f, 0x00, 0x69, 0x00, 0x64, 0x00, 0x2e, 0x00, 0x74, 0x00, 0x65, 0x00,
+ 0x73, 0x00, 0x74, 0x00, 0x2e, 0x00, 0x62, 0x00, 0x61, 0x00, 0x73, 0x00,
+ 0x69, 0x00, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x20, 0x01, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0xd8, 0x01, 0x00, 0x00,
+ 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1c, 0x00,
+ 0xb8, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
+ 0x30, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00,
+ 0x60, 0x00, 0x00, 0x00, 0x6e, 0x00, 0x00, 0x00, 0x04, 0x00, 0x61, 0x00,
+ 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x00, 0x00, 0x08, 0x00, 0x64, 0x00,
+ 0x72, 0x00, 0x61, 0x00, 0x77, 0x00, 0x61, 0x00, 0x62, 0x00, 0x6c, 0x00,
+ 0x65, 0x00, 0x00, 0x00, 0x06, 0x00, 0x6c, 0x00, 0x61, 0x00, 0x79, 0x00,
+ 0x6f, 0x00, 0x75, 0x00, 0x74, 0x00, 0x00, 0x00, 0x06, 0x00, 0x73, 0x00,
+ 0x74, 0x00, 0x72, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x67, 0x00, 0x00, 0x00,
+ 0x07, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x74, 0x00, 0x65, 0x00, 0x67, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x00, 0x00, 0x05, 0x00, 0x73, 0x00, 0x74, 0x00,
+ 0x79, 0x00, 0x6c, 0x00, 0x65, 0x00, 0x00, 0x00, 0x05, 0x00, 0x61, 0x00,
+ 0x72, 0x00, 0x72, 0x00, 0x61, 0x00, 0x79, 0x00, 0x00, 0x00, 0x05, 0x00,
+ 0x64, 0x00, 0x69, 0x00, 0x6d, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x1c, 0x00, 0x2c, 0x01, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00,
+ 0x1c, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00,
+ 0x4c, 0x00, 0x00, 0x00, 0x5a, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00,
+ 0x7e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x00, 0x00,
+ 0xbc, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0x05, 0x00, 0x61, 0x00,
+ 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x31, 0x00, 0x00, 0x00, 0x05, 0x00,
+ 0x61, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x32, 0x00, 0x00, 0x00,
+ 0x09, 0x00, 0x64, 0x00, 0x72, 0x00, 0x61, 0x00, 0x77, 0x00, 0x61, 0x00,
+ 0x62, 0x00, 0x6c, 0x00, 0x65, 0x00, 0x31, 0x00, 0x00, 0x00, 0x04, 0x00,
+ 0x6d, 0x00, 0x61, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x00, 0x00, 0x05, 0x00,
+ 0x74, 0x00, 0x65, 0x00, 0x73, 0x00, 0x74, 0x00, 0x31, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x74, 0x00, 0x65, 0x00, 0x73, 0x00, 0x74, 0x00, 0x32, 0x00,
+ 0x00, 0x00, 0x07, 0x00, 0x6e, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x62, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x31, 0x00, 0x00, 0x00, 0x07, 0x00, 0x6e, 0x00,
+ 0x75, 0x00, 0x6d, 0x00, 0x62, 0x00, 0x65, 0x00, 0x72, 0x00, 0x32, 0x00,
+ 0x00, 0x00, 0x06, 0x00, 0x54, 0x00, 0x68, 0x00, 0x65, 0x00, 0x6d, 0x00,
+ 0x65, 0x00, 0x31, 0x00, 0x00, 0x00, 0x06, 0x00, 0x54, 0x00, 0x68, 0x00,
+ 0x65, 0x00, 0x6d, 0x00, 0x65, 0x00, 0x32, 0x00, 0x00, 0x00, 0x0d, 0x00,
+ 0x69, 0x00, 0x6e, 0x00, 0x74, 0x00, 0x65, 0x00, 0x67, 0x00, 0x65, 0x00,
+ 0x72, 0x00, 0x41, 0x00, 0x72, 0x00, 0x72, 0x00, 0x61, 0x00, 0x79, 0x00,
+ 0x31, 0x00, 0x00, 0x00, 0x06, 0x00, 0x64, 0x00, 0x69, 0x00, 0x6d, 0x00,
+ 0x65, 0x00, 0x6e, 0x00, 0x31, 0x00, 0x00, 0x00, 0x06, 0x00, 0x64, 0x00,
+ 0x69, 0x00, 0x6d, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x32, 0x00, 0x00, 0x00,
+ 0x02, 0x02, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x02, 0x44, 0x00, 0x84, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x1c, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x08, 0x00, 0x00, 0x10, 0x05, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10, 0x05, 0x00, 0x00, 0x00,
+ 0x02, 0x02, 0x10, 0x00, 0x14, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x44, 0x00,
+ 0x58, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x48, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00,
+ 0x02, 0x02, 0x10, 0x00, 0x14, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x04, 0x24, 0x00, 0x00, 0x01, 0x02, 0x44, 0x00,
+ 0x58, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x48, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x03, 0x01, 0x00, 0x00, 0x00,
+ 0x01, 0x02, 0x44, 0x00, 0x58, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x66, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x58, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x03,
+ 0x02, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x44, 0x00, 0x6c, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00,
+ 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x03, 0x03, 0x00, 0x00, 0x00,
+ 0x08, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x03,
+ 0x04, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x44, 0x00, 0x6c, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00,
+ 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+ 0x06, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x10, 0xc8, 0x00, 0x00, 0x00,
+ 0x08, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x07, 0x7f, 0x01, 0x02, 0x44, 0x00, 0x5c, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00,
+ 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x73, 0x76, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00,
+ 0x06, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x10, 0x90, 0x01, 0x00, 0x00,
+ 0x02, 0x02, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x02, 0x44, 0x00, 0x90, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x28, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00, 0x08, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x7f,
+ 0x08, 0x00, 0x00, 0x10, 0x64, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x7f,
+ 0x08, 0x00, 0x00, 0x01, 0x00, 0x00, 0x05, 0x7f, 0x10, 0x00, 0x01, 0x00,
+ 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x7f, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x01, 0x7f, 0x08, 0x00, 0x00, 0x10, 0x2c, 0x01, 0x00, 0x00,
+ 0x02, 0x02, 0x10, 0x00, 0x14, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x44, 0x00,
+ 0x7c, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x48, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00,
+ 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x02, 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x02, 0x08, 0x00, 0x00, 0x10, 0x02, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x02, 0x08, 0x00, 0x00, 0x10, 0x03, 0x00, 0x00, 0x00,
+ 0x02, 0x02, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x02, 0x44, 0x00, 0x6c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00,
+ 0x08, 0x00, 0x00, 0x05, 0x01, 0x30, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+ 0x0c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x05, 0x00, 0x10, 0x00, 0x00
+};
+unsigned int basic_arsc_len = 2292;
diff --git a/libs/androidfw/tests/data/cm/basic/build b/libs/androidfw/tests/data/cm/basic/build
new file mode 100755
index 0000000..036e468
--- /dev/null
+++ b/libs/androidfw/tests/data/cm/basic/build
@@ -0,0 +1,11 @@
+#!/bin/bash
+
+PATH_TO_FRAMEWORK_RES=$(gettop)/prebuilts/sdk/current/android.jar
+
+aapt package -M AndroidManifest.xml -S res -I $PATH_TO_FRAMEWORK_RES --split fr,de -F bundle.apk -f && \
+unzip bundle.apk resources.arsc && \
+mv resources.arsc basic.arsc && \
+xxd -i basic.arsc > basic_arsc.h && \
+unzip bundle_de_fr.apk resources.arsc && \
+mv resources.arsc split_de_fr.arsc && \
+xxd -i split_de_fr.arsc > split_de_fr_arsc.h
diff --git a/libs/androidfw/tests/data/cm/basic/res/drawable/drawable1.png b/libs/androidfw/tests/data/cm/basic/res/drawable/drawable1.png
new file mode 100644
index 0000000..94660d3
--- /dev/null
+++ b/libs/androidfw/tests/data/cm/basic/res/drawable/drawable1.png
Binary files differ
diff --git a/libs/androidfw/tests/data/cm/basic/res/layout-fr-sw600dp/main.xml b/libs/androidfw/tests/data/cm/basic/res/layout-fr-sw600dp/main.xml
new file mode 100644
index 0000000..05ffd58
--- /dev/null
+++ b/libs/androidfw/tests/data/cm/basic/res/layout-fr-sw600dp/main.xml
@@ -0,0 +1,3 @@
+<?xml version="1.0" encoding="utf-8"?>
+<merge>
+</merge>
diff --git a/libs/androidfw/tests/data/cm/basic/res/layout/main.xml b/libs/androidfw/tests/data/cm/basic/res/layout/main.xml
new file mode 100644
index 0000000..05ffd58
--- /dev/null
+++ b/libs/androidfw/tests/data/cm/basic/res/layout/main.xml
@@ -0,0 +1,3 @@
+<?xml version="1.0" encoding="utf-8"?>
+<merge>
+</merge>
diff --git a/libs/androidfw/tests/data/cm/basic/res/values-de/values.xml b/libs/androidfw/tests/data/cm/basic/res/values-de/values.xml
new file mode 100644
index 0000000..103c6a3
--- /dev/null
+++ b/libs/androidfw/tests/data/cm/basic/res/values-de/values.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="test1">versuch 1</string>
+ <string name="test2">versuch 2</string>
+</resources>
diff --git a/libs/androidfw/tests/data/cm/basic/res/values-fr/values.xml b/libs/androidfw/tests/data/cm/basic/res/values-fr/values.xml
new file mode 100644
index 0000000..1806a2d
--- /dev/null
+++ b/libs/androidfw/tests/data/cm/basic/res/values-fr/values.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="test1">essai 1</string>
+ <string name="test2">essai 2</string>
+</resources>
diff --git a/libs/androidfw/tests/data/cm/basic/res/values-sv/values.xml b/libs/androidfw/tests/data/cm/basic/res/values-sv/values.xml
new file mode 100644
index 0000000..9d52307
--- /dev/null
+++ b/libs/androidfw/tests/data/cm/basic/res/values-sv/values.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <integer name="number1">400</integer>
+</resources>
diff --git a/libs/androidfw/tests/data/cm/basic/res/values/values.xml b/libs/androidfw/tests/data/cm/basic/res/values/values.xml
new file mode 100644
index 0000000..0d22a4c
--- /dev/null
+++ b/libs/androidfw/tests/data/cm/basic/res/values/values.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <attr name="attr1" format="reference|integer" />
+ <attr name="attr2" format="reference|integer" />
+
+ <string name="test1">test1</string>
+ <string name="test2">test2</string>
+
+ <integer name="number1">200</integer>
+ <integer name="number2">@array/integerArray1</integer>
+
+ <style name="Theme1">
+ <item name="com.android.test.basic:attr1">100</item>
+ <item name="com.android.test.basic:attr2">@integer/number1</item>
+ </style>
+
+ <style name="Theme2" parent="@com.android.test.basic:style/Theme1">
+ <item name="com.android.test.basic:attr1">300</item>
+ </style>
+
+ <integer-array name="integerArray1">
+ <item>1</item>
+ <item>2</item>
+ <item>3</item>
+ </integer-array>
+
+ <dimen name="dimen1">48dp</dimen>
+ <dimen name="dimen2">16px</dimen>
+</resources>
diff --git a/libs/androidfw/tests/data/cm/basic/split_de_fr_arsc.h b/libs/androidfw/tests/data/cm/basic/split_de_fr_arsc.h
new file mode 100644
index 0000000..23cb3b7
--- /dev/null
+++ b/libs/androidfw/tests/data/cm/basic/split_de_fr_arsc.h
@@ -0,0 +1,92 @@
+unsigned char split_de_fr_arsc[] = {
+ 0x02, 0x00, 0x0c, 0x00, 0x2c, 0x04, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x1c, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00,
+ 0x2c, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x09, 0x00, 0x76, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x75, 0x00, 0x63, 0x00, 0x68, 0x00,
+ 0x20, 0x00, 0x31, 0x00, 0x00, 0x00, 0x09, 0x00, 0x76, 0x00, 0x65, 0x00,
+ 0x72, 0x00, 0x73, 0x00, 0x75, 0x00, 0x63, 0x00, 0x68, 0x00, 0x20, 0x00,
+ 0x32, 0x00, 0x00, 0x00, 0x07, 0x00, 0x65, 0x00, 0x73, 0x00, 0x73, 0x00,
+ 0x61, 0x00, 0x69, 0x00, 0x20, 0x00, 0x31, 0x00, 0x00, 0x00, 0x07, 0x00,
+ 0x65, 0x00, 0x73, 0x00, 0x73, 0x00, 0x61, 0x00, 0x69, 0x00, 0x20, 0x00,
+ 0x32, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x01, 0xa4, 0x03, 0x00, 0x00,
+ 0x7f, 0x00, 0x00, 0x00, 0x63, 0x00, 0x6f, 0x00, 0x6d, 0x00, 0x2e, 0x00,
+ 0x61, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x72, 0x00, 0x6f, 0x00, 0x69, 0x00,
+ 0x64, 0x00, 0x2e, 0x00, 0x74, 0x00, 0x65, 0x00, 0x73, 0x00, 0x74, 0x00,
+ 0x2e, 0x00, 0x62, 0x00, 0x61, 0x00, 0x73, 0x00, 0x69, 0x00, 0x63, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00,
+ 0x08, 0x00, 0x00, 0x00, 0xd8, 0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1c, 0x00, 0xb8, 0x00, 0x00, 0x00,
+ 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x0c, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
+ 0x40, 0x00, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00,
+ 0x6e, 0x00, 0x00, 0x00, 0x04, 0x00, 0x61, 0x00, 0x74, 0x00, 0x74, 0x00,
+ 0x72, 0x00, 0x00, 0x00, 0x08, 0x00, 0x64, 0x00, 0x72, 0x00, 0x61, 0x00,
+ 0x77, 0x00, 0x61, 0x00, 0x62, 0x00, 0x6c, 0x00, 0x65, 0x00, 0x00, 0x00,
+ 0x06, 0x00, 0x6c, 0x00, 0x61, 0x00, 0x79, 0x00, 0x6f, 0x00, 0x75, 0x00,
+ 0x74, 0x00, 0x00, 0x00, 0x06, 0x00, 0x73, 0x00, 0x74, 0x00, 0x72, 0x00,
+ 0x69, 0x00, 0x6e, 0x00, 0x67, 0x00, 0x00, 0x00, 0x07, 0x00, 0x69, 0x00,
+ 0x6e, 0x00, 0x74, 0x00, 0x65, 0x00, 0x67, 0x00, 0x65, 0x00, 0x72, 0x00,
+ 0x00, 0x00, 0x05, 0x00, 0x73, 0x00, 0x74, 0x00, 0x79, 0x00, 0x6c, 0x00,
+ 0x65, 0x00, 0x00, 0x00, 0x05, 0x00, 0x61, 0x00, 0x72, 0x00, 0x72, 0x00,
+ 0x61, 0x00, 0x79, 0x00, 0x00, 0x00, 0x05, 0x00, 0x64, 0x00, 0x69, 0x00,
+ 0x6d, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1c, 0x00,
+ 0x40, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x05, 0x00, 0x74, 0x00,
+ 0x65, 0x00, 0x73, 0x00, 0x74, 0x00, 0x31, 0x00, 0x00, 0x00, 0x05, 0x00,
+ 0x74, 0x00, 0x65, 0x00, 0x73, 0x00, 0x74, 0x00, 0x32, 0x00, 0x00, 0x00,
+ 0x02, 0x02, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x02, 0x02, 0x10, 0x00, 0x14, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00,
+ 0x14, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x01, 0x02, 0x44, 0x00, 0x6c, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00,
+ 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x65, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00,
+ 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x03,
+ 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x44, 0x00, 0x6c, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00,
+ 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x72, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x03, 0x02, 0x00, 0x00, 0x00,
+ 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x03,
+ 0x03, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00,
+ 0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x14, 0x00, 0x00, 0x00,
+ 0x07, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x02, 0x02, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+unsigned int split_de_fr_arsc_len = 1068;
diff --git a/libs/androidfw/tests/data/cm/overlay/AndroidManifest.xml b/libs/androidfw/tests/data/cm/overlay/AndroidManifest.xml
new file mode 100644
index 0000000..a56ac18
--- /dev/null
+++ b/libs/androidfw/tests/data/cm/overlay/AndroidManifest.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.test.basic">
+ <application>
+ </application>
+</manifest>
diff --git a/libs/androidfw/tests/data/cm/overlay/build b/libs/androidfw/tests/data/cm/overlay/build
new file mode 100755
index 0000000..87cf6de
--- /dev/null
+++ b/libs/androidfw/tests/data/cm/overlay/build
@@ -0,0 +1,6 @@
+#!/bin/bash
+
+aapt package -M AndroidManifest.xml -S res -F bundle.apk -f && \
+unzip bundle.apk resources.arsc && \
+mv resources.arsc overlay.arsc && \
+xxd -i overlay.arsc > overlay_arsc.h
diff --git a/libs/androidfw/tests/data/cm/overlay/overlay_arsc.h b/libs/androidfw/tests/data/cm/overlay/overlay_arsc.h
new file mode 100644
index 0000000..2d59417
--- /dev/null
+++ b/libs/androidfw/tests/data/cm/overlay/overlay_arsc.h
@@ -0,0 +1,103 @@
+unsigned char overlay_arsc[] = {
+ 0x02, 0x00, 0x0c, 0x00, 0xa8, 0x04, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x1c, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00,
+ 0x1a, 0x00, 0x72, 0x00, 0x65, 0x00, 0x73, 0x00, 0x2f, 0x00, 0x64, 0x00,
+ 0x72, 0x00, 0x61, 0x00, 0x77, 0x00, 0x61, 0x00, 0x62, 0x00, 0x6c, 0x00,
+ 0x65, 0x00, 0x2f, 0x00, 0x64, 0x00, 0x72, 0x00, 0x61, 0x00, 0x77, 0x00,
+ 0x61, 0x00, 0x62, 0x00, 0x6c, 0x00, 0x65, 0x00, 0x31, 0x00, 0x2e, 0x00,
+ 0x70, 0x00, 0x6e, 0x00, 0x67, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x74, 0x00,
+ 0x65, 0x00, 0x73, 0x00, 0x74, 0x00, 0x32, 0x00, 0x2d, 0x00, 0x6f, 0x00,
+ 0x76, 0x00, 0x65, 0x00, 0x72, 0x00, 0x6c, 0x00, 0x61, 0x00, 0x79, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x01, 0x20, 0x04, 0x00, 0x00,
+ 0x7f, 0x00, 0x00, 0x00, 0x63, 0x00, 0x6f, 0x00, 0x6d, 0x00, 0x2e, 0x00,
+ 0x61, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x72, 0x00, 0x6f, 0x00, 0x69, 0x00,
+ 0x64, 0x00, 0x2e, 0x00, 0x74, 0x00, 0x65, 0x00, 0x73, 0x00, 0x74, 0x00,
+ 0x2e, 0x00, 0x62, 0x00, 0x61, 0x00, 0x73, 0x00, 0x69, 0x00, 0x63, 0x00,
+ 0x2e, 0x00, 0x6f, 0x00, 0x76, 0x00, 0x65, 0x00, 0x72, 0x00, 0x6c, 0x00,
+ 0x61, 0x00, 0x79, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x9c, 0x01, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1c, 0x00, 0x7c, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x0c, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
+ 0x3e, 0x00, 0x00, 0x00, 0x04, 0x00, 0x61, 0x00, 0x74, 0x00, 0x74, 0x00,
+ 0x72, 0x00, 0x00, 0x00, 0x08, 0x00, 0x64, 0x00, 0x72, 0x00, 0x61, 0x00,
+ 0x77, 0x00, 0x61, 0x00, 0x62, 0x00, 0x6c, 0x00, 0x65, 0x00, 0x00, 0x00,
+ 0x06, 0x00, 0x73, 0x00, 0x74, 0x00, 0x72, 0x00, 0x69, 0x00, 0x6e, 0x00,
+ 0x67, 0x00, 0x00, 0x00, 0x05, 0x00, 0x61, 0x00, 0x72, 0x00, 0x72, 0x00,
+ 0x61, 0x00, 0x79, 0x00, 0x00, 0x00, 0x05, 0x00, 0x64, 0x00, 0x69, 0x00,
+ 0x6d, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1c, 0x00,
+ 0x94, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00,
+ 0x42, 0x00, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, 0x09, 0x00, 0x64, 0x00,
+ 0x72, 0x00, 0x61, 0x00, 0x77, 0x00, 0x61, 0x00, 0x62, 0x00, 0x6c, 0x00,
+ 0x65, 0x00, 0x31, 0x00, 0x00, 0x00, 0x05, 0x00, 0x74, 0x00, 0x65, 0x00,
+ 0x73, 0x00, 0x74, 0x00, 0x32, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x69, 0x00,
+ 0x6e, 0x00, 0x74, 0x00, 0x65, 0x00, 0x67, 0x00, 0x65, 0x00, 0x72, 0x00,
+ 0x41, 0x00, 0x72, 0x00, 0x72, 0x00, 0x61, 0x00, 0x79, 0x00, 0x31, 0x00,
+ 0x00, 0x00, 0x06, 0x00, 0x64, 0x00, 0x69, 0x00, 0x6d, 0x00, 0x65, 0x00,
+ 0x6e, 0x00, 0x31, 0x00, 0x00, 0x00, 0x06, 0x00, 0x64, 0x00, 0x69, 0x00,
+ 0x6d, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x02, 0x02, 0x10, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x14, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x02, 0x44, 0x00, 0x58, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x03,
+ 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x14, 0x00, 0x00, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x02, 0x44, 0x00, 0x58, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x03,
+ 0x01, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x14, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x02, 0x44, 0x00, 0x70, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x08, 0x00, 0x00, 0x10,
+ 0x0a, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x02, 0x08, 0x00, 0x00, 0x10,
+ 0x0b, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x44, 0x00, 0x6c, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00,
+ 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x05, 0x02, 0x38, 0x00, 0x00,
+ 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x05,
+ 0x01, 0x0c, 0x00, 0x00
+};
+unsigned int overlay_arsc_len = 1192;
diff --git a/libs/androidfw/tests/data/cm/overlay/res/drawable/drawable1.png b/libs/androidfw/tests/data/cm/overlay/res/drawable/drawable1.png
new file mode 100644
index 0000000..a7045ed
--- /dev/null
+++ b/libs/androidfw/tests/data/cm/overlay/res/drawable/drawable1.png
Binary files differ
diff --git a/libs/androidfw/tests/data/cm/overlay/res/values/values.xml b/libs/androidfw/tests/data/cm/overlay/res/values/values.xml
new file mode 100644
index 0000000..5bf0427
--- /dev/null
+++ b/libs/androidfw/tests/data/cm/overlay/res/values/values.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="test2">test2-overlay</string>
+ <integer-array name="integerArray1">
+ <item>10</item>
+ <item>11</item>
+ </integer-array>
+
+ <dimen name="dimen1">56sp</dimen>
+ <dimen name="dimen2">12dp</dimen>
+
+</resources>
diff --git a/libs/androidfw/tests/data/cm/override/AndroidManifest.xml b/libs/androidfw/tests/data/cm/override/AndroidManifest.xml
new file mode 100644
index 0000000..ed26054
--- /dev/null
+++ b/libs/androidfw/tests/data/cm/override/AndroidManifest.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.test.override">
+ <application>
+ </application>
+</manifest>
diff --git a/libs/androidfw/tests/data/cm/override/R.h b/libs/androidfw/tests/data/cm/override/R.h
new file mode 100644
index 0000000..a57c6b1
--- /dev/null
+++ b/libs/androidfw/tests/data/cm/override/R.h
@@ -0,0 +1,16 @@
+#ifndef __BASE_R_H
+#define __BASE_R_H
+
+namespace override {
+namespace R {
+
+namespace string {
+ enum {
+ string1 = 0x7f020000, // default
+ };
+}
+
+} // namespace R
+} // namespace base
+
+#endif // __BASE_R_H
diff --git a/libs/androidfw/tests/data/cm/override/build b/libs/androidfw/tests/data/cm/override/build
new file mode 100755
index 0000000..f6ba33d
--- /dev/null
+++ b/libs/androidfw/tests/data/cm/override/build
@@ -0,0 +1,6 @@
+#!/bin/bash
+
+aapt package -M AndroidManifest.xml -S res -F bundle.apk -f && \
+unzip bundle.apk resources.arsc && \
+mv resources.arsc override.arsc && \
+xxd -i override.arsc > override_arsc.h
diff --git a/libs/androidfw/tests/data/cm/override/override_arsc.h b/libs/androidfw/tests/data/cm/override/override_arsc.h
new file mode 100644
index 0000000..2598635
--- /dev/null
+++ b/libs/androidfw/tests/data/cm/override/override_arsc.h
@@ -0,0 +1,53 @@
+unsigned char override_arsc[] = {
+ 0x02, 0x00, 0x0c, 0x00, 0x50, 0x02, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x1c, 0x00, 0x34, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x73, 0x00,
+ 0x74, 0x00, 0x72, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x67, 0x00, 0x31, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x01, 0x10, 0x02, 0x00, 0x00,
+ 0x7f, 0x00, 0x00, 0x00, 0x63, 0x00, 0x6f, 0x00, 0x6d, 0x00, 0x2e, 0x00,
+ 0x61, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x72, 0x00, 0x6f, 0x00, 0x69, 0x00,
+ 0x64, 0x00, 0x2e, 0x00, 0x74, 0x00, 0x65, 0x00, 0x73, 0x00, 0x74, 0x00,
+ 0x2e, 0x00, 0x6f, 0x00, 0x76, 0x00, 0x65, 0x00, 0x72, 0x00, 0x72, 0x00,
+ 0x69, 0x00, 0x64, 0x00, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x60, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1c, 0x00, 0x40, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x0c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x61, 0x00, 0x74, 0x00, 0x74, 0x00,
+ 0x72, 0x00, 0x00, 0x00, 0x06, 0x00, 0x73, 0x00, 0x74, 0x00, 0x72, 0x00,
+ 0x69, 0x00, 0x6e, 0x00, 0x67, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1c, 0x00,
+ 0x34, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x73, 0x00, 0x74, 0x00, 0x72, 0x00,
+ 0x69, 0x00, 0x6e, 0x00, 0x67, 0x00, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x02, 0x02, 0x10, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x14, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x02, 0x44, 0x00, 0x58, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x03,
+ 0x00, 0x00, 0x00, 0x00
+};
+unsigned int override_arsc_len = 592;
diff --git a/libs/androidfw/tests/data/cm/override/res/values/values.xml b/libs/androidfw/tests/data/cm/override/res/values/values.xml
new file mode 100644
index 0000000..7b607ef
--- /dev/null
+++ b/libs/androidfw/tests/data/cm/override/res/values/values.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="string1">string1</string>
+</resources>
diff --git a/libs/androidfw/tests/data/cm/system/AndroidManifest.xml b/libs/androidfw/tests/data/cm/system/AndroidManifest.xml
new file mode 100644
index 0000000..af105ee
--- /dev/null
+++ b/libs/androidfw/tests/data/cm/system/AndroidManifest.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android">
+</manifest>
diff --git a/libs/androidfw/tests/data/cm/system/R.h b/libs/androidfw/tests/data/cm/system/R.h
new file mode 100644
index 0000000..ba83b89
--- /dev/null
+++ b/libs/androidfw/tests/data/cm/system/R.h
@@ -0,0 +1,26 @@
+#ifndef __ANDROID_R_H
+#define __ANDROID_R_H
+
+namespace android {
+namespace R {
+
+namespace attr {
+ enum {
+ background = 0x01010000, // default
+ foreground = 0x01010001, // default
+ some_dimen = 0x01010002, // default
+ another_dimen = 0x01010003, // default
+ windowNoTitle = 0x01010056, // default
+ };
+}
+
+namespace style {
+ enum {
+ Theme_One = 0x01020000, // default
+ };
+}
+
+} // namespace R
+} // namespace android
+
+#endif // __ANDROID_R_H
diff --git a/libs/androidfw/tests/data/cm/system/build b/libs/androidfw/tests/data/cm/system/build
new file mode 100755
index 0000000..2a3ac0b
--- /dev/null
+++ b/libs/androidfw/tests/data/cm/system/build
@@ -0,0 +1,6 @@
+#!/bin/bash
+
+aapt package -x -M AndroidManifest.xml -S res -F bundle.apk -f && \
+unzip bundle.apk resources.arsc && \
+mv resources.arsc system.arsc && \
+xxd -i system.arsc > system_arsc.h
diff --git a/libs/androidfw/tests/data/cm/system/res/values/filler.xml b/libs/androidfw/tests/data/cm/system/res/values/filler.xml
new file mode 100644
index 0000000..27af8dc
--- /dev/null
+++ b/libs/androidfw/tests/data/cm/system/res/values/filler.xml
@@ -0,0 +1,168 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- Filler so we can test the protected attribute "windowNoTitle" -->
+ <java-symbol name="dummyAttr04" type="attr" id="0x01010004" />
+ <java-symbol name="dummyAttr05" type="attr" id="0x01010005" />
+ <java-symbol name="dummyAttr06" type="attr" id="0x01010006" />
+ <java-symbol name="dummyAttr07" type="attr" id="0x01010007" />
+ <java-symbol name="dummyAttr08" type="attr" id="0x01010008" />
+ <java-symbol name="dummyAttr09" type="attr" id="0x01010009" />
+ <java-symbol name="dummyAttr0a" type="attr" id="0x0101000a" />
+ <java-symbol name="dummyAttr0b" type="attr" id="0x0101000b" />
+ <java-symbol name="dummyAttr0c" type="attr" id="0x0101000c" />
+ <java-symbol name="dummyAttr0d" type="attr" id="0x0101000d" />
+ <java-symbol name="dummyAttr0e" type="attr" id="0x0101000e" />
+ <java-symbol name="dummyAttr0f" type="attr" id="0x0101000f" />
+ <java-symbol name="dummyAttr10" type="attr" id="0x01010010" />
+ <java-symbol name="dummyAttr11" type="attr" id="0x01010011" />
+ <java-symbol name="dummyAttr12" type="attr" id="0x01010012" />
+ <java-symbol name="dummyAttr13" type="attr" id="0x01010013" />
+ <java-symbol name="dummyAttr14" type="attr" id="0x01010014" />
+ <java-symbol name="dummyAttr15" type="attr" id="0x01010015" />
+ <java-symbol name="dummyAttr16" type="attr" id="0x01010016" />
+ <java-symbol name="dummyAttr17" type="attr" id="0x01010017" />
+ <java-symbol name="dummyAttr18" type="attr" id="0x01010018" />
+ <java-symbol name="dummyAttr19" type="attr" id="0x01010019" />
+ <java-symbol name="dummyAttr1a" type="attr" id="0x0101001a" />
+ <java-symbol name="dummyAttr1b" type="attr" id="0x0101001b" />
+ <java-symbol name="dummyAttr1c" type="attr" id="0x0101001c" />
+ <java-symbol name="dummyAttr1d" type="attr" id="0x0101001d" />
+ <java-symbol name="dummyAttr1e" type="attr" id="0x0101001e" />
+ <java-symbol name="dummyAttr1f" type="attr" id="0x0101001f" />
+ <java-symbol name="dummyAttr20" type="attr" id="0x01010020" />
+ <java-symbol name="dummyAttr21" type="attr" id="0x01010021" />
+ <java-symbol name="dummyAttr22" type="attr" id="0x01010022" />
+ <java-symbol name="dummyAttr23" type="attr" id="0x01010023" />
+ <java-symbol name="dummyAttr24" type="attr" id="0x01010024" />
+ <java-symbol name="dummyAttr25" type="attr" id="0x01010025" />
+ <java-symbol name="dummyAttr26" type="attr" id="0x01010026" />
+ <java-symbol name="dummyAttr27" type="attr" id="0x01010027" />
+ <java-symbol name="dummyAttr28" type="attr" id="0x01010028" />
+ <java-symbol name="dummyAttr29" type="attr" id="0x01010029" />
+ <java-symbol name="dummyAttr2a" type="attr" id="0x0101002a" />
+ <java-symbol name="dummyAttr2b" type="attr" id="0x0101002b" />
+ <java-symbol name="dummyAttr2c" type="attr" id="0x0101002c" />
+ <java-symbol name="dummyAttr2d" type="attr" id="0x0101002d" />
+ <java-symbol name="dummyAttr2e" type="attr" id="0x0101002e" />
+ <java-symbol name="dummyAttr2f" type="attr" id="0x0101002f" />
+ <java-symbol name="dummyAttr30" type="attr" id="0x01010030" />
+ <java-symbol name="dummyAttr31" type="attr" id="0x01010031" />
+ <java-symbol name="dummyAttr32" type="attr" id="0x01010032" />
+ <java-symbol name="dummyAttr33" type="attr" id="0x01010033" />
+ <java-symbol name="dummyAttr34" type="attr" id="0x01010034" />
+ <java-symbol name="dummyAttr35" type="attr" id="0x01010035" />
+ <java-symbol name="dummyAttr36" type="attr" id="0x01010036" />
+ <java-symbol name="dummyAttr37" type="attr" id="0x01010037" />
+ <java-symbol name="dummyAttr38" type="attr" id="0x01010038" />
+ <java-symbol name="dummyAttr39" type="attr" id="0x01010039" />
+ <java-symbol name="dummyAttr3a" type="attr" id="0x0101003a" />
+ <java-symbol name="dummyAttr3b" type="attr" id="0x0101003b" />
+ <java-symbol name="dummyAttr3c" type="attr" id="0x0101003c" />
+ <java-symbol name="dummyAttr3d" type="attr" id="0x0101003d" />
+ <java-symbol name="dummyAttr3e" type="attr" id="0x0101003e" />
+ <java-symbol name="dummyAttr3f" type="attr" id="0x0101003f" />
+ <java-symbol name="dummyAttr40" type="attr" id="0x01010040" />
+ <java-symbol name="dummyAttr41" type="attr" id="0x01010041" />
+ <java-symbol name="dummyAttr42" type="attr" id="0x01010042" />
+ <java-symbol name="dummyAttr43" type="attr" id="0x01010043" />
+ <java-symbol name="dummyAttr44" type="attr" id="0x01010044" />
+ <java-symbol name="dummyAttr45" type="attr" id="0x01010045" />
+ <java-symbol name="dummyAttr46" type="attr" id="0x01010046" />
+ <java-symbol name="dummyAttr47" type="attr" id="0x01010047" />
+ <java-symbol name="dummyAttr48" type="attr" id="0x01010048" />
+ <java-symbol name="dummyAttr49" type="attr" id="0x01010049" />
+ <java-symbol name="dummyAttr4a" type="attr" id="0x0101004a" />
+ <java-symbol name="dummyAttr4b" type="attr" id="0x0101004b" />
+ <java-symbol name="dummyAttr4c" type="attr" id="0x0101004c" />
+ <java-symbol name="dummyAttr4d" type="attr" id="0x0101004d" />
+ <java-symbol name="dummyAttr4e" type="attr" id="0x0101004e" />
+ <java-symbol name="dummyAttr4f" type="attr" id="0x0101004f" />
+ <java-symbol name="dummyAttr50" type="attr" id="0x01010050" />
+ <java-symbol name="dummyAttr51" type="attr" id="0x01010051" />
+ <java-symbol name="dummyAttr52" type="attr" id="0x01010052" />
+ <java-symbol name="dummyAttr53" type="attr" id="0x01010053" />
+ <java-symbol name="dummyAttr54" type="attr" id="0x01010054" />
+ <java-symbol name="dummyAttr55" type="attr" id="0x01010055" />
+ <attr name="dummyAttr04" format="reference"/>
+ <attr name="dummyAttr05" format="reference"/>
+ <attr name="dummyAttr06" format="reference"/>
+ <attr name="dummyAttr07" format="reference"/>
+ <attr name="dummyAttr08" format="reference"/>
+ <attr name="dummyAttr09" format="reference"/>
+ <attr name="dummyAttr0a" format="reference"/>
+ <attr name="dummyAttr0b" format="reference"/>
+ <attr name="dummyAttr0c" format="reference"/>
+ <attr name="dummyAttr0d" format="reference"/>
+ <attr name="dummyAttr0e" format="reference"/>
+ <attr name="dummyAttr0f" format="reference"/>
+ <attr name="dummyAttr10" format="reference"/>
+ <attr name="dummyAttr11" format="reference"/>
+ <attr name="dummyAttr12" format="reference"/>
+ <attr name="dummyAttr13" format="reference"/>
+ <attr name="dummyAttr14" format="reference"/>
+ <attr name="dummyAttr15" format="reference"/>
+ <attr name="dummyAttr16" format="reference"/>
+ <attr name="dummyAttr17" format="reference"/>
+ <attr name="dummyAttr18" format="reference"/>
+ <attr name="dummyAttr19" format="reference"/>
+ <attr name="dummyAttr1a" format="reference"/>
+ <attr name="dummyAttr1b" format="reference"/>
+ <attr name="dummyAttr1c" format="reference"/>
+ <attr name="dummyAttr1d" format="reference"/>
+ <attr name="dummyAttr1e" format="reference"/>
+ <attr name="dummyAttr1f" format="reference"/>
+ <attr name="dummyAttr20" format="reference"/>
+ <attr name="dummyAttr21" format="reference"/>
+ <attr name="dummyAttr22" format="reference"/>
+ <attr name="dummyAttr23" format="reference"/>
+ <attr name="dummyAttr24" format="reference"/>
+ <attr name="dummyAttr25" format="reference"/>
+ <attr name="dummyAttr26" format="reference"/>
+ <attr name="dummyAttr27" format="reference"/>
+ <attr name="dummyAttr28" format="reference"/>
+ <attr name="dummyAttr29" format="reference"/>
+ <attr name="dummyAttr2a" format="reference"/>
+ <attr name="dummyAttr2b" format="reference"/>
+ <attr name="dummyAttr2c" format="reference"/>
+ <attr name="dummyAttr2d" format="reference"/>
+ <attr name="dummyAttr2e" format="reference"/>
+ <attr name="dummyAttr2f" format="reference"/>
+ <attr name="dummyAttr30" format="reference"/>
+ <attr name="dummyAttr31" format="reference"/>
+ <attr name="dummyAttr32" format="reference"/>
+ <attr name="dummyAttr33" format="reference"/>
+ <attr name="dummyAttr34" format="reference"/>
+ <attr name="dummyAttr35" format="reference"/>
+ <attr name="dummyAttr36" format="reference"/>
+ <attr name="dummyAttr37" format="reference"/>
+ <attr name="dummyAttr38" format="reference"/>
+ <attr name="dummyAttr39" format="reference"/>
+ <attr name="dummyAttr3a" format="reference"/>
+ <attr name="dummyAttr3b" format="reference"/>
+ <attr name="dummyAttr3c" format="reference"/>
+ <attr name="dummyAttr3d" format="reference"/>
+ <attr name="dummyAttr3e" format="reference"/>
+ <attr name="dummyAttr3f" format="reference"/>
+ <attr name="dummyAttr40" format="reference"/>
+ <attr name="dummyAttr41" format="reference"/>
+ <attr name="dummyAttr42" format="reference"/>
+ <attr name="dummyAttr43" format="reference"/>
+ <attr name="dummyAttr44" format="reference"/>
+ <attr name="dummyAttr45" format="reference"/>
+ <attr name="dummyAttr46" format="reference"/>
+ <attr name="dummyAttr47" format="reference"/>
+ <attr name="dummyAttr48" format="reference"/>
+ <attr name="dummyAttr49" format="reference"/>
+ <attr name="dummyAttr4a" format="reference"/>
+ <attr name="dummyAttr4b" format="reference"/>
+ <attr name="dummyAttr4c" format="reference"/>
+ <attr name="dummyAttr4d" format="reference"/>
+ <attr name="dummyAttr4e" format="reference"/>
+ <attr name="dummyAttr4f" format="reference"/>
+ <attr name="dummyAttr50" format="reference"/>
+ <attr name="dummyAttr51" format="reference"/>
+ <attr name="dummyAttr52" format="reference"/>
+ <attr name="dummyAttr53" format="reference"/>
+ <attr name="dummyAttr54" format="reference"/>
+ <attr name="dummyAttr55" format="reference"/>
+</resources> \ No newline at end of file
diff --git a/libs/androidfw/tests/data/cm/system/res/values/themes.xml b/libs/androidfw/tests/data/cm/system/res/values/themes.xml
new file mode 100644
index 0000000..c870b1e
--- /dev/null
+++ b/libs/androidfw/tests/data/cm/system/res/values/themes.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <public name="background" type="attr" id="0x01010000"/>
+ <public name="foreground" type="attr" id="0x01010001"/>
+ <public name="someDimen" type="attr" id="0x01010002" />
+ <public name="anotherDimen" type="attr" id="0x01010003" />
+ <!-- attributes 0x01010004 to 0x01010055 are in filler.xml -->
+ <public name="windowNoTitle" type="attr" id="0x01010056" />
+ <public name="Theme.One" type="style" id="0x01020000"/>
+
+ <attr name="background" format="color|reference"/>
+ <attr name="foreground" format="color|reference"/>
+ <attr name="someDimen" format="dimension|reference"/>
+ <attr name="anotherDimen" format="dimension|reference"/>
+ <attr name="windowNoTitle" format="boolean|reference"/>
+ <style name="Theme.One" parent="">
+ <item name="android:background">#ff0000</item>
+ <item name="android:foreground">#000000</item>
+ <item name="android:windowNoTitle">true</item>
+ </style>
+</resources>
diff --git a/libs/androidfw/tests/data/cm/system/system_arsc.h b/libs/androidfw/tests/data/cm/system/system_arsc.h
new file mode 100644
index 0000000..e157a0e
--- /dev/null
+++ b/libs/androidfw/tests/data/cm/system/system_arsc.h
@@ -0,0 +1,538 @@
+unsigned char system_arsc[] = {
+ 0x02, 0x00, 0x0c, 0x00, 0x10, 0x19, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x1c, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x01, 0xe8, 0x18, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x72, 0x00,
+ 0x6f, 0x00, 0x69, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x60, 0x01, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1c, 0x00, 0x40, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x0c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x61, 0x00, 0x74, 0x00, 0x74, 0x00,
+ 0x72, 0x00, 0x00, 0x00, 0x05, 0x00, 0x73, 0x00, 0x74, 0x00, 0x79, 0x00,
+ 0x6c, 0x00, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1c, 0x00,
+ 0x68, 0x0a, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x7c, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
+ 0x46, 0x00, 0x00, 0x00, 0x62, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00,
+ 0x96, 0x00, 0x00, 0x00, 0xb0, 0x00, 0x00, 0x00, 0xca, 0x00, 0x00, 0x00,
+ 0xe4, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x18, 0x01, 0x00, 0x00,
+ 0x32, 0x01, 0x00, 0x00, 0x4c, 0x01, 0x00, 0x00, 0x66, 0x01, 0x00, 0x00,
+ 0x80, 0x01, 0x00, 0x00, 0x9a, 0x01, 0x00, 0x00, 0xb4, 0x01, 0x00, 0x00,
+ 0xce, 0x01, 0x00, 0x00, 0xe8, 0x01, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00,
+ 0x1c, 0x02, 0x00, 0x00, 0x36, 0x02, 0x00, 0x00, 0x50, 0x02, 0x00, 0x00,
+ 0x6a, 0x02, 0x00, 0x00, 0x84, 0x02, 0x00, 0x00, 0x9e, 0x02, 0x00, 0x00,
+ 0xb8, 0x02, 0x00, 0x00, 0xd2, 0x02, 0x00, 0x00, 0xec, 0x02, 0x00, 0x00,
+ 0x06, 0x03, 0x00, 0x00, 0x20, 0x03, 0x00, 0x00, 0x3a, 0x03, 0x00, 0x00,
+ 0x54, 0x03, 0x00, 0x00, 0x6e, 0x03, 0x00, 0x00, 0x88, 0x03, 0x00, 0x00,
+ 0xa2, 0x03, 0x00, 0x00, 0xbc, 0x03, 0x00, 0x00, 0xd6, 0x03, 0x00, 0x00,
+ 0xf0, 0x03, 0x00, 0x00, 0x0a, 0x04, 0x00, 0x00, 0x24, 0x04, 0x00, 0x00,
+ 0x3e, 0x04, 0x00, 0x00, 0x58, 0x04, 0x00, 0x00, 0x72, 0x04, 0x00, 0x00,
+ 0x8c, 0x04, 0x00, 0x00, 0xa6, 0x04, 0x00, 0x00, 0xc0, 0x04, 0x00, 0x00,
+ 0xda, 0x04, 0x00, 0x00, 0xf4, 0x04, 0x00, 0x00, 0x0e, 0x05, 0x00, 0x00,
+ 0x28, 0x05, 0x00, 0x00, 0x42, 0x05, 0x00, 0x00, 0x5c, 0x05, 0x00, 0x00,
+ 0x76, 0x05, 0x00, 0x00, 0x90, 0x05, 0x00, 0x00, 0xaa, 0x05, 0x00, 0x00,
+ 0xc4, 0x05, 0x00, 0x00, 0xde, 0x05, 0x00, 0x00, 0xf8, 0x05, 0x00, 0x00,
+ 0x12, 0x06, 0x00, 0x00, 0x2c, 0x06, 0x00, 0x00, 0x46, 0x06, 0x00, 0x00,
+ 0x60, 0x06, 0x00, 0x00, 0x7a, 0x06, 0x00, 0x00, 0x94, 0x06, 0x00, 0x00,
+ 0xae, 0x06, 0x00, 0x00, 0xc8, 0x06, 0x00, 0x00, 0xe2, 0x06, 0x00, 0x00,
+ 0xfc, 0x06, 0x00, 0x00, 0x16, 0x07, 0x00, 0x00, 0x30, 0x07, 0x00, 0x00,
+ 0x4a, 0x07, 0x00, 0x00, 0x64, 0x07, 0x00, 0x00, 0x7e, 0x07, 0x00, 0x00,
+ 0x98, 0x07, 0x00, 0x00, 0xb2, 0x07, 0x00, 0x00, 0xcc, 0x07, 0x00, 0x00,
+ 0xe6, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x1a, 0x08, 0x00, 0x00,
+ 0x34, 0x08, 0x00, 0x00, 0x4e, 0x08, 0x00, 0x00, 0x68, 0x08, 0x00, 0x00,
+ 0x82, 0x08, 0x00, 0x00, 0x9c, 0x08, 0x00, 0x00, 0xb6, 0x08, 0x00, 0x00,
+ 0xd4, 0x08, 0x00, 0x00, 0x0a, 0x00, 0x62, 0x00, 0x61, 0x00, 0x63, 0x00,
+ 0x6b, 0x00, 0x67, 0x00, 0x72, 0x00, 0x6f, 0x00, 0x75, 0x00, 0x6e, 0x00,
+ 0x64, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x66, 0x00, 0x6f, 0x00, 0x72, 0x00,
+ 0x65, 0x00, 0x67, 0x00, 0x72, 0x00, 0x6f, 0x00, 0x75, 0x00, 0x6e, 0x00,
+ 0x64, 0x00, 0x00, 0x00, 0x09, 0x00, 0x73, 0x00, 0x6f, 0x00, 0x6d, 0x00,
+ 0x65, 0x00, 0x44, 0x00, 0x69, 0x00, 0x6d, 0x00, 0x65, 0x00, 0x6e, 0x00,
+ 0x00, 0x00, 0x0c, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x6f, 0x00, 0x74, 0x00,
+ 0x68, 0x00, 0x65, 0x00, 0x72, 0x00, 0x44, 0x00, 0x69, 0x00, 0x6d, 0x00,
+ 0x65, 0x00, 0x6e, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x64, 0x00, 0x75, 0x00,
+ 0x6d, 0x00, 0x6d, 0x00, 0x79, 0x00, 0x41, 0x00, 0x74, 0x00, 0x74, 0x00,
+ 0x72, 0x00, 0x30, 0x00, 0x34, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x64, 0x00,
+ 0x75, 0x00, 0x6d, 0x00, 0x6d, 0x00, 0x79, 0x00, 0x41, 0x00, 0x74, 0x00,
+ 0x74, 0x00, 0x72, 0x00, 0x30, 0x00, 0x35, 0x00, 0x00, 0x00, 0x0b, 0x00,
+ 0x64, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x6d, 0x00, 0x79, 0x00, 0x41, 0x00,
+ 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x30, 0x00, 0x36, 0x00, 0x00, 0x00,
+ 0x0b, 0x00, 0x64, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x6d, 0x00, 0x79, 0x00,
+ 0x41, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x30, 0x00, 0x37, 0x00,
+ 0x00, 0x00, 0x0b, 0x00, 0x64, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x6d, 0x00,
+ 0x79, 0x00, 0x41, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x30, 0x00,
+ 0x38, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x64, 0x00, 0x75, 0x00, 0x6d, 0x00,
+ 0x6d, 0x00, 0x79, 0x00, 0x41, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00,
+ 0x30, 0x00, 0x39, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x64, 0x00, 0x75, 0x00,
+ 0x6d, 0x00, 0x6d, 0x00, 0x79, 0x00, 0x41, 0x00, 0x74, 0x00, 0x74, 0x00,
+ 0x72, 0x00, 0x30, 0x00, 0x61, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x64, 0x00,
+ 0x75, 0x00, 0x6d, 0x00, 0x6d, 0x00, 0x79, 0x00, 0x41, 0x00, 0x74, 0x00,
+ 0x74, 0x00, 0x72, 0x00, 0x30, 0x00, 0x62, 0x00, 0x00, 0x00, 0x0b, 0x00,
+ 0x64, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x6d, 0x00, 0x79, 0x00, 0x41, 0x00,
+ 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x30, 0x00, 0x63, 0x00, 0x00, 0x00,
+ 0x0b, 0x00, 0x64, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x6d, 0x00, 0x79, 0x00,
+ 0x41, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x30, 0x00, 0x64, 0x00,
+ 0x00, 0x00, 0x0b, 0x00, 0x64, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x6d, 0x00,
+ 0x79, 0x00, 0x41, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x30, 0x00,
+ 0x65, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x64, 0x00, 0x75, 0x00, 0x6d, 0x00,
+ 0x6d, 0x00, 0x79, 0x00, 0x41, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00,
+ 0x30, 0x00, 0x66, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x64, 0x00, 0x75, 0x00,
+ 0x6d, 0x00, 0x6d, 0x00, 0x79, 0x00, 0x41, 0x00, 0x74, 0x00, 0x74, 0x00,
+ 0x72, 0x00, 0x31, 0x00, 0x30, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x64, 0x00,
+ 0x75, 0x00, 0x6d, 0x00, 0x6d, 0x00, 0x79, 0x00, 0x41, 0x00, 0x74, 0x00,
+ 0x74, 0x00, 0x72, 0x00, 0x31, 0x00, 0x31, 0x00, 0x00, 0x00, 0x0b, 0x00,
+ 0x64, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x6d, 0x00, 0x79, 0x00, 0x41, 0x00,
+ 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x31, 0x00, 0x32, 0x00, 0x00, 0x00,
+ 0x0b, 0x00, 0x64, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x6d, 0x00, 0x79, 0x00,
+ 0x41, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x31, 0x00, 0x33, 0x00,
+ 0x00, 0x00, 0x0b, 0x00, 0x64, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x6d, 0x00,
+ 0x79, 0x00, 0x41, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x31, 0x00,
+ 0x34, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x64, 0x00, 0x75, 0x00, 0x6d, 0x00,
+ 0x6d, 0x00, 0x79, 0x00, 0x41, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00,
+ 0x31, 0x00, 0x35, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x64, 0x00, 0x75, 0x00,
+ 0x6d, 0x00, 0x6d, 0x00, 0x79, 0x00, 0x41, 0x00, 0x74, 0x00, 0x74, 0x00,
+ 0x72, 0x00, 0x31, 0x00, 0x36, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x64, 0x00,
+ 0x75, 0x00, 0x6d, 0x00, 0x6d, 0x00, 0x79, 0x00, 0x41, 0x00, 0x74, 0x00,
+ 0x74, 0x00, 0x72, 0x00, 0x31, 0x00, 0x37, 0x00, 0x00, 0x00, 0x0b, 0x00,
+ 0x64, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x6d, 0x00, 0x79, 0x00, 0x41, 0x00,
+ 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x31, 0x00, 0x38, 0x00, 0x00, 0x00,
+ 0x0b, 0x00, 0x64, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x6d, 0x00, 0x79, 0x00,
+ 0x41, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x31, 0x00, 0x39, 0x00,
+ 0x00, 0x00, 0x0b, 0x00, 0x64, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x6d, 0x00,
+ 0x79, 0x00, 0x41, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x31, 0x00,
+ 0x61, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x64, 0x00, 0x75, 0x00, 0x6d, 0x00,
+ 0x6d, 0x00, 0x79, 0x00, 0x41, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00,
+ 0x31, 0x00, 0x62, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x64, 0x00, 0x75, 0x00,
+ 0x6d, 0x00, 0x6d, 0x00, 0x79, 0x00, 0x41, 0x00, 0x74, 0x00, 0x74, 0x00,
+ 0x72, 0x00, 0x31, 0x00, 0x63, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x64, 0x00,
+ 0x75, 0x00, 0x6d, 0x00, 0x6d, 0x00, 0x79, 0x00, 0x41, 0x00, 0x74, 0x00,
+ 0x74, 0x00, 0x72, 0x00, 0x31, 0x00, 0x64, 0x00, 0x00, 0x00, 0x0b, 0x00,
+ 0x64, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x6d, 0x00, 0x79, 0x00, 0x41, 0x00,
+ 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x31, 0x00, 0x65, 0x00, 0x00, 0x00,
+ 0x0b, 0x00, 0x64, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x6d, 0x00, 0x79, 0x00,
+ 0x41, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x31, 0x00, 0x66, 0x00,
+ 0x00, 0x00, 0x0b, 0x00, 0x64, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x6d, 0x00,
+ 0x79, 0x00, 0x41, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x32, 0x00,
+ 0x30, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x64, 0x00, 0x75, 0x00, 0x6d, 0x00,
+ 0x6d, 0x00, 0x79, 0x00, 0x41, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00,
+ 0x32, 0x00, 0x31, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x64, 0x00, 0x75, 0x00,
+ 0x6d, 0x00, 0x6d, 0x00, 0x79, 0x00, 0x41, 0x00, 0x74, 0x00, 0x74, 0x00,
+ 0x72, 0x00, 0x32, 0x00, 0x32, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x64, 0x00,
+ 0x75, 0x00, 0x6d, 0x00, 0x6d, 0x00, 0x79, 0x00, 0x41, 0x00, 0x74, 0x00,
+ 0x74, 0x00, 0x72, 0x00, 0x32, 0x00, 0x33, 0x00, 0x00, 0x00, 0x0b, 0x00,
+ 0x64, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x6d, 0x00, 0x79, 0x00, 0x41, 0x00,
+ 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x32, 0x00, 0x34, 0x00, 0x00, 0x00,
+ 0x0b, 0x00, 0x64, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x6d, 0x00, 0x79, 0x00,
+ 0x41, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x32, 0x00, 0x35, 0x00,
+ 0x00, 0x00, 0x0b, 0x00, 0x64, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x6d, 0x00,
+ 0x79, 0x00, 0x41, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x32, 0x00,
+ 0x36, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x64, 0x00, 0x75, 0x00, 0x6d, 0x00,
+ 0x6d, 0x00, 0x79, 0x00, 0x41, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00,
+ 0x32, 0x00, 0x37, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x64, 0x00, 0x75, 0x00,
+ 0x6d, 0x00, 0x6d, 0x00, 0x79, 0x00, 0x41, 0x00, 0x74, 0x00, 0x74, 0x00,
+ 0x72, 0x00, 0x32, 0x00, 0x38, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x64, 0x00,
+ 0x75, 0x00, 0x6d, 0x00, 0x6d, 0x00, 0x79, 0x00, 0x41, 0x00, 0x74, 0x00,
+ 0x74, 0x00, 0x72, 0x00, 0x32, 0x00, 0x39, 0x00, 0x00, 0x00, 0x0b, 0x00,
+ 0x64, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x6d, 0x00, 0x79, 0x00, 0x41, 0x00,
+ 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x32, 0x00, 0x61, 0x00, 0x00, 0x00,
+ 0x0b, 0x00, 0x64, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x6d, 0x00, 0x79, 0x00,
+ 0x41, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x32, 0x00, 0x62, 0x00,
+ 0x00, 0x00, 0x0b, 0x00, 0x64, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x6d, 0x00,
+ 0x79, 0x00, 0x41, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x32, 0x00,
+ 0x63, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x64, 0x00, 0x75, 0x00, 0x6d, 0x00,
+ 0x6d, 0x00, 0x79, 0x00, 0x41, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00,
+ 0x32, 0x00, 0x64, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x64, 0x00, 0x75, 0x00,
+ 0x6d, 0x00, 0x6d, 0x00, 0x79, 0x00, 0x41, 0x00, 0x74, 0x00, 0x74, 0x00,
+ 0x72, 0x00, 0x32, 0x00, 0x65, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x64, 0x00,
+ 0x75, 0x00, 0x6d, 0x00, 0x6d, 0x00, 0x79, 0x00, 0x41, 0x00, 0x74, 0x00,
+ 0x74, 0x00, 0x72, 0x00, 0x32, 0x00, 0x66, 0x00, 0x00, 0x00, 0x0b, 0x00,
+ 0x64, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x6d, 0x00, 0x79, 0x00, 0x41, 0x00,
+ 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x33, 0x00, 0x30, 0x00, 0x00, 0x00,
+ 0x0b, 0x00, 0x64, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x6d, 0x00, 0x79, 0x00,
+ 0x41, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x33, 0x00, 0x31, 0x00,
+ 0x00, 0x00, 0x0b, 0x00, 0x64, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x6d, 0x00,
+ 0x79, 0x00, 0x41, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x33, 0x00,
+ 0x32, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x64, 0x00, 0x75, 0x00, 0x6d, 0x00,
+ 0x6d, 0x00, 0x79, 0x00, 0x41, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00,
+ 0x33, 0x00, 0x33, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x64, 0x00, 0x75, 0x00,
+ 0x6d, 0x00, 0x6d, 0x00, 0x79, 0x00, 0x41, 0x00, 0x74, 0x00, 0x74, 0x00,
+ 0x72, 0x00, 0x33, 0x00, 0x34, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x64, 0x00,
+ 0x75, 0x00, 0x6d, 0x00, 0x6d, 0x00, 0x79, 0x00, 0x41, 0x00, 0x74, 0x00,
+ 0x74, 0x00, 0x72, 0x00, 0x33, 0x00, 0x35, 0x00, 0x00, 0x00, 0x0b, 0x00,
+ 0x64, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x6d, 0x00, 0x79, 0x00, 0x41, 0x00,
+ 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x33, 0x00, 0x36, 0x00, 0x00, 0x00,
+ 0x0b, 0x00, 0x64, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x6d, 0x00, 0x79, 0x00,
+ 0x41, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x33, 0x00, 0x37, 0x00,
+ 0x00, 0x00, 0x0b, 0x00, 0x64, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x6d, 0x00,
+ 0x79, 0x00, 0x41, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x33, 0x00,
+ 0x38, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x64, 0x00, 0x75, 0x00, 0x6d, 0x00,
+ 0x6d, 0x00, 0x79, 0x00, 0x41, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00,
+ 0x33, 0x00, 0x39, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x64, 0x00, 0x75, 0x00,
+ 0x6d, 0x00, 0x6d, 0x00, 0x79, 0x00, 0x41, 0x00, 0x74, 0x00, 0x74, 0x00,
+ 0x72, 0x00, 0x33, 0x00, 0x61, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x64, 0x00,
+ 0x75, 0x00, 0x6d, 0x00, 0x6d, 0x00, 0x79, 0x00, 0x41, 0x00, 0x74, 0x00,
+ 0x74, 0x00, 0x72, 0x00, 0x33, 0x00, 0x62, 0x00, 0x00, 0x00, 0x0b, 0x00,
+ 0x64, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x6d, 0x00, 0x79, 0x00, 0x41, 0x00,
+ 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x33, 0x00, 0x63, 0x00, 0x00, 0x00,
+ 0x0b, 0x00, 0x64, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x6d, 0x00, 0x79, 0x00,
+ 0x41, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x33, 0x00, 0x64, 0x00,
+ 0x00, 0x00, 0x0b, 0x00, 0x64, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x6d, 0x00,
+ 0x79, 0x00, 0x41, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x33, 0x00,
+ 0x65, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x64, 0x00, 0x75, 0x00, 0x6d, 0x00,
+ 0x6d, 0x00, 0x79, 0x00, 0x41, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00,
+ 0x33, 0x00, 0x66, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x64, 0x00, 0x75, 0x00,
+ 0x6d, 0x00, 0x6d, 0x00, 0x79, 0x00, 0x41, 0x00, 0x74, 0x00, 0x74, 0x00,
+ 0x72, 0x00, 0x34, 0x00, 0x30, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x64, 0x00,
+ 0x75, 0x00, 0x6d, 0x00, 0x6d, 0x00, 0x79, 0x00, 0x41, 0x00, 0x74, 0x00,
+ 0x74, 0x00, 0x72, 0x00, 0x34, 0x00, 0x31, 0x00, 0x00, 0x00, 0x0b, 0x00,
+ 0x64, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x6d, 0x00, 0x79, 0x00, 0x41, 0x00,
+ 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x34, 0x00, 0x32, 0x00, 0x00, 0x00,
+ 0x0b, 0x00, 0x64, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x6d, 0x00, 0x79, 0x00,
+ 0x41, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x34, 0x00, 0x33, 0x00,
+ 0x00, 0x00, 0x0b, 0x00, 0x64, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x6d, 0x00,
+ 0x79, 0x00, 0x41, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x34, 0x00,
+ 0x34, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x64, 0x00, 0x75, 0x00, 0x6d, 0x00,
+ 0x6d, 0x00, 0x79, 0x00, 0x41, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00,
+ 0x34, 0x00, 0x35, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x64, 0x00, 0x75, 0x00,
+ 0x6d, 0x00, 0x6d, 0x00, 0x79, 0x00, 0x41, 0x00, 0x74, 0x00, 0x74, 0x00,
+ 0x72, 0x00, 0x34, 0x00, 0x36, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x64, 0x00,
+ 0x75, 0x00, 0x6d, 0x00, 0x6d, 0x00, 0x79, 0x00, 0x41, 0x00, 0x74, 0x00,
+ 0x74, 0x00, 0x72, 0x00, 0x34, 0x00, 0x37, 0x00, 0x00, 0x00, 0x0b, 0x00,
+ 0x64, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x6d, 0x00, 0x79, 0x00, 0x41, 0x00,
+ 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x34, 0x00, 0x38, 0x00, 0x00, 0x00,
+ 0x0b, 0x00, 0x64, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x6d, 0x00, 0x79, 0x00,
+ 0x41, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x34, 0x00, 0x39, 0x00,
+ 0x00, 0x00, 0x0b, 0x00, 0x64, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x6d, 0x00,
+ 0x79, 0x00, 0x41, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x34, 0x00,
+ 0x61, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x64, 0x00, 0x75, 0x00, 0x6d, 0x00,
+ 0x6d, 0x00, 0x79, 0x00, 0x41, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00,
+ 0x34, 0x00, 0x62, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x64, 0x00, 0x75, 0x00,
+ 0x6d, 0x00, 0x6d, 0x00, 0x79, 0x00, 0x41, 0x00, 0x74, 0x00, 0x74, 0x00,
+ 0x72, 0x00, 0x34, 0x00, 0x63, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x64, 0x00,
+ 0x75, 0x00, 0x6d, 0x00, 0x6d, 0x00, 0x79, 0x00, 0x41, 0x00, 0x74, 0x00,
+ 0x74, 0x00, 0x72, 0x00, 0x34, 0x00, 0x64, 0x00, 0x00, 0x00, 0x0b, 0x00,
+ 0x64, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x6d, 0x00, 0x79, 0x00, 0x41, 0x00,
+ 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x34, 0x00, 0x65, 0x00, 0x00, 0x00,
+ 0x0b, 0x00, 0x64, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x6d, 0x00, 0x79, 0x00,
+ 0x41, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x34, 0x00, 0x66, 0x00,
+ 0x00, 0x00, 0x0b, 0x00, 0x64, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x6d, 0x00,
+ 0x79, 0x00, 0x41, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x35, 0x00,
+ 0x30, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x64, 0x00, 0x75, 0x00, 0x6d, 0x00,
+ 0x6d, 0x00, 0x79, 0x00, 0x41, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00,
+ 0x35, 0x00, 0x31, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x64, 0x00, 0x75, 0x00,
+ 0x6d, 0x00, 0x6d, 0x00, 0x79, 0x00, 0x41, 0x00, 0x74, 0x00, 0x74, 0x00,
+ 0x72, 0x00, 0x35, 0x00, 0x32, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x64, 0x00,
+ 0x75, 0x00, 0x6d, 0x00, 0x6d, 0x00, 0x79, 0x00, 0x41, 0x00, 0x74, 0x00,
+ 0x74, 0x00, 0x72, 0x00, 0x35, 0x00, 0x33, 0x00, 0x00, 0x00, 0x0b, 0x00,
+ 0x64, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x6d, 0x00, 0x79, 0x00, 0x41, 0x00,
+ 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x35, 0x00, 0x34, 0x00, 0x00, 0x00,
+ 0x0b, 0x00, 0x64, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x6d, 0x00, 0x79, 0x00,
+ 0x41, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x35, 0x00, 0x35, 0x00,
+ 0x00, 0x00, 0x0d, 0x00, 0x77, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x64, 0x00,
+ 0x6f, 0x00, 0x77, 0x00, 0x4e, 0x00, 0x6f, 0x00, 0x54, 0x00, 0x69, 0x00,
+ 0x74, 0x00, 0x6c, 0x00, 0x65, 0x00, 0x00, 0x00, 0x09, 0x00, 0x54, 0x00,
+ 0x68, 0x00, 0x65, 0x00, 0x6d, 0x00, 0x65, 0x00, 0x2e, 0x00, 0x4f, 0x00,
+ 0x6e, 0x00, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00,
+ 0x6c, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x57, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40,
+ 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40,
+ 0x01, 0x02, 0x44, 0x00, 0x24, 0x0b, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x57, 0x00, 0x00, 0x00, 0xa0, 0x01, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x1c, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00,
+ 0x70, 0x00, 0x00, 0x00, 0x8c, 0x00, 0x00, 0x00, 0xa8, 0x00, 0x00, 0x00,
+ 0xc4, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00,
+ 0x18, 0x01, 0x00, 0x00, 0x34, 0x01, 0x00, 0x00, 0x50, 0x01, 0x00, 0x00,
+ 0x6c, 0x01, 0x00, 0x00, 0x88, 0x01, 0x00, 0x00, 0xa4, 0x01, 0x00, 0x00,
+ 0xc0, 0x01, 0x00, 0x00, 0xdc, 0x01, 0x00, 0x00, 0xf8, 0x01, 0x00, 0x00,
+ 0x14, 0x02, 0x00, 0x00, 0x30, 0x02, 0x00, 0x00, 0x4c, 0x02, 0x00, 0x00,
+ 0x68, 0x02, 0x00, 0x00, 0x84, 0x02, 0x00, 0x00, 0xa0, 0x02, 0x00, 0x00,
+ 0xbc, 0x02, 0x00, 0x00, 0xd8, 0x02, 0x00, 0x00, 0xf4, 0x02, 0x00, 0x00,
+ 0x10, 0x03, 0x00, 0x00, 0x2c, 0x03, 0x00, 0x00, 0x48, 0x03, 0x00, 0x00,
+ 0x64, 0x03, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, 0x9c, 0x03, 0x00, 0x00,
+ 0xb8, 0x03, 0x00, 0x00, 0xd4, 0x03, 0x00, 0x00, 0xf0, 0x03, 0x00, 0x00,
+ 0x0c, 0x04, 0x00, 0x00, 0x28, 0x04, 0x00, 0x00, 0x44, 0x04, 0x00, 0x00,
+ 0x60, 0x04, 0x00, 0x00, 0x7c, 0x04, 0x00, 0x00, 0x98, 0x04, 0x00, 0x00,
+ 0xb4, 0x04, 0x00, 0x00, 0xd0, 0x04, 0x00, 0x00, 0xec, 0x04, 0x00, 0x00,
+ 0x08, 0x05, 0x00, 0x00, 0x24, 0x05, 0x00, 0x00, 0x40, 0x05, 0x00, 0x00,
+ 0x5c, 0x05, 0x00, 0x00, 0x78, 0x05, 0x00, 0x00, 0x94, 0x05, 0x00, 0x00,
+ 0xb0, 0x05, 0x00, 0x00, 0xcc, 0x05, 0x00, 0x00, 0xe8, 0x05, 0x00, 0x00,
+ 0x04, 0x06, 0x00, 0x00, 0x20, 0x06, 0x00, 0x00, 0x3c, 0x06, 0x00, 0x00,
+ 0x58, 0x06, 0x00, 0x00, 0x74, 0x06, 0x00, 0x00, 0x90, 0x06, 0x00, 0x00,
+ 0xac, 0x06, 0x00, 0x00, 0xc8, 0x06, 0x00, 0x00, 0xe4, 0x06, 0x00, 0x00,
+ 0x00, 0x07, 0x00, 0x00, 0x1c, 0x07, 0x00, 0x00, 0x38, 0x07, 0x00, 0x00,
+ 0x54, 0x07, 0x00, 0x00, 0x70, 0x07, 0x00, 0x00, 0x8c, 0x07, 0x00, 0x00,
+ 0xa8, 0x07, 0x00, 0x00, 0xc4, 0x07, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00,
+ 0xfc, 0x07, 0x00, 0x00, 0x18, 0x08, 0x00, 0x00, 0x34, 0x08, 0x00, 0x00,
+ 0x50, 0x08, 0x00, 0x00, 0x6c, 0x08, 0x00, 0x00, 0x88, 0x08, 0x00, 0x00,
+ 0xa4, 0x08, 0x00, 0x00, 0xc0, 0x08, 0x00, 0x00, 0xdc, 0x08, 0x00, 0x00,
+ 0xf8, 0x08, 0x00, 0x00, 0x14, 0x09, 0x00, 0x00, 0x30, 0x09, 0x00, 0x00,
+ 0x4c, 0x09, 0x00, 0x00, 0x68, 0x09, 0x00, 0x00, 0x10, 0x00, 0x03, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10, 0x11, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10,
+ 0x11, 0x00, 0x00, 0x00, 0x10, 0x00, 0x03, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x08, 0x00, 0x00, 0x10, 0x41, 0x00, 0x00, 0x00, 0x10, 0x00, 0x03, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10, 0x41, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10,
+ 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00,
+ 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x01, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10,
+ 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00, 0x08, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00,
+ 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x01, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10,
+ 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00, 0x0b, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00,
+ 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x01, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10,
+ 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00, 0x0e, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00,
+ 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x01, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10,
+ 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00, 0x11, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00,
+ 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x01, 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10,
+ 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00, 0x14, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00,
+ 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x01, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10,
+ 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00, 0x17, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00,
+ 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x01, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10,
+ 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00, 0x1a, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00,
+ 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x01, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10,
+ 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00, 0x1d, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00,
+ 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x01, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10,
+ 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00, 0x20, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00,
+ 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x01, 0x00, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10,
+ 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00, 0x23, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00,
+ 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x01, 0x00, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10,
+ 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00, 0x26, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00,
+ 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x01, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10,
+ 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00, 0x29, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00,
+ 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x01, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10,
+ 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00, 0x2c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00,
+ 0x2d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x01, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10,
+ 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00, 0x2f, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00,
+ 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x01, 0x00, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10,
+ 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00, 0x32, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00,
+ 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x01, 0x00, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10,
+ 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00, 0x35, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00,
+ 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x01, 0x00, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10,
+ 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00,
+ 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x01, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10,
+ 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00, 0x3b, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00,
+ 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x01, 0x00, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10,
+ 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00, 0x3e, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00,
+ 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x01, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10,
+ 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00, 0x41, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00,
+ 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x01, 0x00, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10,
+ 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00, 0x44, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00,
+ 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x01, 0x00, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10,
+ 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00, 0x47, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00,
+ 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x01, 0x00, 0x49, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10,
+ 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00, 0x4a, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00,
+ 0x4b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x01, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10,
+ 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00, 0x4d, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00,
+ 0x4e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x01, 0x00, 0x4f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10,
+ 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00, 0x50, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00,
+ 0x51, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x01, 0x00, 0x52, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10,
+ 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00, 0x53, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00,
+ 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x01, 0x00, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10,
+ 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x03, 0x00, 0x56, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x08, 0x00, 0x00, 0x10, 0x09, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00,
+ 0x14, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x40, 0x01, 0x02, 0x44, 0x00, 0x7c, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00,
+ 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x03, 0x00, 0x57, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01,
+ 0x08, 0x00, 0x00, 0x1d, 0x00, 0x00, 0xff, 0xff, 0x01, 0x00, 0x01, 0x01,
+ 0x08, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0xff, 0x56, 0x00, 0x01, 0x01,
+ 0x08, 0x00, 0x00, 0x12, 0xff, 0xff, 0xff, 0xff
+};
+unsigned int system_arsc_len = 6416;
diff --git a/libs/androidfw/tests/data/overlay/overlay_arsc.h b/libs/androidfw/tests/data/overlay/overlay_arsc.h
index 5bd98b2..2d59417 100644
--- a/libs/androidfw/tests/data/overlay/overlay_arsc.h
+++ b/libs/androidfw/tests/data/overlay/overlay_arsc.h
@@ -1,17 +1,22 @@
unsigned char overlay_arsc[] = {
- 0x02, 0x00, 0x0c, 0x00, 0x10, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
- 0x01, 0x00, 0x1c, 0x00, 0x40, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x74, 0x00,
+ 0x02, 0x00, 0x0c, 0x00, 0xa8, 0x04, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x1c, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00,
+ 0x1a, 0x00, 0x72, 0x00, 0x65, 0x00, 0x73, 0x00, 0x2f, 0x00, 0x64, 0x00,
+ 0x72, 0x00, 0x61, 0x00, 0x77, 0x00, 0x61, 0x00, 0x62, 0x00, 0x6c, 0x00,
+ 0x65, 0x00, 0x2f, 0x00, 0x64, 0x00, 0x72, 0x00, 0x61, 0x00, 0x77, 0x00,
+ 0x61, 0x00, 0x62, 0x00, 0x6c, 0x00, 0x65, 0x00, 0x31, 0x00, 0x2e, 0x00,
+ 0x70, 0x00, 0x6e, 0x00, 0x67, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x74, 0x00,
0x65, 0x00, 0x73, 0x00, 0x74, 0x00, 0x32, 0x00, 0x2d, 0x00, 0x6f, 0x00,
0x76, 0x00, 0x65, 0x00, 0x72, 0x00, 0x6c, 0x00, 0x61, 0x00, 0x79, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x01, 0xc4, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x01, 0x20, 0x04, 0x00, 0x00,
0x7f, 0x00, 0x00, 0x00, 0x63, 0x00, 0x6f, 0x00, 0x6d, 0x00, 0x2e, 0x00,
0x61, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x72, 0x00, 0x6f, 0x00, 0x69, 0x00,
0x64, 0x00, 0x2e, 0x00, 0x74, 0x00, 0x65, 0x00, 0x73, 0x00, 0x74, 0x00,
0x2e, 0x00, 0x62, 0x00, 0x61, 0x00, 0x73, 0x00, 0x69, 0x00, 0x63, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x2e, 0x00, 0x6f, 0x00, 0x76, 0x00, 0x65, 0x00, 0x72, 0x00, 0x6c, 0x00,
+ 0x61, 0x00, 0x79, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -28,21 +33,30 @@ unsigned char overlay_arsc[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00,
- 0x03, 0x00, 0x00, 0x00, 0x74, 0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1c, 0x00, 0x54, 0x00, 0x00, 0x00,
- 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x0c, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x61, 0x00,
- 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x00, 0x00, 0x06, 0x00, 0x73, 0x00,
- 0x74, 0x00, 0x72, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x67, 0x00, 0x00, 0x00,
- 0x05, 0x00, 0x61, 0x00, 0x72, 0x00, 0x72, 0x00, 0x61, 0x00, 0x79, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1c, 0x00, 0x50, 0x00, 0x00, 0x00,
- 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x0e, 0x00, 0x00, 0x00, 0x05, 0x00, 0x74, 0x00, 0x65, 0x00, 0x73, 0x00,
- 0x74, 0x00, 0x32, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x69, 0x00, 0x6e, 0x00,
- 0x74, 0x00, 0x65, 0x00, 0x67, 0x00, 0x65, 0x00, 0x72, 0x00, 0x41, 0x00,
- 0x72, 0x00, 0x72, 0x00, 0x61, 0x00, 0x79, 0x00, 0x31, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x9c, 0x01, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1c, 0x00, 0x7c, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x0c, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
+ 0x3e, 0x00, 0x00, 0x00, 0x04, 0x00, 0x61, 0x00, 0x74, 0x00, 0x74, 0x00,
+ 0x72, 0x00, 0x00, 0x00, 0x08, 0x00, 0x64, 0x00, 0x72, 0x00, 0x61, 0x00,
+ 0x77, 0x00, 0x61, 0x00, 0x62, 0x00, 0x6c, 0x00, 0x65, 0x00, 0x00, 0x00,
+ 0x06, 0x00, 0x73, 0x00, 0x74, 0x00, 0x72, 0x00, 0x69, 0x00, 0x6e, 0x00,
+ 0x67, 0x00, 0x00, 0x00, 0x05, 0x00, 0x61, 0x00, 0x72, 0x00, 0x72, 0x00,
+ 0x61, 0x00, 0x79, 0x00, 0x00, 0x00, 0x05, 0x00, 0x64, 0x00, 0x69, 0x00,
+ 0x6d, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1c, 0x00,
+ 0x94, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00,
+ 0x42, 0x00, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, 0x09, 0x00, 0x64, 0x00,
+ 0x72, 0x00, 0x61, 0x00, 0x77, 0x00, 0x61, 0x00, 0x62, 0x00, 0x6c, 0x00,
+ 0x65, 0x00, 0x31, 0x00, 0x00, 0x00, 0x05, 0x00, 0x74, 0x00, 0x65, 0x00,
+ 0x73, 0x00, 0x74, 0x00, 0x32, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x69, 0x00,
+ 0x6e, 0x00, 0x74, 0x00, 0x65, 0x00, 0x67, 0x00, 0x65, 0x00, 0x72, 0x00,
+ 0x41, 0x00, 0x72, 0x00, 0x72, 0x00, 0x61, 0x00, 0x79, 0x00, 0x31, 0x00,
+ 0x00, 0x00, 0x06, 0x00, 0x64, 0x00, 0x69, 0x00, 0x6d, 0x00, 0x65, 0x00,
+ 0x6e, 0x00, 0x31, 0x00, 0x00, 0x00, 0x06, 0x00, 0x64, 0x00, 0x69, 0x00,
+ 0x6d, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00,
0x02, 0x02, 0x10, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x14, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -55,15 +69,35 @@ unsigned char overlay_arsc[] = {
0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x03,
0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x14, 0x00, 0x00, 0x00,
0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x01, 0x02, 0x44, 0x00, 0x70, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0x01, 0x02, 0x44, 0x00, 0x58, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x03,
+ 0x01, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x14, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x02, 0x44, 0x00, 0x70, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x10, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x08, 0x00, 0x00, 0x10,
0x0a, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x02, 0x08, 0x00, 0x00, 0x10,
- 0x0b, 0x00, 0x00, 0x00
+ 0x0b, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x44, 0x00, 0x6c, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00,
+ 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x05, 0x02, 0x38, 0x00, 0x00,
+ 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x05,
+ 0x01, 0x0c, 0x00, 0x00
};
-unsigned int overlay_arsc_len = 784;
+unsigned int overlay_arsc_len = 1192;
diff --git a/libs/androidfw/tests/data/overlay/res/drawable/drawable1.png b/libs/androidfw/tests/data/overlay/res/drawable/drawable1.png
new file mode 100644
index 0000000..a7045ed
--- /dev/null
+++ b/libs/androidfw/tests/data/overlay/res/drawable/drawable1.png
Binary files differ
diff --git a/libs/androidfw/tests/data/overlay/res/values/values.xml b/libs/androidfw/tests/data/overlay/res/values/values.xml
index 3e1af98..3fd4ae9 100644
--- a/libs/androidfw/tests/data/overlay/res/values/values.xml
+++ b/libs/androidfw/tests/data/overlay/res/values/values.xml
@@ -20,4 +20,8 @@
<item>10</item>
<item>11</item>
</integer-array>
+
+ <dimen name="dimen1">56sp</dimen>
+ <dimen name="dimen2">12dp</dimen>
+
</resources>
diff --git a/libs/androidfw/tests/data/override/AndroidManifest.xml b/libs/androidfw/tests/data/override/AndroidManifest.xml
new file mode 100644
index 0000000..ed26054
--- /dev/null
+++ b/libs/androidfw/tests/data/override/AndroidManifest.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.test.override">
+ <application>
+ </application>
+</manifest>
diff --git a/libs/androidfw/tests/data/override/R.h b/libs/androidfw/tests/data/override/R.h
new file mode 100644
index 0000000..a57c6b1
--- /dev/null
+++ b/libs/androidfw/tests/data/override/R.h
@@ -0,0 +1,16 @@
+#ifndef __BASE_R_H
+#define __BASE_R_H
+
+namespace override {
+namespace R {
+
+namespace string {
+ enum {
+ string1 = 0x7f020000, // default
+ };
+}
+
+} // namespace R
+} // namespace base
+
+#endif // __BASE_R_H
diff --git a/libs/androidfw/tests/data/override/build b/libs/androidfw/tests/data/override/build
new file mode 100755
index 0000000..f6ba33d
--- /dev/null
+++ b/libs/androidfw/tests/data/override/build
@@ -0,0 +1,6 @@
+#!/bin/bash
+
+aapt package -M AndroidManifest.xml -S res -F bundle.apk -f && \
+unzip bundle.apk resources.arsc && \
+mv resources.arsc override.arsc && \
+xxd -i override.arsc > override_arsc.h
diff --git a/libs/androidfw/tests/data/override/override_arsc.h b/libs/androidfw/tests/data/override/override_arsc.h
new file mode 100644
index 0000000..2598635
--- /dev/null
+++ b/libs/androidfw/tests/data/override/override_arsc.h
@@ -0,0 +1,53 @@
+unsigned char override_arsc[] = {
+ 0x02, 0x00, 0x0c, 0x00, 0x50, 0x02, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x1c, 0x00, 0x34, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x73, 0x00,
+ 0x74, 0x00, 0x72, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x67, 0x00, 0x31, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x01, 0x10, 0x02, 0x00, 0x00,
+ 0x7f, 0x00, 0x00, 0x00, 0x63, 0x00, 0x6f, 0x00, 0x6d, 0x00, 0x2e, 0x00,
+ 0x61, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x72, 0x00, 0x6f, 0x00, 0x69, 0x00,
+ 0x64, 0x00, 0x2e, 0x00, 0x74, 0x00, 0x65, 0x00, 0x73, 0x00, 0x74, 0x00,
+ 0x2e, 0x00, 0x6f, 0x00, 0x76, 0x00, 0x65, 0x00, 0x72, 0x00, 0x72, 0x00,
+ 0x69, 0x00, 0x64, 0x00, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x60, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1c, 0x00, 0x40, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x0c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x61, 0x00, 0x74, 0x00, 0x74, 0x00,
+ 0x72, 0x00, 0x00, 0x00, 0x06, 0x00, 0x73, 0x00, 0x74, 0x00, 0x72, 0x00,
+ 0x69, 0x00, 0x6e, 0x00, 0x67, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1c, 0x00,
+ 0x34, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x73, 0x00, 0x74, 0x00, 0x72, 0x00,
+ 0x69, 0x00, 0x6e, 0x00, 0x67, 0x00, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x02, 0x02, 0x10, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x14, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x02, 0x44, 0x00, 0x58, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x03,
+ 0x00, 0x00, 0x00, 0x00
+};
+unsigned int override_arsc_len = 592;
diff --git a/libs/androidfw/tests/data/override/res/values/values.xml b/libs/androidfw/tests/data/override/res/values/values.xml
new file mode 100644
index 0000000..7b607ef
--- /dev/null
+++ b/libs/androidfw/tests/data/override/res/values/values.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="string1">string1</string>
+</resources>
diff --git a/libs/androidfw/tests/data/system/R.h b/libs/androidfw/tests/data/system/R.h
index 27f25fe..0f96bda 100644
--- a/libs/androidfw/tests/data/system/R.h
+++ b/libs/androidfw/tests/data/system/R.h
@@ -22,8 +22,11 @@ namespace R {
namespace attr {
enum {
- background = 0x01010000, // default
- foreground = 0x01010001, // default
+ background = 0x01010000, // default
+ foreground = 0x01010001, // default
+ some_dimen = 0x01010002, // default
+ another_dimen = 0x01010003, // default
+ windowNoTitle = 0x01010056, // default
};
}
diff --git a/libs/androidfw/tests/data/system/res/values/filler.xml b/libs/androidfw/tests/data/system/res/values/filler.xml
new file mode 100644
index 0000000..27af8dc
--- /dev/null
+++ b/libs/androidfw/tests/data/system/res/values/filler.xml
@@ -0,0 +1,168 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- Filler so we can test the protected attribute "windowNoTitle" -->
+ <java-symbol name="dummyAttr04" type="attr" id="0x01010004" />
+ <java-symbol name="dummyAttr05" type="attr" id="0x01010005" />
+ <java-symbol name="dummyAttr06" type="attr" id="0x01010006" />
+ <java-symbol name="dummyAttr07" type="attr" id="0x01010007" />
+ <java-symbol name="dummyAttr08" type="attr" id="0x01010008" />
+ <java-symbol name="dummyAttr09" type="attr" id="0x01010009" />
+ <java-symbol name="dummyAttr0a" type="attr" id="0x0101000a" />
+ <java-symbol name="dummyAttr0b" type="attr" id="0x0101000b" />
+ <java-symbol name="dummyAttr0c" type="attr" id="0x0101000c" />
+ <java-symbol name="dummyAttr0d" type="attr" id="0x0101000d" />
+ <java-symbol name="dummyAttr0e" type="attr" id="0x0101000e" />
+ <java-symbol name="dummyAttr0f" type="attr" id="0x0101000f" />
+ <java-symbol name="dummyAttr10" type="attr" id="0x01010010" />
+ <java-symbol name="dummyAttr11" type="attr" id="0x01010011" />
+ <java-symbol name="dummyAttr12" type="attr" id="0x01010012" />
+ <java-symbol name="dummyAttr13" type="attr" id="0x01010013" />
+ <java-symbol name="dummyAttr14" type="attr" id="0x01010014" />
+ <java-symbol name="dummyAttr15" type="attr" id="0x01010015" />
+ <java-symbol name="dummyAttr16" type="attr" id="0x01010016" />
+ <java-symbol name="dummyAttr17" type="attr" id="0x01010017" />
+ <java-symbol name="dummyAttr18" type="attr" id="0x01010018" />
+ <java-symbol name="dummyAttr19" type="attr" id="0x01010019" />
+ <java-symbol name="dummyAttr1a" type="attr" id="0x0101001a" />
+ <java-symbol name="dummyAttr1b" type="attr" id="0x0101001b" />
+ <java-symbol name="dummyAttr1c" type="attr" id="0x0101001c" />
+ <java-symbol name="dummyAttr1d" type="attr" id="0x0101001d" />
+ <java-symbol name="dummyAttr1e" type="attr" id="0x0101001e" />
+ <java-symbol name="dummyAttr1f" type="attr" id="0x0101001f" />
+ <java-symbol name="dummyAttr20" type="attr" id="0x01010020" />
+ <java-symbol name="dummyAttr21" type="attr" id="0x01010021" />
+ <java-symbol name="dummyAttr22" type="attr" id="0x01010022" />
+ <java-symbol name="dummyAttr23" type="attr" id="0x01010023" />
+ <java-symbol name="dummyAttr24" type="attr" id="0x01010024" />
+ <java-symbol name="dummyAttr25" type="attr" id="0x01010025" />
+ <java-symbol name="dummyAttr26" type="attr" id="0x01010026" />
+ <java-symbol name="dummyAttr27" type="attr" id="0x01010027" />
+ <java-symbol name="dummyAttr28" type="attr" id="0x01010028" />
+ <java-symbol name="dummyAttr29" type="attr" id="0x01010029" />
+ <java-symbol name="dummyAttr2a" type="attr" id="0x0101002a" />
+ <java-symbol name="dummyAttr2b" type="attr" id="0x0101002b" />
+ <java-symbol name="dummyAttr2c" type="attr" id="0x0101002c" />
+ <java-symbol name="dummyAttr2d" type="attr" id="0x0101002d" />
+ <java-symbol name="dummyAttr2e" type="attr" id="0x0101002e" />
+ <java-symbol name="dummyAttr2f" type="attr" id="0x0101002f" />
+ <java-symbol name="dummyAttr30" type="attr" id="0x01010030" />
+ <java-symbol name="dummyAttr31" type="attr" id="0x01010031" />
+ <java-symbol name="dummyAttr32" type="attr" id="0x01010032" />
+ <java-symbol name="dummyAttr33" type="attr" id="0x01010033" />
+ <java-symbol name="dummyAttr34" type="attr" id="0x01010034" />
+ <java-symbol name="dummyAttr35" type="attr" id="0x01010035" />
+ <java-symbol name="dummyAttr36" type="attr" id="0x01010036" />
+ <java-symbol name="dummyAttr37" type="attr" id="0x01010037" />
+ <java-symbol name="dummyAttr38" type="attr" id="0x01010038" />
+ <java-symbol name="dummyAttr39" type="attr" id="0x01010039" />
+ <java-symbol name="dummyAttr3a" type="attr" id="0x0101003a" />
+ <java-symbol name="dummyAttr3b" type="attr" id="0x0101003b" />
+ <java-symbol name="dummyAttr3c" type="attr" id="0x0101003c" />
+ <java-symbol name="dummyAttr3d" type="attr" id="0x0101003d" />
+ <java-symbol name="dummyAttr3e" type="attr" id="0x0101003e" />
+ <java-symbol name="dummyAttr3f" type="attr" id="0x0101003f" />
+ <java-symbol name="dummyAttr40" type="attr" id="0x01010040" />
+ <java-symbol name="dummyAttr41" type="attr" id="0x01010041" />
+ <java-symbol name="dummyAttr42" type="attr" id="0x01010042" />
+ <java-symbol name="dummyAttr43" type="attr" id="0x01010043" />
+ <java-symbol name="dummyAttr44" type="attr" id="0x01010044" />
+ <java-symbol name="dummyAttr45" type="attr" id="0x01010045" />
+ <java-symbol name="dummyAttr46" type="attr" id="0x01010046" />
+ <java-symbol name="dummyAttr47" type="attr" id="0x01010047" />
+ <java-symbol name="dummyAttr48" type="attr" id="0x01010048" />
+ <java-symbol name="dummyAttr49" type="attr" id="0x01010049" />
+ <java-symbol name="dummyAttr4a" type="attr" id="0x0101004a" />
+ <java-symbol name="dummyAttr4b" type="attr" id="0x0101004b" />
+ <java-symbol name="dummyAttr4c" type="attr" id="0x0101004c" />
+ <java-symbol name="dummyAttr4d" type="attr" id="0x0101004d" />
+ <java-symbol name="dummyAttr4e" type="attr" id="0x0101004e" />
+ <java-symbol name="dummyAttr4f" type="attr" id="0x0101004f" />
+ <java-symbol name="dummyAttr50" type="attr" id="0x01010050" />
+ <java-symbol name="dummyAttr51" type="attr" id="0x01010051" />
+ <java-symbol name="dummyAttr52" type="attr" id="0x01010052" />
+ <java-symbol name="dummyAttr53" type="attr" id="0x01010053" />
+ <java-symbol name="dummyAttr54" type="attr" id="0x01010054" />
+ <java-symbol name="dummyAttr55" type="attr" id="0x01010055" />
+ <attr name="dummyAttr04" format="reference"/>
+ <attr name="dummyAttr05" format="reference"/>
+ <attr name="dummyAttr06" format="reference"/>
+ <attr name="dummyAttr07" format="reference"/>
+ <attr name="dummyAttr08" format="reference"/>
+ <attr name="dummyAttr09" format="reference"/>
+ <attr name="dummyAttr0a" format="reference"/>
+ <attr name="dummyAttr0b" format="reference"/>
+ <attr name="dummyAttr0c" format="reference"/>
+ <attr name="dummyAttr0d" format="reference"/>
+ <attr name="dummyAttr0e" format="reference"/>
+ <attr name="dummyAttr0f" format="reference"/>
+ <attr name="dummyAttr10" format="reference"/>
+ <attr name="dummyAttr11" format="reference"/>
+ <attr name="dummyAttr12" format="reference"/>
+ <attr name="dummyAttr13" format="reference"/>
+ <attr name="dummyAttr14" format="reference"/>
+ <attr name="dummyAttr15" format="reference"/>
+ <attr name="dummyAttr16" format="reference"/>
+ <attr name="dummyAttr17" format="reference"/>
+ <attr name="dummyAttr18" format="reference"/>
+ <attr name="dummyAttr19" format="reference"/>
+ <attr name="dummyAttr1a" format="reference"/>
+ <attr name="dummyAttr1b" format="reference"/>
+ <attr name="dummyAttr1c" format="reference"/>
+ <attr name="dummyAttr1d" format="reference"/>
+ <attr name="dummyAttr1e" format="reference"/>
+ <attr name="dummyAttr1f" format="reference"/>
+ <attr name="dummyAttr20" format="reference"/>
+ <attr name="dummyAttr21" format="reference"/>
+ <attr name="dummyAttr22" format="reference"/>
+ <attr name="dummyAttr23" format="reference"/>
+ <attr name="dummyAttr24" format="reference"/>
+ <attr name="dummyAttr25" format="reference"/>
+ <attr name="dummyAttr26" format="reference"/>
+ <attr name="dummyAttr27" format="reference"/>
+ <attr name="dummyAttr28" format="reference"/>
+ <attr name="dummyAttr29" format="reference"/>
+ <attr name="dummyAttr2a" format="reference"/>
+ <attr name="dummyAttr2b" format="reference"/>
+ <attr name="dummyAttr2c" format="reference"/>
+ <attr name="dummyAttr2d" format="reference"/>
+ <attr name="dummyAttr2e" format="reference"/>
+ <attr name="dummyAttr2f" format="reference"/>
+ <attr name="dummyAttr30" format="reference"/>
+ <attr name="dummyAttr31" format="reference"/>
+ <attr name="dummyAttr32" format="reference"/>
+ <attr name="dummyAttr33" format="reference"/>
+ <attr name="dummyAttr34" format="reference"/>
+ <attr name="dummyAttr35" format="reference"/>
+ <attr name="dummyAttr36" format="reference"/>
+ <attr name="dummyAttr37" format="reference"/>
+ <attr name="dummyAttr38" format="reference"/>
+ <attr name="dummyAttr39" format="reference"/>
+ <attr name="dummyAttr3a" format="reference"/>
+ <attr name="dummyAttr3b" format="reference"/>
+ <attr name="dummyAttr3c" format="reference"/>
+ <attr name="dummyAttr3d" format="reference"/>
+ <attr name="dummyAttr3e" format="reference"/>
+ <attr name="dummyAttr3f" format="reference"/>
+ <attr name="dummyAttr40" format="reference"/>
+ <attr name="dummyAttr41" format="reference"/>
+ <attr name="dummyAttr42" format="reference"/>
+ <attr name="dummyAttr43" format="reference"/>
+ <attr name="dummyAttr44" format="reference"/>
+ <attr name="dummyAttr45" format="reference"/>
+ <attr name="dummyAttr46" format="reference"/>
+ <attr name="dummyAttr47" format="reference"/>
+ <attr name="dummyAttr48" format="reference"/>
+ <attr name="dummyAttr49" format="reference"/>
+ <attr name="dummyAttr4a" format="reference"/>
+ <attr name="dummyAttr4b" format="reference"/>
+ <attr name="dummyAttr4c" format="reference"/>
+ <attr name="dummyAttr4d" format="reference"/>
+ <attr name="dummyAttr4e" format="reference"/>
+ <attr name="dummyAttr4f" format="reference"/>
+ <attr name="dummyAttr50" format="reference"/>
+ <attr name="dummyAttr51" format="reference"/>
+ <attr name="dummyAttr52" format="reference"/>
+ <attr name="dummyAttr53" format="reference"/>
+ <attr name="dummyAttr54" format="reference"/>
+ <attr name="dummyAttr55" format="reference"/>
+</resources> \ No newline at end of file
diff --git a/libs/androidfw/tests/data/system/res/values/themes.xml b/libs/androidfw/tests/data/system/res/values/themes.xml
index 35d43c7..a426bd3 100644
--- a/libs/androidfw/tests/data/system/res/values/themes.xml
+++ b/libs/androidfw/tests/data/system/res/values/themes.xml
@@ -17,12 +17,20 @@
<resources>
<public name="background" type="attr" id="0x01010000"/>
<public name="foreground" type="attr" id="0x01010001"/>
+ <public name="someDimen" type="attr" id="0x01010002" />
+ <public name="anotherDimen" type="attr" id="0x01010003" />
+ <!-- attributes 0x01010004 to 0x01010055 are in filler.xml -->
+ <public name="windowNoTitle" type="attr" id="0x01010056" />
<public name="Theme.One" type="style" id="0x01020000"/>
<attr name="background" format="color|reference"/>
<attr name="foreground" format="color|reference"/>
+ <attr name="someDimen" format="dimension|reference"/>
+ <attr name="anotherDimen" format="dimension|reference"/>
+ <attr name="windowNoTitle" format="boolean|reference"/>
<style name="Theme.One" parent="">
<item name="android:background">#ff0000</item>
<item name="android:foreground">#000000</item>
+ <item name="android:windowNoTitle">true</item>
</style>
</resources>
diff --git a/libs/androidfw/tests/data/system/system_arsc.h b/libs/androidfw/tests/data/system/system_arsc.h
index 215ecae..e157a0e 100644
--- a/libs/androidfw/tests/data/system/system_arsc.h
+++ b/libs/androidfw/tests/data/system/system_arsc.h
@@ -1,8 +1,8 @@
unsigned char system_arsc[] = {
- 0x02, 0x00, 0x0c, 0x00, 0x18, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x0c, 0x00, 0x10, 0x19, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x01, 0x00, 0x1c, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x01, 0xf0, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x01, 0xe8, 0x18, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x72, 0x00,
0x6f, 0x00, 0x69, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -25,45 +25,514 @@ unsigned char system_arsc[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00,
- 0x02, 0x00, 0x00, 0x00, 0x60, 0x01, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x60, 0x01, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1c, 0x00, 0x40, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x0c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x61, 0x00, 0x74, 0x00, 0x74, 0x00,
0x72, 0x00, 0x00, 0x00, 0x05, 0x00, 0x73, 0x00, 0x74, 0x00, 0x79, 0x00,
0x6c, 0x00, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1c, 0x00,
- 0x70, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x68, 0x0a, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x7c, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
- 0x0a, 0x00, 0x62, 0x00, 0x61, 0x00, 0x63, 0x00, 0x6b, 0x00, 0x67, 0x00,
- 0x72, 0x00, 0x6f, 0x00, 0x75, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x00, 0x00,
- 0x0a, 0x00, 0x66, 0x00, 0x6f, 0x00, 0x72, 0x00, 0x65, 0x00, 0x67, 0x00,
- 0x72, 0x00, 0x6f, 0x00, 0x75, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x00, 0x00,
- 0x09, 0x00, 0x54, 0x00, 0x68, 0x00, 0x65, 0x00, 0x6d, 0x00, 0x65, 0x00,
- 0x2e, 0x00, 0x4f, 0x00, 0x6e, 0x00, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x02, 0x02, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
- 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40,
- 0x01, 0x02, 0x44, 0x00, 0x84, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
- 0x02, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
+ 0x46, 0x00, 0x00, 0x00, 0x62, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00,
+ 0x96, 0x00, 0x00, 0x00, 0xb0, 0x00, 0x00, 0x00, 0xca, 0x00, 0x00, 0x00,
+ 0xe4, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x18, 0x01, 0x00, 0x00,
+ 0x32, 0x01, 0x00, 0x00, 0x4c, 0x01, 0x00, 0x00, 0x66, 0x01, 0x00, 0x00,
+ 0x80, 0x01, 0x00, 0x00, 0x9a, 0x01, 0x00, 0x00, 0xb4, 0x01, 0x00, 0x00,
+ 0xce, 0x01, 0x00, 0x00, 0xe8, 0x01, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00,
+ 0x1c, 0x02, 0x00, 0x00, 0x36, 0x02, 0x00, 0x00, 0x50, 0x02, 0x00, 0x00,
+ 0x6a, 0x02, 0x00, 0x00, 0x84, 0x02, 0x00, 0x00, 0x9e, 0x02, 0x00, 0x00,
+ 0xb8, 0x02, 0x00, 0x00, 0xd2, 0x02, 0x00, 0x00, 0xec, 0x02, 0x00, 0x00,
+ 0x06, 0x03, 0x00, 0x00, 0x20, 0x03, 0x00, 0x00, 0x3a, 0x03, 0x00, 0x00,
+ 0x54, 0x03, 0x00, 0x00, 0x6e, 0x03, 0x00, 0x00, 0x88, 0x03, 0x00, 0x00,
+ 0xa2, 0x03, 0x00, 0x00, 0xbc, 0x03, 0x00, 0x00, 0xd6, 0x03, 0x00, 0x00,
+ 0xf0, 0x03, 0x00, 0x00, 0x0a, 0x04, 0x00, 0x00, 0x24, 0x04, 0x00, 0x00,
+ 0x3e, 0x04, 0x00, 0x00, 0x58, 0x04, 0x00, 0x00, 0x72, 0x04, 0x00, 0x00,
+ 0x8c, 0x04, 0x00, 0x00, 0xa6, 0x04, 0x00, 0x00, 0xc0, 0x04, 0x00, 0x00,
+ 0xda, 0x04, 0x00, 0x00, 0xf4, 0x04, 0x00, 0x00, 0x0e, 0x05, 0x00, 0x00,
+ 0x28, 0x05, 0x00, 0x00, 0x42, 0x05, 0x00, 0x00, 0x5c, 0x05, 0x00, 0x00,
+ 0x76, 0x05, 0x00, 0x00, 0x90, 0x05, 0x00, 0x00, 0xaa, 0x05, 0x00, 0x00,
+ 0xc4, 0x05, 0x00, 0x00, 0xde, 0x05, 0x00, 0x00, 0xf8, 0x05, 0x00, 0x00,
+ 0x12, 0x06, 0x00, 0x00, 0x2c, 0x06, 0x00, 0x00, 0x46, 0x06, 0x00, 0x00,
+ 0x60, 0x06, 0x00, 0x00, 0x7a, 0x06, 0x00, 0x00, 0x94, 0x06, 0x00, 0x00,
+ 0xae, 0x06, 0x00, 0x00, 0xc8, 0x06, 0x00, 0x00, 0xe2, 0x06, 0x00, 0x00,
+ 0xfc, 0x06, 0x00, 0x00, 0x16, 0x07, 0x00, 0x00, 0x30, 0x07, 0x00, 0x00,
+ 0x4a, 0x07, 0x00, 0x00, 0x64, 0x07, 0x00, 0x00, 0x7e, 0x07, 0x00, 0x00,
+ 0x98, 0x07, 0x00, 0x00, 0xb2, 0x07, 0x00, 0x00, 0xcc, 0x07, 0x00, 0x00,
+ 0xe6, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x1a, 0x08, 0x00, 0x00,
+ 0x34, 0x08, 0x00, 0x00, 0x4e, 0x08, 0x00, 0x00, 0x68, 0x08, 0x00, 0x00,
+ 0x82, 0x08, 0x00, 0x00, 0x9c, 0x08, 0x00, 0x00, 0xb6, 0x08, 0x00, 0x00,
+ 0xd4, 0x08, 0x00, 0x00, 0x0a, 0x00, 0x62, 0x00, 0x61, 0x00, 0x63, 0x00,
+ 0x6b, 0x00, 0x67, 0x00, 0x72, 0x00, 0x6f, 0x00, 0x75, 0x00, 0x6e, 0x00,
+ 0x64, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x66, 0x00, 0x6f, 0x00, 0x72, 0x00,
+ 0x65, 0x00, 0x67, 0x00, 0x72, 0x00, 0x6f, 0x00, 0x75, 0x00, 0x6e, 0x00,
+ 0x64, 0x00, 0x00, 0x00, 0x09, 0x00, 0x73, 0x00, 0x6f, 0x00, 0x6d, 0x00,
+ 0x65, 0x00, 0x44, 0x00, 0x69, 0x00, 0x6d, 0x00, 0x65, 0x00, 0x6e, 0x00,
+ 0x00, 0x00, 0x0c, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x6f, 0x00, 0x74, 0x00,
+ 0x68, 0x00, 0x65, 0x00, 0x72, 0x00, 0x44, 0x00, 0x69, 0x00, 0x6d, 0x00,
+ 0x65, 0x00, 0x6e, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x64, 0x00, 0x75, 0x00,
+ 0x6d, 0x00, 0x6d, 0x00, 0x79, 0x00, 0x41, 0x00, 0x74, 0x00, 0x74, 0x00,
+ 0x72, 0x00, 0x30, 0x00, 0x34, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x64, 0x00,
+ 0x75, 0x00, 0x6d, 0x00, 0x6d, 0x00, 0x79, 0x00, 0x41, 0x00, 0x74, 0x00,
+ 0x74, 0x00, 0x72, 0x00, 0x30, 0x00, 0x35, 0x00, 0x00, 0x00, 0x0b, 0x00,
+ 0x64, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x6d, 0x00, 0x79, 0x00, 0x41, 0x00,
+ 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x30, 0x00, 0x36, 0x00, 0x00, 0x00,
+ 0x0b, 0x00, 0x64, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x6d, 0x00, 0x79, 0x00,
+ 0x41, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x30, 0x00, 0x37, 0x00,
+ 0x00, 0x00, 0x0b, 0x00, 0x64, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x6d, 0x00,
+ 0x79, 0x00, 0x41, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x30, 0x00,
+ 0x38, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x64, 0x00, 0x75, 0x00, 0x6d, 0x00,
+ 0x6d, 0x00, 0x79, 0x00, 0x41, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00,
+ 0x30, 0x00, 0x39, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x64, 0x00, 0x75, 0x00,
+ 0x6d, 0x00, 0x6d, 0x00, 0x79, 0x00, 0x41, 0x00, 0x74, 0x00, 0x74, 0x00,
+ 0x72, 0x00, 0x30, 0x00, 0x61, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x64, 0x00,
+ 0x75, 0x00, 0x6d, 0x00, 0x6d, 0x00, 0x79, 0x00, 0x41, 0x00, 0x74, 0x00,
+ 0x74, 0x00, 0x72, 0x00, 0x30, 0x00, 0x62, 0x00, 0x00, 0x00, 0x0b, 0x00,
+ 0x64, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x6d, 0x00, 0x79, 0x00, 0x41, 0x00,
+ 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x30, 0x00, 0x63, 0x00, 0x00, 0x00,
+ 0x0b, 0x00, 0x64, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x6d, 0x00, 0x79, 0x00,
+ 0x41, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x30, 0x00, 0x64, 0x00,
+ 0x00, 0x00, 0x0b, 0x00, 0x64, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x6d, 0x00,
+ 0x79, 0x00, 0x41, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x30, 0x00,
+ 0x65, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x64, 0x00, 0x75, 0x00, 0x6d, 0x00,
+ 0x6d, 0x00, 0x79, 0x00, 0x41, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00,
+ 0x30, 0x00, 0x66, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x64, 0x00, 0x75, 0x00,
+ 0x6d, 0x00, 0x6d, 0x00, 0x79, 0x00, 0x41, 0x00, 0x74, 0x00, 0x74, 0x00,
+ 0x72, 0x00, 0x31, 0x00, 0x30, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x64, 0x00,
+ 0x75, 0x00, 0x6d, 0x00, 0x6d, 0x00, 0x79, 0x00, 0x41, 0x00, 0x74, 0x00,
+ 0x74, 0x00, 0x72, 0x00, 0x31, 0x00, 0x31, 0x00, 0x00, 0x00, 0x0b, 0x00,
+ 0x64, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x6d, 0x00, 0x79, 0x00, 0x41, 0x00,
+ 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x31, 0x00, 0x32, 0x00, 0x00, 0x00,
+ 0x0b, 0x00, 0x64, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x6d, 0x00, 0x79, 0x00,
+ 0x41, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x31, 0x00, 0x33, 0x00,
+ 0x00, 0x00, 0x0b, 0x00, 0x64, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x6d, 0x00,
+ 0x79, 0x00, 0x41, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x31, 0x00,
+ 0x34, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x64, 0x00, 0x75, 0x00, 0x6d, 0x00,
+ 0x6d, 0x00, 0x79, 0x00, 0x41, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00,
+ 0x31, 0x00, 0x35, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x64, 0x00, 0x75, 0x00,
+ 0x6d, 0x00, 0x6d, 0x00, 0x79, 0x00, 0x41, 0x00, 0x74, 0x00, 0x74, 0x00,
+ 0x72, 0x00, 0x31, 0x00, 0x36, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x64, 0x00,
+ 0x75, 0x00, 0x6d, 0x00, 0x6d, 0x00, 0x79, 0x00, 0x41, 0x00, 0x74, 0x00,
+ 0x74, 0x00, 0x72, 0x00, 0x31, 0x00, 0x37, 0x00, 0x00, 0x00, 0x0b, 0x00,
+ 0x64, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x6d, 0x00, 0x79, 0x00, 0x41, 0x00,
+ 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x31, 0x00, 0x38, 0x00, 0x00, 0x00,
+ 0x0b, 0x00, 0x64, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x6d, 0x00, 0x79, 0x00,
+ 0x41, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x31, 0x00, 0x39, 0x00,
+ 0x00, 0x00, 0x0b, 0x00, 0x64, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x6d, 0x00,
+ 0x79, 0x00, 0x41, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x31, 0x00,
+ 0x61, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x64, 0x00, 0x75, 0x00, 0x6d, 0x00,
+ 0x6d, 0x00, 0x79, 0x00, 0x41, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00,
+ 0x31, 0x00, 0x62, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x64, 0x00, 0x75, 0x00,
+ 0x6d, 0x00, 0x6d, 0x00, 0x79, 0x00, 0x41, 0x00, 0x74, 0x00, 0x74, 0x00,
+ 0x72, 0x00, 0x31, 0x00, 0x63, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x64, 0x00,
+ 0x75, 0x00, 0x6d, 0x00, 0x6d, 0x00, 0x79, 0x00, 0x41, 0x00, 0x74, 0x00,
+ 0x74, 0x00, 0x72, 0x00, 0x31, 0x00, 0x64, 0x00, 0x00, 0x00, 0x0b, 0x00,
+ 0x64, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x6d, 0x00, 0x79, 0x00, 0x41, 0x00,
+ 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x31, 0x00, 0x65, 0x00, 0x00, 0x00,
+ 0x0b, 0x00, 0x64, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x6d, 0x00, 0x79, 0x00,
+ 0x41, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x31, 0x00, 0x66, 0x00,
+ 0x00, 0x00, 0x0b, 0x00, 0x64, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x6d, 0x00,
+ 0x79, 0x00, 0x41, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x32, 0x00,
+ 0x30, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x64, 0x00, 0x75, 0x00, 0x6d, 0x00,
+ 0x6d, 0x00, 0x79, 0x00, 0x41, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00,
+ 0x32, 0x00, 0x31, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x64, 0x00, 0x75, 0x00,
+ 0x6d, 0x00, 0x6d, 0x00, 0x79, 0x00, 0x41, 0x00, 0x74, 0x00, 0x74, 0x00,
+ 0x72, 0x00, 0x32, 0x00, 0x32, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x64, 0x00,
+ 0x75, 0x00, 0x6d, 0x00, 0x6d, 0x00, 0x79, 0x00, 0x41, 0x00, 0x74, 0x00,
+ 0x74, 0x00, 0x72, 0x00, 0x32, 0x00, 0x33, 0x00, 0x00, 0x00, 0x0b, 0x00,
+ 0x64, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x6d, 0x00, 0x79, 0x00, 0x41, 0x00,
+ 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x32, 0x00, 0x34, 0x00, 0x00, 0x00,
+ 0x0b, 0x00, 0x64, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x6d, 0x00, 0x79, 0x00,
+ 0x41, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x32, 0x00, 0x35, 0x00,
+ 0x00, 0x00, 0x0b, 0x00, 0x64, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x6d, 0x00,
+ 0x79, 0x00, 0x41, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x32, 0x00,
+ 0x36, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x64, 0x00, 0x75, 0x00, 0x6d, 0x00,
+ 0x6d, 0x00, 0x79, 0x00, 0x41, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00,
+ 0x32, 0x00, 0x37, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x64, 0x00, 0x75, 0x00,
+ 0x6d, 0x00, 0x6d, 0x00, 0x79, 0x00, 0x41, 0x00, 0x74, 0x00, 0x74, 0x00,
+ 0x72, 0x00, 0x32, 0x00, 0x38, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x64, 0x00,
+ 0x75, 0x00, 0x6d, 0x00, 0x6d, 0x00, 0x79, 0x00, 0x41, 0x00, 0x74, 0x00,
+ 0x74, 0x00, 0x72, 0x00, 0x32, 0x00, 0x39, 0x00, 0x00, 0x00, 0x0b, 0x00,
+ 0x64, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x6d, 0x00, 0x79, 0x00, 0x41, 0x00,
+ 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x32, 0x00, 0x61, 0x00, 0x00, 0x00,
+ 0x0b, 0x00, 0x64, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x6d, 0x00, 0x79, 0x00,
+ 0x41, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x32, 0x00, 0x62, 0x00,
+ 0x00, 0x00, 0x0b, 0x00, 0x64, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x6d, 0x00,
+ 0x79, 0x00, 0x41, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x32, 0x00,
+ 0x63, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x64, 0x00, 0x75, 0x00, 0x6d, 0x00,
+ 0x6d, 0x00, 0x79, 0x00, 0x41, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00,
+ 0x32, 0x00, 0x64, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x64, 0x00, 0x75, 0x00,
+ 0x6d, 0x00, 0x6d, 0x00, 0x79, 0x00, 0x41, 0x00, 0x74, 0x00, 0x74, 0x00,
+ 0x72, 0x00, 0x32, 0x00, 0x65, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x64, 0x00,
+ 0x75, 0x00, 0x6d, 0x00, 0x6d, 0x00, 0x79, 0x00, 0x41, 0x00, 0x74, 0x00,
+ 0x74, 0x00, 0x72, 0x00, 0x32, 0x00, 0x66, 0x00, 0x00, 0x00, 0x0b, 0x00,
+ 0x64, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x6d, 0x00, 0x79, 0x00, 0x41, 0x00,
+ 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x33, 0x00, 0x30, 0x00, 0x00, 0x00,
+ 0x0b, 0x00, 0x64, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x6d, 0x00, 0x79, 0x00,
+ 0x41, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x33, 0x00, 0x31, 0x00,
+ 0x00, 0x00, 0x0b, 0x00, 0x64, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x6d, 0x00,
+ 0x79, 0x00, 0x41, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x33, 0x00,
+ 0x32, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x64, 0x00, 0x75, 0x00, 0x6d, 0x00,
+ 0x6d, 0x00, 0x79, 0x00, 0x41, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00,
+ 0x33, 0x00, 0x33, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x64, 0x00, 0x75, 0x00,
+ 0x6d, 0x00, 0x6d, 0x00, 0x79, 0x00, 0x41, 0x00, 0x74, 0x00, 0x74, 0x00,
+ 0x72, 0x00, 0x33, 0x00, 0x34, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x64, 0x00,
+ 0x75, 0x00, 0x6d, 0x00, 0x6d, 0x00, 0x79, 0x00, 0x41, 0x00, 0x74, 0x00,
+ 0x74, 0x00, 0x72, 0x00, 0x33, 0x00, 0x35, 0x00, 0x00, 0x00, 0x0b, 0x00,
+ 0x64, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x6d, 0x00, 0x79, 0x00, 0x41, 0x00,
+ 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x33, 0x00, 0x36, 0x00, 0x00, 0x00,
+ 0x0b, 0x00, 0x64, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x6d, 0x00, 0x79, 0x00,
+ 0x41, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x33, 0x00, 0x37, 0x00,
+ 0x00, 0x00, 0x0b, 0x00, 0x64, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x6d, 0x00,
+ 0x79, 0x00, 0x41, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x33, 0x00,
+ 0x38, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x64, 0x00, 0x75, 0x00, 0x6d, 0x00,
+ 0x6d, 0x00, 0x79, 0x00, 0x41, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00,
+ 0x33, 0x00, 0x39, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x64, 0x00, 0x75, 0x00,
+ 0x6d, 0x00, 0x6d, 0x00, 0x79, 0x00, 0x41, 0x00, 0x74, 0x00, 0x74, 0x00,
+ 0x72, 0x00, 0x33, 0x00, 0x61, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x64, 0x00,
+ 0x75, 0x00, 0x6d, 0x00, 0x6d, 0x00, 0x79, 0x00, 0x41, 0x00, 0x74, 0x00,
+ 0x74, 0x00, 0x72, 0x00, 0x33, 0x00, 0x62, 0x00, 0x00, 0x00, 0x0b, 0x00,
+ 0x64, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x6d, 0x00, 0x79, 0x00, 0x41, 0x00,
+ 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x33, 0x00, 0x63, 0x00, 0x00, 0x00,
+ 0x0b, 0x00, 0x64, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x6d, 0x00, 0x79, 0x00,
+ 0x41, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x33, 0x00, 0x64, 0x00,
+ 0x00, 0x00, 0x0b, 0x00, 0x64, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x6d, 0x00,
+ 0x79, 0x00, 0x41, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x33, 0x00,
+ 0x65, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x64, 0x00, 0x75, 0x00, 0x6d, 0x00,
+ 0x6d, 0x00, 0x79, 0x00, 0x41, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00,
+ 0x33, 0x00, 0x66, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x64, 0x00, 0x75, 0x00,
+ 0x6d, 0x00, 0x6d, 0x00, 0x79, 0x00, 0x41, 0x00, 0x74, 0x00, 0x74, 0x00,
+ 0x72, 0x00, 0x34, 0x00, 0x30, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x64, 0x00,
+ 0x75, 0x00, 0x6d, 0x00, 0x6d, 0x00, 0x79, 0x00, 0x41, 0x00, 0x74, 0x00,
+ 0x74, 0x00, 0x72, 0x00, 0x34, 0x00, 0x31, 0x00, 0x00, 0x00, 0x0b, 0x00,
+ 0x64, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x6d, 0x00, 0x79, 0x00, 0x41, 0x00,
+ 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x34, 0x00, 0x32, 0x00, 0x00, 0x00,
+ 0x0b, 0x00, 0x64, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x6d, 0x00, 0x79, 0x00,
+ 0x41, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x34, 0x00, 0x33, 0x00,
+ 0x00, 0x00, 0x0b, 0x00, 0x64, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x6d, 0x00,
+ 0x79, 0x00, 0x41, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x34, 0x00,
+ 0x34, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x64, 0x00, 0x75, 0x00, 0x6d, 0x00,
+ 0x6d, 0x00, 0x79, 0x00, 0x41, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00,
+ 0x34, 0x00, 0x35, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x64, 0x00, 0x75, 0x00,
+ 0x6d, 0x00, 0x6d, 0x00, 0x79, 0x00, 0x41, 0x00, 0x74, 0x00, 0x74, 0x00,
+ 0x72, 0x00, 0x34, 0x00, 0x36, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x64, 0x00,
+ 0x75, 0x00, 0x6d, 0x00, 0x6d, 0x00, 0x79, 0x00, 0x41, 0x00, 0x74, 0x00,
+ 0x74, 0x00, 0x72, 0x00, 0x34, 0x00, 0x37, 0x00, 0x00, 0x00, 0x0b, 0x00,
+ 0x64, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x6d, 0x00, 0x79, 0x00, 0x41, 0x00,
+ 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x34, 0x00, 0x38, 0x00, 0x00, 0x00,
+ 0x0b, 0x00, 0x64, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x6d, 0x00, 0x79, 0x00,
+ 0x41, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x34, 0x00, 0x39, 0x00,
+ 0x00, 0x00, 0x0b, 0x00, 0x64, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x6d, 0x00,
+ 0x79, 0x00, 0x41, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x34, 0x00,
+ 0x61, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x64, 0x00, 0x75, 0x00, 0x6d, 0x00,
+ 0x6d, 0x00, 0x79, 0x00, 0x41, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00,
+ 0x34, 0x00, 0x62, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x64, 0x00, 0x75, 0x00,
+ 0x6d, 0x00, 0x6d, 0x00, 0x79, 0x00, 0x41, 0x00, 0x74, 0x00, 0x74, 0x00,
+ 0x72, 0x00, 0x34, 0x00, 0x63, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x64, 0x00,
+ 0x75, 0x00, 0x6d, 0x00, 0x6d, 0x00, 0x79, 0x00, 0x41, 0x00, 0x74, 0x00,
+ 0x74, 0x00, 0x72, 0x00, 0x34, 0x00, 0x64, 0x00, 0x00, 0x00, 0x0b, 0x00,
+ 0x64, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x6d, 0x00, 0x79, 0x00, 0x41, 0x00,
+ 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x34, 0x00, 0x65, 0x00, 0x00, 0x00,
+ 0x0b, 0x00, 0x64, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x6d, 0x00, 0x79, 0x00,
+ 0x41, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x34, 0x00, 0x66, 0x00,
+ 0x00, 0x00, 0x0b, 0x00, 0x64, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x6d, 0x00,
+ 0x79, 0x00, 0x41, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x35, 0x00,
+ 0x30, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x64, 0x00, 0x75, 0x00, 0x6d, 0x00,
+ 0x6d, 0x00, 0x79, 0x00, 0x41, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00,
+ 0x35, 0x00, 0x31, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x64, 0x00, 0x75, 0x00,
+ 0x6d, 0x00, 0x6d, 0x00, 0x79, 0x00, 0x41, 0x00, 0x74, 0x00, 0x74, 0x00,
+ 0x72, 0x00, 0x35, 0x00, 0x32, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x64, 0x00,
+ 0x75, 0x00, 0x6d, 0x00, 0x6d, 0x00, 0x79, 0x00, 0x41, 0x00, 0x74, 0x00,
+ 0x74, 0x00, 0x72, 0x00, 0x35, 0x00, 0x33, 0x00, 0x00, 0x00, 0x0b, 0x00,
+ 0x64, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x6d, 0x00, 0x79, 0x00, 0x41, 0x00,
+ 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x35, 0x00, 0x34, 0x00, 0x00, 0x00,
+ 0x0b, 0x00, 0x64, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x6d, 0x00, 0x79, 0x00,
+ 0x41, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x35, 0x00, 0x35, 0x00,
+ 0x00, 0x00, 0x0d, 0x00, 0x77, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x64, 0x00,
+ 0x6f, 0x00, 0x77, 0x00, 0x4e, 0x00, 0x6f, 0x00, 0x54, 0x00, 0x69, 0x00,
+ 0x74, 0x00, 0x6c, 0x00, 0x65, 0x00, 0x00, 0x00, 0x09, 0x00, 0x54, 0x00,
+ 0x68, 0x00, 0x65, 0x00, 0x6d, 0x00, 0x65, 0x00, 0x2e, 0x00, 0x4f, 0x00,
+ 0x6e, 0x00, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00,
+ 0x6c, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x57, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40,
+ 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x1c, 0x00, 0x00, 0x00, 0x10, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
- 0x08, 0x00, 0x00, 0x10, 0x11, 0x00, 0x00, 0x00, 0x10, 0x00, 0x03, 0x00,
- 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40,
+ 0x01, 0x02, 0x44, 0x00, 0x24, 0x0b, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x57, 0x00, 0x00, 0x00, 0xa0, 0x01, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x1c, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00,
+ 0x70, 0x00, 0x00, 0x00, 0x8c, 0x00, 0x00, 0x00, 0xa8, 0x00, 0x00, 0x00,
+ 0xc4, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00,
+ 0x18, 0x01, 0x00, 0x00, 0x34, 0x01, 0x00, 0x00, 0x50, 0x01, 0x00, 0x00,
+ 0x6c, 0x01, 0x00, 0x00, 0x88, 0x01, 0x00, 0x00, 0xa4, 0x01, 0x00, 0x00,
+ 0xc0, 0x01, 0x00, 0x00, 0xdc, 0x01, 0x00, 0x00, 0xf8, 0x01, 0x00, 0x00,
+ 0x14, 0x02, 0x00, 0x00, 0x30, 0x02, 0x00, 0x00, 0x4c, 0x02, 0x00, 0x00,
+ 0x68, 0x02, 0x00, 0x00, 0x84, 0x02, 0x00, 0x00, 0xa0, 0x02, 0x00, 0x00,
+ 0xbc, 0x02, 0x00, 0x00, 0xd8, 0x02, 0x00, 0x00, 0xf4, 0x02, 0x00, 0x00,
+ 0x10, 0x03, 0x00, 0x00, 0x2c, 0x03, 0x00, 0x00, 0x48, 0x03, 0x00, 0x00,
+ 0x64, 0x03, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, 0x9c, 0x03, 0x00, 0x00,
+ 0xb8, 0x03, 0x00, 0x00, 0xd4, 0x03, 0x00, 0x00, 0xf0, 0x03, 0x00, 0x00,
+ 0x0c, 0x04, 0x00, 0x00, 0x28, 0x04, 0x00, 0x00, 0x44, 0x04, 0x00, 0x00,
+ 0x60, 0x04, 0x00, 0x00, 0x7c, 0x04, 0x00, 0x00, 0x98, 0x04, 0x00, 0x00,
+ 0xb4, 0x04, 0x00, 0x00, 0xd0, 0x04, 0x00, 0x00, 0xec, 0x04, 0x00, 0x00,
+ 0x08, 0x05, 0x00, 0x00, 0x24, 0x05, 0x00, 0x00, 0x40, 0x05, 0x00, 0x00,
+ 0x5c, 0x05, 0x00, 0x00, 0x78, 0x05, 0x00, 0x00, 0x94, 0x05, 0x00, 0x00,
+ 0xb0, 0x05, 0x00, 0x00, 0xcc, 0x05, 0x00, 0x00, 0xe8, 0x05, 0x00, 0x00,
+ 0x04, 0x06, 0x00, 0x00, 0x20, 0x06, 0x00, 0x00, 0x3c, 0x06, 0x00, 0x00,
+ 0x58, 0x06, 0x00, 0x00, 0x74, 0x06, 0x00, 0x00, 0x90, 0x06, 0x00, 0x00,
+ 0xac, 0x06, 0x00, 0x00, 0xc8, 0x06, 0x00, 0x00, 0xe4, 0x06, 0x00, 0x00,
+ 0x00, 0x07, 0x00, 0x00, 0x1c, 0x07, 0x00, 0x00, 0x38, 0x07, 0x00, 0x00,
+ 0x54, 0x07, 0x00, 0x00, 0x70, 0x07, 0x00, 0x00, 0x8c, 0x07, 0x00, 0x00,
+ 0xa8, 0x07, 0x00, 0x00, 0xc4, 0x07, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00,
+ 0xfc, 0x07, 0x00, 0x00, 0x18, 0x08, 0x00, 0x00, 0x34, 0x08, 0x00, 0x00,
+ 0x50, 0x08, 0x00, 0x00, 0x6c, 0x08, 0x00, 0x00, 0x88, 0x08, 0x00, 0x00,
+ 0xa4, 0x08, 0x00, 0x00, 0xc0, 0x08, 0x00, 0x00, 0xdc, 0x08, 0x00, 0x00,
+ 0xf8, 0x08, 0x00, 0x00, 0x14, 0x09, 0x00, 0x00, 0x30, 0x09, 0x00, 0x00,
+ 0x4c, 0x09, 0x00, 0x00, 0x68, 0x09, 0x00, 0x00, 0x10, 0x00, 0x03, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10, 0x11, 0x00, 0x00, 0x00,
- 0x02, 0x02, 0x10, 0x00, 0x14, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
- 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x02, 0x44, 0x00,
- 0x70, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
- 0x48, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10,
+ 0x11, 0x00, 0x00, 0x00, 0x10, 0x00, 0x03, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x08, 0x00, 0x00, 0x10, 0x41, 0x00, 0x00, 0x00, 0x10, 0x00, 0x03, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10, 0x41, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10,
+ 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00,
+ 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x01, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10,
+ 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00, 0x08, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00,
+ 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x01, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10,
+ 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00, 0x0b, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00,
+ 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x01, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10,
+ 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00, 0x0e, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00,
+ 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x01, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10,
+ 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00, 0x11, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00,
+ 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x01, 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10,
+ 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00, 0x14, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00,
+ 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x01, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10,
+ 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00, 0x17, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00,
+ 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x01, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10,
+ 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00, 0x1a, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00,
+ 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x01, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10,
+ 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00, 0x1d, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00,
+ 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x01, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10,
+ 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00, 0x20, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00,
+ 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x01, 0x00, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10,
+ 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00, 0x23, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00,
+ 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x01, 0x00, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10,
+ 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00, 0x26, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00,
+ 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x01, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10,
+ 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00, 0x29, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00,
+ 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x01, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10,
+ 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00, 0x2c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00,
+ 0x2d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x01, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10,
+ 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00, 0x2f, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00,
+ 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x01, 0x00, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10,
+ 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00, 0x32, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00,
+ 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x01, 0x00, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10,
+ 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00, 0x35, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00,
+ 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x01, 0x00, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10,
+ 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00,
+ 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x01, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10,
+ 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00, 0x3b, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00,
+ 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x01, 0x00, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10,
+ 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00, 0x3e, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00,
+ 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x01, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10,
+ 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00, 0x41, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00,
+ 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x01, 0x00, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10,
+ 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00, 0x44, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00,
+ 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x01, 0x00, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10,
+ 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00, 0x47, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00,
+ 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x01, 0x00, 0x49, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10,
+ 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00, 0x4a, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00,
+ 0x4b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x01, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10,
+ 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00, 0x4d, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00,
+ 0x4e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x01, 0x00, 0x4f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10,
+ 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00, 0x50, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00,
+ 0x51, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x01, 0x00, 0x52, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10,
+ 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00, 0x53, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00,
+ 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x01, 0x00, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10,
+ 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x03, 0x00, 0x56, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x08, 0x00, 0x00, 0x10, 0x09, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00,
+ 0x14, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x40, 0x01, 0x02, 0x44, 0x00, 0x7c, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00,
+ 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x03, 0x00,
- 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x01, 0x01, 0x08, 0x00, 0x00, 0x1d, 0x00, 0x00, 0xff, 0xff,
- 0x01, 0x00, 0x01, 0x01, 0x08, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0xff
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x03, 0x00, 0x57, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01,
+ 0x08, 0x00, 0x00, 0x1d, 0x00, 0x00, 0xff, 0xff, 0x01, 0x00, 0x01, 0x01,
+ 0x08, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0xff, 0x56, 0x00, 0x01, 0x01,
+ 0x08, 0x00, 0x00, 0x12, 0xff, 0xff, 0xff, 0xff
};
-unsigned int system_arsc_len = 792;
+unsigned int system_arsc_len = 6416;
diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp
index 35051b7..54cfaea 100644
--- a/libs/hwui/FontRenderer.cpp
+++ b/libs/hwui/FontRenderer.cpp
@@ -683,14 +683,6 @@ bool FontRenderer::renderTextOnPath(const SkPaint* paint, const Rect* clip, cons
return mDrawn;
}
-void FontRenderer::removeFont(const Font* font) {
- mActiveFonts.remove(font->getDescription());
-
- if (mCurrentFont == font) {
- mCurrentFont = nullptr;
- }
-}
-
void FontRenderer::blurImage(uint8_t** image, int32_t width, int32_t height, float radius) {
uint32_t intRadius = Blur::convertRadiusToInt(radius);
#ifdef ANDROID_ENABLE_RENDERSCRIPT
diff --git a/libs/hwui/FontRenderer.h b/libs/hwui/FontRenderer.h
index dfb107c..3da20ee 100644
--- a/libs/hwui/FontRenderer.h
+++ b/libs/hwui/FontRenderer.h
@@ -151,8 +151,6 @@ private:
float x3, float y3, float u3, float v3,
float x4, float y4, float u4, float v4, CacheTexture* texture);
- void removeFont(const Font* font);
-
void checkTextureUpdate();
void setTextureDirty() {
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 2292ef4..c5e709e 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -181,6 +181,16 @@ void OpenGLRenderer::discardFramebuffer(float left, float top, float right, floa
}
void OpenGLRenderer::clear(float left, float top, float right, float bottom, bool opaque) {
+#ifdef QCOM_BSP_LEGACY
+ mRenderState.scissor().setEnabled(true);
+ mRenderState.scissor().set(left, getViewportHeight() - bottom, right - left, bottom - top);
+ glClear(GL_COLOR_BUFFER_BIT);
+ mDirty = true;
+ if (opaque) {
+ mRenderState.scissor().reset();
+ return;
+ }
+#else
if (!opaque) {
mRenderState.scissor().setEnabled(true);
mRenderState.scissor().set(left, getViewportHeight() - bottom, right - left, bottom - top);
@@ -190,6 +200,7 @@ void OpenGLRenderer::clear(float left, float top, float right, float bottom, boo
}
mRenderState.scissor().reset();
+#endif
}
void OpenGLRenderer::startTilingCurrentClip(bool opaque, bool expand) {
@@ -2325,12 +2336,15 @@ void OpenGLRenderer::drawPath(const SkPath* path, const SkPaint* paint) {
PathTexture* texture = mCaches.pathCache.get(path, paint);
if (!texture) return;
- const AutoTexture autoCleanup(texture);
const float x = texture->left - texture->offset;
const float y = texture->top - texture->offset;
drawPathTexture(texture, x, y, paint);
+
+ if (texture->cleanup) {
+ mCaches.pathCache.remove(path, paint);
+ }
mDirty = true;
}
diff --git a/libs/hwui/PathCache.cpp b/libs/hwui/PathCache.cpp
index 3af640f..3236f6f 100644
--- a/libs/hwui/PathCache.cpp
+++ b/libs/hwui/PathCache.cpp
@@ -400,6 +400,13 @@ PathTexture* PathCache::get(const SkPath* path, const SkPaint* paint) {
return texture;
}
+void PathCache::remove(const SkPath* path, const SkPaint* paint)
+{
+ PathDescription entry(kShapePath, paint);
+ entry.shape.path.mGenerationID = path->getGenerationID();
+ mCache.remove(entry);
+}
+
void PathCache::precache(const SkPath* path, const SkPaint* paint) {
if (!Caches::getInstance().tasks.canRunTasks()) {
return;
diff --git a/libs/hwui/PathCache.h b/libs/hwui/PathCache.h
index 7014863..c529915 100644
--- a/libs/hwui/PathCache.h
+++ b/libs/hwui/PathCache.h
@@ -201,6 +201,7 @@ public:
PathTexture* getArc(float width, float height, float startAngle, float sweepAngle,
bool useCenter, const SkPaint* paint);
PathTexture* get(const SkPath* path, const SkPaint* paint);
+ void remove(const SkPath* path, const SkPaint* paint);
/**
* Removes the specified path. This is meant to be called from threads
diff --git a/libs/hwui/SpotShadow.cpp b/libs/hwui/SpotShadow.cpp
index 7a2b9af..5d36a03 100644
--- a/libs/hwui/SpotShadow.cpp
+++ b/libs/hwui/SpotShadow.cpp
@@ -742,7 +742,7 @@ inline void genNewPenumbraAndPairWithUmbra(const Vector2* penumbra, int penumbra
// vertex's location.
int newPenumbraNumber = indexDelta - 1;
- float accumulatedDeltaLength[newPenumbraNumber];
+ float accumulatedDeltaLength[indexDelta];
float totalDeltaLength = 0;
// To save time, cache the previous umbra vertex info outside the loop
diff --git a/libs/hwui/font/Font.cpp b/libs/hwui/font/Font.cpp
index 5de64a4..762f2bb 100644
--- a/libs/hwui/font/Font.cpp
+++ b/libs/hwui/font/Font.cpp
@@ -64,8 +64,6 @@ Font::FontDescription::FontDescription(const SkPaint* paint, const SkMatrix& ras
}
Font::~Font() {
- mState->removeFont(this);
-
for (uint32_t i = 0; i < mCachedGlyphs.size(); i++) {
delete mCachedGlyphs.valueAt(i);
}
diff --git a/libs/storage/IMountService.cpp b/libs/storage/IMountService.cpp
index c643ed0..f7379b6 100644
--- a/libs/storage/IMountService.cpp
+++ b/libs/storage/IMountService.cpp
@@ -50,6 +50,7 @@ enum {
TRANSACTION_isExternalStorageEmulated,
TRANSACTION_decryptStorage,
TRANSACTION_encryptStorage,
+ TRANSACTION_encryptWipeStorage = IBinder::FIRST_CALL_TRANSACTION + 61,
};
class BpMountService: public BpInterface<IMountService>
@@ -551,6 +552,23 @@ public:
}
return reply.readInt32();
}
+
+ int32_t encryptWipeStorage(const String16& password)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IMountService::getInterfaceDescriptor());
+ data.writeString16(password);
+ if (remote()->transact(TRANSACTION_encryptWipeStorage, data, &reply) != NO_ERROR) {
+ ALOGD("encryptWipeStorage could not contact remote\n");
+ return -1;
+ }
+ int32_t err = reply.readExceptionCode();
+ if (err < 0) {
+ ALOGD("encryptWipeStorage caught exception %d\n", err);
+ return err;
+ }
+ return reply.readInt32();
+ }
};
IMPLEMENT_META_INTERFACE(MountService, "IMountService")
diff --git a/location/java/android/location/GeoFenceParams.aidl b/location/java/android/location/GeoFenceParams.aidl
new file mode 100644
index 0000000..3e9be4c
--- /dev/null
+++ b/location/java/android/location/GeoFenceParams.aidl
@@ -0,0 +1,23 @@
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+ *
+ * Not a Contribution, Apache license notifications and license are retained
+ * for attribution purposes only.
+ *
+ * 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.location;
+
+parcelable GeoFenceParams;
diff --git a/location/java/android/location/GeoFenceParams.java b/location/java/android/location/GeoFenceParams.java
new file mode 100644
index 0000000..aa6e245
--- /dev/null
+++ b/location/java/android/location/GeoFenceParams.java
@@ -0,0 +1,132 @@
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+ *
+ * Not a Contribution, Apache license notifications and license are retained
+ * for attribution purposes only.
+ *
+ * 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.location;
+
+import android.app.PendingIntent;
+import android.os.Binder;
+import android.os.Parcel;
+import android.os.Parcelable;
+import java.io.PrintWriter;
+
+/**
+ * GeoFenceParams for internal use
+ * {@hide}
+ */
+public class GeoFenceParams implements Parcelable {
+ public static final int ENTERING = 1;
+ public static final int LEAVING = 2;
+ public final int mUid;
+ public final double mLatitude;
+ public final double mLongitude;
+ public final float mRadius;
+ public final long mExpiration;
+ public final PendingIntent mIntent;
+ public final String mPackageName;
+
+ public static final Parcelable.Creator<GeoFenceParams> CREATOR = new Parcelable.Creator<GeoFenceParams>() {
+ public GeoFenceParams createFromParcel(Parcel in) {
+ return new GeoFenceParams(in);
+ }
+
+ @Override
+ public GeoFenceParams[] newArray(int size) {
+ return new GeoFenceParams[size];
+ }
+ };
+
+ public GeoFenceParams(double lat, double lon, float r,
+ long expire, PendingIntent intent, String packageName) {
+ this(Binder.getCallingUid(), lat, lon, r, expire, intent, packageName);
+ }
+
+ public GeoFenceParams(int uid, double lat, double lon, float r,
+ long expire, PendingIntent intent, String packageName) {
+ mUid = uid;
+ mLatitude = lat;
+ mLongitude = lon;
+ mRadius = r;
+ mExpiration = expire;
+ mIntent = intent;
+ mPackageName = packageName;
+ }
+
+ private GeoFenceParams(Parcel in) {
+ mUid = in.readInt();
+ mLatitude = in.readDouble();
+ mLongitude = in.readDouble();
+ mRadius = in.readFloat();
+ mExpiration = in.readLong();
+ mIntent = in.readParcelable(null);
+ mPackageName = in.readString();
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(mUid);
+ dest.writeDouble(mLatitude);
+ dest.writeDouble(mLongitude);
+ dest.writeFloat(mRadius);
+ dest.writeLong(mExpiration);
+ dest.writeParcelable(mIntent, 0);
+ dest.writeString(mPackageName);
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("GeoFenceParams:\n\tmUid - ");
+ sb.append(mUid);
+ sb.append("\n\tmLatitide - ");
+ sb.append(mLatitude);
+ sb.append("\n\tmLongitude - ");
+ sb.append(mLongitude);
+ sb.append("\n\tmRadius - ");
+ sb.append(mRadius);
+ sb.append("\n\tmExpiration - ");
+ sb.append(mExpiration);
+ sb.append("\n\tmIntent - ");
+ sb.append(mIntent);
+ return sb.toString();
+ }
+
+ public long getExpiration() {
+ return mExpiration;
+ }
+
+ public PendingIntent getIntent() {
+ return mIntent;
+ }
+
+ public int getCallerUid() {
+ return mUid;
+ }
+
+ public void dump(PrintWriter pw, String prefix) {
+ pw.println(prefix + this);
+ pw.println(prefix + "mLatitude=" + mLatitude + " mLongitude=" + mLongitude);
+ pw.println(prefix + "mRadius=" + mRadius + " mExpiration=" + mExpiration);
+ }
+}
diff --git a/core/java/android/bluetooth/IBluetoothProfileServiceConnection.aidl b/location/java/android/location/IGeoFenceListener.aidl
index 96c59e2..ccec143 100755..100644
--- a/core/java/android/bluetooth/IBluetoothProfileServiceConnection.aidl
+++ b/location/java/android/location/IGeoFenceListener.aidl
@@ -1,5 +1,9 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+ *
+ * Not a Contribution, Apache license notifications and license are retained
+ * for attribution purposes only.
+ *
+ * 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.
@@ -14,17 +18,13 @@
* limitations under the License.
*/
-package android.bluetooth;
+package android.location;
-import android.content.ComponentName;
-import android.os.IBinder;
+import android.app.PendingIntent;
/**
- * Callback for bluetooth profile connections.
- *
* {@hide}
*/
-interface IBluetoothProfileServiceConnection {
- void onServiceConnected(in ComponentName comp, in IBinder service);
- void onServiceDisconnected(in ComponentName comp);
+oneway interface IGeoFenceListener {
+ void geoFenceExpired(in PendingIntent intent);
}
diff --git a/location/java/android/location/IGeoFencer.aidl b/location/java/android/location/IGeoFencer.aidl
new file mode 100644
index 0000000..d576c6e
--- /dev/null
+++ b/location/java/android/location/IGeoFencer.aidl
@@ -0,0 +1,33 @@
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+ *
+ * Not a Contribution, Apache license notifications and license are retained
+ * for attribution purposes only.
+ *
+ * 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.location;
+
+import android.location.GeoFenceParams;
+import android.app.PendingIntent;
+
+/**
+ * {@hide}
+ */
+interface IGeoFencer {
+ boolean setGeoFence(in IBinder who, in GeoFenceParams params);
+ void clearGeoFence(in IBinder who, in PendingIntent fence);
+ void clearGeoFenceUser(int uid);
+}
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index 2c19324..4544814 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -456,6 +456,7 @@ public class LocationManager {
@RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
public void requestLocationUpdates(String provider, long minTime, float minDistance,
LocationListener listener) {
+ android.util.SeempLog.record(47);
checkProvider(provider);
checkListener(listener);
@@ -488,6 +489,7 @@ public class LocationManager {
@RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
public void requestLocationUpdates(String provider, long minTime, float minDistance,
LocationListener listener, Looper looper) {
+ android.util.SeempLog.record(47);
checkProvider(provider);
checkListener(listener);
@@ -521,6 +523,7 @@ public class LocationManager {
@RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
public void requestLocationUpdates(long minTime, float minDistance, Criteria criteria,
LocationListener listener, Looper looper) {
+ android.util.SeempLog.record(47);
checkCriteria(criteria);
checkListener(listener);
@@ -549,6 +552,7 @@ public class LocationManager {
@RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
public void requestLocationUpdates(String provider, long minTime, float minDistance,
PendingIntent intent) {
+ android.util.SeempLog.record(47);
checkProvider(provider);
checkPendingIntent(intent);
@@ -651,6 +655,7 @@ public class LocationManager {
@RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
public void requestLocationUpdates(long minTime, float minDistance, Criteria criteria,
PendingIntent intent) {
+ android.util.SeempLog.record(47);
checkCriteria(criteria);
checkPendingIntent(intent);
@@ -680,6 +685,7 @@ public class LocationManager {
*/
@RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
public void requestSingleUpdate(String provider, LocationListener listener, Looper looper) {
+ android.util.SeempLog.record(64);
checkProvider(provider);
checkListener(listener);
@@ -710,6 +716,7 @@ public class LocationManager {
*/
@RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
public void requestSingleUpdate(Criteria criteria, LocationListener listener, Looper looper) {
+ android.util.SeempLog.record(64);
checkCriteria(criteria);
checkListener(listener);
@@ -733,6 +740,7 @@ public class LocationManager {
*/
@RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
public void requestSingleUpdate(String provider, PendingIntent intent) {
+ android.util.SeempLog.record(64);
checkProvider(provider);
checkPendingIntent(intent);
@@ -757,6 +765,7 @@ public class LocationManager {
*/
@RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
public void requestSingleUpdate(Criteria criteria, PendingIntent intent) {
+ android.util.SeempLog.record(64);
checkCriteria(criteria);
checkPendingIntent(intent);
@@ -825,6 +834,7 @@ public class LocationManager {
@SystemApi
public void requestLocationUpdates(LocationRequest request, LocationListener listener,
Looper looper) {
+ android.util.SeempLog.record(47);
checkListener(listener);
requestLocationUpdates(request, listener, looper, null);
}
@@ -852,6 +862,7 @@ public class LocationManager {
*/
@SystemApi
public void requestLocationUpdates(LocationRequest request, PendingIntent intent) {
+ android.util.SeempLog.record(47);
checkPendingIntent(intent);
requestLocationUpdates(request, null, null, intent);
}
@@ -870,6 +881,7 @@ public class LocationManager {
private void requestLocationUpdates(LocationRequest request, LocationListener listener,
Looper looper, PendingIntent intent) {
+ android.util.SeempLog.record(47);
String packageName = mContext.getPackageName();
@@ -978,6 +990,7 @@ public class LocationManager {
@RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
public void addProximityAlert(double latitude, double longitude, float radius, long expiration,
PendingIntent intent) {
+ android.util.SeempLog.record(45);
checkPendingIntent(intent);
if (expiration < 0) expiration = Long.MAX_VALUE;
@@ -1191,6 +1204,7 @@ public class LocationManager {
*/
@RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
public Location getLastKnownLocation(String provider) {
+ android.util.SeempLog.record(46);
checkProvider(provider);
String packageName = mContext.getPackageName();
LocationRequest request = LocationRequest.createFromDeprecatedProvider(
@@ -1511,6 +1525,7 @@ public class LocationManager {
*/
@RequiresPermission(ACCESS_FINE_LOCATION)
public boolean addGpsStatusListener(GpsStatus.Listener listener) {
+ android.util.SeempLog.record(43);
boolean result;
if (mGpsStatusListeners.get(listener) != null) {
@@ -1558,6 +1573,7 @@ public class LocationManager {
*/
@RequiresPermission(ACCESS_FINE_LOCATION)
public boolean addNmeaListener(GpsStatus.NmeaListener listener) {
+ android.util.SeempLog.record(44);
boolean result;
if (mNmeaListeners.get(listener) != null) {
@@ -1676,6 +1692,7 @@ public class LocationManager {
* @return true if the command succeeds.
*/
public boolean sendExtraCommand(String provider, String command, Bundle extras) {
+ android.util.SeempLog.record(48);
try {
return mService.sendExtraCommand(provider, command, extras);
} catch (RemoteException e) {
diff --git a/media/java/android/media/AudioFormat.java b/media/java/android/media/AudioFormat.java
index bde3d19..962316b 100644
--- a/media/java/android/media/AudioFormat.java
+++ b/media/java/android/media/AudioFormat.java
@@ -252,6 +252,30 @@ public class AudioFormat {
* */
public static final int ENCODING_AAC_HE_V2 = 12;
+ /** Audio data format: AMRNB
+ * @hide
+ * */
+ public static final int ENCODING_AMRNB = 100;
+ /** Audio data format: AMRWB
+ * @hide
+ * */
+ public static final int ENCODING_AMRWB = 101;
+ /** Audio data format: EVRC
+ * @hide
+ * */
+ public static final int ENCODING_EVRC = 102;
+ /** Audio data format: EVRCB
+ * @hide
+ * */
+ public static final int ENCODING_EVRCB = 103;
+ /** Audio data format: EVRCWB
+ * @hide
+ * */
+ public static final int ENCODING_EVRCWB = 104;
+ /** Audio data format: EVRCNW
+ * @hide
+ * */
+ public static final int ENCODING_EVRCNW = 105;
/** Invalid audio channel configuration */
/** @deprecated Use {@link #CHANNEL_INVALID} instead. */
@Deprecated public static final int CHANNEL_CONFIGURATION_INVALID = 0;
@@ -409,6 +433,11 @@ public class AudioFormat {
public static final int CHANNEL_IN_STEREO = (CHANNEL_IN_LEFT | CHANNEL_IN_RIGHT);
/** @hide */
public static final int CHANNEL_IN_FRONT_BACK = CHANNEL_IN_FRONT | CHANNEL_IN_BACK;
+ /** @hide */
+ public static final int CHANNEL_IN_5POINT1 = (CHANNEL_IN_LEFT |
+ CHANNEL_IN_RIGHT | CHANNEL_IN_FRONT | CHANNEL_IN_BACK |
+ CHANNEL_IN_LEFT_PROCESSED | CHANNEL_IN_RIGHT_PROCESSED);
+
// CHANNEL_IN_ALL is not yet defined; if added then it should match AUDIO_CHANNEL_IN_ALL
/** @hide */
@@ -422,6 +451,15 @@ public class AudioFormat {
return 2;
case ENCODING_PCM_FLOAT:
return 4;
+ case ENCODING_AMRNB:
+ return 32;
+ case ENCODING_AMRWB:
+ return 61;
+ case ENCODING_EVRC:
+ case ENCODING_EVRCB:
+ case ENCODING_EVRCWB:
+ case ENCODING_EVRCNW:
+ return 23;
case ENCODING_INVALID:
default:
throw new IllegalArgumentException("Bad audio format " + audioFormat);
@@ -443,6 +481,12 @@ public class AudioFormat {
case ENCODING_AAC_LC:
case ENCODING_AAC_HE_V1:
case ENCODING_AAC_HE_V2:
+ case ENCODING_AMRNB:
+ case ENCODING_AMRWB:
+ case ENCODING_EVRC:
+ case ENCODING_EVRCB:
+ case ENCODING_EVRCWB:
+ case ENCODING_EVRCNW:
return true;
default:
return false;
@@ -483,6 +527,12 @@ public class AudioFormat {
case ENCODING_AAC_LC:
case ENCODING_AAC_HE_V1:
case ENCODING_AAC_HE_V2:
+ case ENCODING_AMRNB:
+ case ENCODING_AMRWB:
+ case ENCODING_EVRC:
+ case ENCODING_EVRCB:
+ case ENCODING_EVRCWB:
+ case ENCODING_EVRCNW:
return false;
case ENCODING_INVALID:
default:
@@ -715,6 +765,12 @@ public class AudioFormat {
case ENCODING_E_AC3:
case ENCODING_DTS:
case ENCODING_DTS_HD:
+ case ENCODING_AMRNB:
+ case ENCODING_AMRWB:
+ case ENCODING_EVRC:
+ case ENCODING_EVRCB:
+ case ENCODING_EVRCWB:
+ case ENCODING_EVRCNW:
mEncoding = encoding;
break;
case ENCODING_INVALID:
@@ -859,7 +915,13 @@ public class AudioFormat {
ENCODING_AC3,
ENCODING_E_AC3,
ENCODING_DTS,
- ENCODING_DTS_HD
+ ENCODING_DTS_HD,
+ ENCODING_AMRNB,
+ ENCODING_AMRWB,
+ ENCODING_EVRC,
+ ENCODING_EVRCB,
+ ENCODING_EVRCWB,
+ ENCODING_EVRCNW
})
@Retention(RetentionPolicy.SOURCE)
public @interface Encoding {}
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 875e716..fc917f6 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -67,7 +67,6 @@ public class AudioManager {
private final boolean mUseFixedVolume;
private static String TAG = "AudioManager";
private static final AudioPortEventHandler sAudioPortEventHandler = new AudioPortEventHandler();
-
/**
* Broadcast intent, a hint for applications that audio is about to become
* 'noisy' due to a change in audio outputs. For example, this intent may
@@ -310,6 +309,32 @@ public class AudioManager {
*/
public static final String EXTRA_ENCODINGS = "android.media.extra.ENCODINGS";
+ /**
+ * @hide Broadcast intent when RemoteControlClient list is updated.
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String RCC_CHANGED_ACTION =
+ "org.codeaurora.bluetooth.RCC_CHANGED_ACTION";
+
+ /**
+ * @hide Used for sharing the calling package name
+ */
+ public static final String EXTRA_CALLING_PACKAGE_NAME =
+ "org.codeaurora.bluetooth.EXTRA_CALLING_PACKAGE_NAME";
+
+ /**
+ * @hide Used for sharing the focus changed value
+ */
+ public static final String EXTRA_FOCUS_CHANGED_VALUE =
+ "org.codeaurora.bluetooth.EXTRA_FOCUS_CHANGED_VALUE";
+
+ /**
+ * @hide Used for sharing the availability changed value
+ */
+ public static final String EXTRA_AVAILABLITY_CHANGED_VALUE =
+ "org.codeaurora.bluetooth.EXTRA_AVAILABLITY_CHANGED_VALUE";
+
+
/** The audio stream for phone calls */
public static final int STREAM_VOICE_CALL = AudioSystem.STREAM_VOICE_CALL;
/** The audio stream for system sounds */
@@ -2481,6 +2506,7 @@ public class AudioManager {
//====================================================================
// Remote Control
+
/**
* Register a component to be the sole receiver of MEDIA_BUTTON intents.
* @param eventReceiver identifier of a {@link android.content.BroadcastReceiver}
@@ -2499,6 +2525,7 @@ public class AudioManager {
"receiver and context package names don't match");
return;
}
+
// construct a PendingIntent for the media button and register it
Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
// the associated intent will be handled by the component being registered
@@ -2508,6 +2535,7 @@ public class AudioManager {
registerMediaButtonIntent(pi, eventReceiver);
}
+
/**
* Register a component to be the sole receiver of MEDIA_BUTTON intents. This is like
* {@link #registerMediaButtonEventReceiver(android.content.ComponentName)}, but allows
@@ -2637,6 +2665,13 @@ public class AudioManager {
return false;
}
rctlr.startListeningToSessions();
+ IAudioService service = getService();
+ try {
+ service.updateRemoteControllerOnExistingMediaPlayers();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error in calling Audio service interface" +
+ "updateRemoteControllerOnExistingMediaPlayers() due to " + e);
+ }
return true;
}
@@ -2660,6 +2695,24 @@ public class AudioManager {
/**
* @hide
+ */
+ public void updateMediaPlayerList(String packageName, boolean toAdd) {
+ IAudioService service = getService();
+ try {
+ if (toAdd) {
+ Log.d(TAG, "updateMediaPlayerList: Add RCC " + packageName + " to List");
+ service.addMediaPlayerAndUpdateRemoteController(packageName);
+ } else {
+ Log.d(TAG, "updateMediaPlayerList: Remove RCC " + packageName + " from List");
+ service.removeMediaPlayerAndUpdateRemoteController(packageName);
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "Exception while executing updateMediaPlayerList: " + e);
+ }
+ }
+
+ /**
+ * @hide
* Registers a remote control display that will be sent information by remote control clients.
* Use this method if your IRemoteControlDisplay is not going to display artwork, otherwise
* use {@link #registerRemoteControlDisplay(IRemoteControlDisplay, int, int)} to pass the
@@ -2811,6 +2864,52 @@ public class AudioManager {
}
}
+ /**
+ * @hide
+ * Request the user of a RemoteControlClient to play the requested item.
+ * @param generationId the RemoteControlClient generation counter for which this request is
+ * issued.
+ * @param uid uid of the song to be played.
+ * @scope scope of the file system to use
+ */
+ public void setRemoteControlClientPlayItem(long uid, int scope) {
+ IAudioService service = getService();
+ try {
+ service.setRemoteControlClientPlayItem(uid, scope);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Dead object in setRemoteControlClientPlayItem(" +
+ uid + ", " + scope + ")", e);
+ }
+ }
+
+ /**
+ * @hide
+ * Request the user of a RemoteControlClient to provide with the now playing list entries.
+ * @param generationId the RemoteControlClient generation counter for which this request is
+ * issued.
+ */
+ public void getRemoteControlClientNowPlayingEntries() {
+ IAudioService service = getService();
+ try {
+ service.getRemoteControlClientNowPlayingEntries();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Dead object in getRemoteControlClientNowPlayingEntries(" + ")", e);
+ }
+ }
+
+ /**
+ * @hide
+ * Request the user of a RemoteControlClient to set the music player as current browsed player.
+ */
+ public void setRemoteControlClientBrowsedPlayer() {
+ Log.d(TAG, "setRemoteControlClientBrowsedPlayer: ");
+ IAudioService service = getService();
+ try {
+ service.setRemoteControlClientBrowsedPlayer();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Dead object in setRemoteControlClientBrowsedPlayer(" + ")", e);
+ }
+ }
/**
* @hide
diff --git a/media/java/android/media/AudioRecord.java b/media/java/android/media/AudioRecord.java
index 974b62e..e819b8a 100644
--- a/media/java/android/media/AudioRecord.java
+++ b/media/java/android/media/AudioRecord.java
@@ -643,6 +643,12 @@ public class AudioRecord
case AudioFormat.ENCODING_PCM_FLOAT:
case AudioFormat.ENCODING_PCM_16BIT:
case AudioFormat.ENCODING_PCM_8BIT:
+ case AudioFormat.ENCODING_AMRNB:
+ case AudioFormat.ENCODING_AMRWB:
+ case AudioFormat.ENCODING_EVRC:
+ case AudioFormat.ENCODING_EVRCB:
+ case AudioFormat.ENCODING_EVRCWB:
+ case AudioFormat.ENCODING_EVRCNW:
mAudioFormat = audioFormat;
break;
default:
@@ -845,6 +851,9 @@ public class AudioRecord
case (AudioFormat.CHANNEL_IN_FRONT | AudioFormat.CHANNEL_IN_BACK):
channelCount = 2;
break;
+ case AudioFormat.CHANNEL_IN_5POINT1:
+ channelCount = 6;
+ break;
case AudioFormat.CHANNEL_INVALID:
default:
loge("getMinBufferSize(): Invalid channel configuration.");
@@ -881,6 +890,7 @@ public class AudioRecord
*/
public void startRecording()
throws IllegalStateException {
+ android.util.SeempLog.record(70);
if (mState != STATE_INITIALIZED) {
throw new IllegalStateException("startRecording() called on an "
+ "uninitialized AudioRecord.");
@@ -893,6 +903,11 @@ public class AudioRecord
mRecordingState = RECORDSTATE_RECORDING;
}
}
+
+ if (getRecordingState() == RECORDSTATE_RECORDING &&
+ getAudioSource() == MediaRecorder.AudioSource.HOTWORD) {
+ handleHotwordInput(true);
+ }
}
/**
@@ -904,6 +919,7 @@ public class AudioRecord
*/
public void startRecording(MediaSyncEvent syncEvent)
throws IllegalStateException {
+ android.util.SeempLog.record(70);
if (mState != STATE_INITIALIZED) {
throw new IllegalStateException("startRecording() called on an "
+ "uninitialized AudioRecord.");
@@ -934,6 +950,10 @@ public class AudioRecord
native_stop();
mRecordingState = RECORDSTATE_STOPPED;
}
+
+ if (getAudioSource() == MediaRecorder.AudioSource.HOTWORD) {
+ handleHotwordInput(false);
+ }
}
private final IBinder mICallBack = new Binder();
@@ -950,6 +970,16 @@ public class AudioRecord
}
}
+ private void handleHotwordInput(boolean listening) {
+ final IBinder b = ServiceManager.getService(android.content.Context.AUDIO_SERVICE);
+ final IAudioService ias = IAudioService.Stub.asInterface(b);
+ try {
+ ias.handleHotwordInput(listening);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error talking to AudioService when handling hotword input.", e);
+ }
+ }
+
//---------------------------------------------------------
// Audio data supply
//--------------------
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index c59d1c7..927cd87 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -319,7 +319,7 @@ public class AudioSystem
public static final int DEVICE_OUT_AUX_LINE = 0x200000;
public static final int DEVICE_OUT_SPEAKER_SAFE = 0x400000;
public static final int DEVICE_OUT_IP = 0x800000;
-
+ public static final int DEVICE_OUT_PROXY = 0x1000000;
public static final int DEVICE_OUT_DEFAULT = DEVICE_BIT_DEFAULT;
public static final int DEVICE_OUT_ALL = (DEVICE_OUT_EARPIECE |
@@ -346,6 +346,7 @@ public class AudioSystem
DEVICE_OUT_AUX_LINE |
DEVICE_OUT_SPEAKER_SAFE |
DEVICE_OUT_IP |
+ DEVICE_OUT_PROXY |
DEVICE_OUT_DEFAULT);
public static final int DEVICE_OUT_ALL_A2DP = (DEVICE_OUT_BLUETOOTH_A2DP |
DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES |
@@ -385,6 +386,7 @@ public class AudioSystem
public static final int DEVICE_IN_BLUETOOTH_A2DP = DEVICE_BIT_IN | 0x20000;
public static final int DEVICE_IN_LOOPBACK = DEVICE_BIT_IN | 0x40000;
public static final int DEVICE_IN_IP = DEVICE_BIT_IN | 0x80000;
+ public static final int DEVICE_IN_PROXY = DEVICE_BIT_IN | 0x1000000;
public static final int DEVICE_IN_DEFAULT = DEVICE_BIT_IN | DEVICE_BIT_DEFAULT;
public static final int DEVICE_IN_ALL = (DEVICE_IN_COMMUNICATION |
@@ -407,6 +409,7 @@ public class AudioSystem
DEVICE_IN_BLUETOOTH_A2DP |
DEVICE_IN_LOOPBACK |
DEVICE_IN_IP |
+ DEVICE_IN_PROXY |
DEVICE_IN_DEFAULT);
public static final int DEVICE_IN_ALL_SCO = DEVICE_IN_BLUETOOTH_SCO_HEADSET;
public static final int DEVICE_IN_ALL_USB = (DEVICE_IN_USB_ACCESSORY |
@@ -442,6 +445,7 @@ public class AudioSystem
public static final String DEVICE_OUT_AUX_LINE_NAME = "aux_line";
public static final String DEVICE_OUT_SPEAKER_SAFE_NAME = "speaker_safe";
public static final String DEVICE_OUT_IP_NAME = "ip";
+ public static final String DEVICE_OUT_PROXY_NAME = "proxy";
public static final String DEVICE_IN_COMMUNICATION_NAME = "communication";
public static final String DEVICE_IN_AMBIENT_NAME = "ambient";
@@ -515,6 +519,8 @@ public class AudioSystem
return DEVICE_OUT_SPEAKER_SAFE_NAME;
case DEVICE_OUT_IP:
return DEVICE_OUT_IP_NAME;
+ case DEVICE_OUT_PROXY:
+ return DEVICE_OUT_PROXY_NAME;
case DEVICE_OUT_DEFAULT:
default:
return Integer.toString(device);
diff --git a/media/java/android/media/CamcorderProfile.java b/media/java/android/media/CamcorderProfile.java
index d303a2e..6785670 100644
--- a/media/java/android/media/CamcorderProfile.java
+++ b/media/java/android/media/CamcorderProfile.java
@@ -206,6 +206,77 @@ public class CamcorderProfile
private static final int QUALITY_HIGH_SPEED_LIST_START = QUALITY_HIGH_SPEED_LOW;
private static final int QUALITY_HIGH_SPEED_LIST_END = QUALITY_HIGH_SPEED_2160P;
+ // Vendor-specific quality profiles
+ /**
+ * Quality level corresponding to the VGA (640 x 480) resolution.
+ * @hide
+ */
+ public static final int QUALITY_VGA = 10000;
+
+ /**
+ * Quality level corresponding to the 4k-DCI (4096 x 2160) resolution.
+ * @hide
+ */
+ public static final int QUALITY_4KDCI = 10001;
+
+ /**
+ * Time lapse quality level corresponding to the VGA (640 x 480) resolution.
+ * @hide
+ */
+ public static final int QUALITY_TIME_LAPSE_VGA = 10002;
+
+ /**
+ * Time lapse quality level corresponding to the 4k-DCI (4096 x 2160) resolution.
+ * @hide
+ */
+ public static final int QUALITY_TIME_LAPSE_4KDCI = 10003;
+
+ /**
+ * High speed ( >= 100fps) quality level corresponding to the CIF (352 x 288)
+ * @hide
+ */
+ public static final int QUALITY_HIGH_SPEED_CIF = 10004;
+
+ /**
+ * High speed ( >= 100fps) quality level corresponding to the VGA (640 x 480)
+ * @hide
+ */
+ public static final int QUALITY_HIGH_SPEED_VGA = 10005;
+
+ /**
+ * High speed ( >= 100fps) quality level corresponding to the 4K-DCI (4096 x 2160)
+ * @hide
+ */
+ public static final int QUALITY_HIGH_SPEED_4KDCI = 10006;
+
+ /**
+ * Quality level corresponding to QHD resolution
+ * @hide
+ */
+ public static final int QUALITY_QHD = 10007;
+
+ /**
+ * Quality level corresponding to 2K resolution
+ * @hide
+ */
+ public static final int QUALITY_2k = 10008;
+
+ /**
+ * Time lapse quality level corresponding to the QHD resolution.
+ * @hide
+ */
+ public static final int QUALITY_TIME_LAPSE_QHD = 10009;
+
+ /**
+ * Time lapse quality level corresponding to the 2K resolution.
+ * @hide
+ */
+ public static final int QUALITY_TIME_LAPSE_2k = 10010;
+
+ // Start and end of vendor quality list
+ private static final int QUALITY_VENDOR_LIST_START = QUALITY_VGA;
+ private static final int QUALITY_VENDOR_LIST_END = QUALITY_TIME_LAPSE_2k;
+
/**
* Default recording duration in seconds before the session is terminated.
* This is useful for applications like MMS has limited file size requirement.
@@ -391,7 +462,9 @@ public class CamcorderProfile
(quality >= QUALITY_TIME_LAPSE_LIST_START &&
quality <= QUALITY_TIME_LAPSE_LIST_END) ||
(quality >= QUALITY_HIGH_SPEED_LIST_START &&
- quality <= QUALITY_HIGH_SPEED_LIST_END))) {
+ quality <= QUALITY_HIGH_SPEED_LIST_END) ||
+ (quality >= QUALITY_VENDOR_LIST_START &&
+ quality <= QUALITY_VENDOR_LIST_END))) {
String errMessage = "Unsupported quality level: " + quality;
throw new IllegalArgumentException(errMessage);
}
diff --git a/media/java/android/media/ClosedCaptionRenderer.java b/media/java/android/media/ClosedCaptionRenderer.java
index 8403c1c..2cf754e 100644
--- a/media/java/android/media/ClosedCaptionRenderer.java
+++ b/media/java/android/media/ClosedCaptionRenderer.java
@@ -609,8 +609,10 @@ class CCParser {
if (mLines[mRow] != null) {
for (int i = 0; i < mCol; i++) {
if (mLines[mRow].charAt(i) != TS) {
- for (int j = mCol; j < mLines[mRow].length(); j++) {
- mLines[j].setCharAt(j, TS);
+ for (int j = mCol; j < mLines[mRow].length() && j < mLines.length; j++) {
+ if (mLines[j] != null){
+ mLines[j].setCharAt(j, TS);
+ }
}
return;
}
diff --git a/media/java/android/media/EncoderCapabilities.java b/media/java/android/media/EncoderCapabilities.java
index 332e360..d612c20 100644
--- a/media/java/android/media/EncoderCapabilities.java
+++ b/media/java/android/media/EncoderCapabilities.java
@@ -47,13 +47,17 @@ public class EncoderCapabilities
public final int mMinFrameRate, mMaxFrameRate; // min and max frame rate (fps)
public final int mMinFrameWidth, mMaxFrameWidth; // min and max frame width (pixel)
public final int mMinFrameHeight, mMaxFrameHeight; // minn and max frame height (pixel)
+ public final int mMaxHFRFrameWidth, mMaxHFRFrameHeight; // max HFR size (pixel)
+ public final int mMaxHFRMode; // max HFR mode
// Private constructor called by JNI
private VideoEncoderCap(int codec,
int minBitRate, int maxBitRate,
int minFrameRate, int maxFrameRate,
int minFrameWidth, int maxFrameWidth,
- int minFrameHeight, int maxFrameHeight) {
+ int minFrameHeight, int maxFrameHeight,
+ int maxHFRFrameWidth, int maxHFRFrameHeight,
+ int maxHFRMode) {
mCodec = codec;
mMinBitRate = minBitRate;
mMaxBitRate = maxBitRate;
@@ -63,6 +67,9 @@ public class EncoderCapabilities
mMaxFrameWidth = maxFrameWidth;
mMinFrameHeight = minFrameHeight;
mMaxFrameHeight = maxFrameHeight;
+ mMaxHFRFrameWidth = maxHFRFrameWidth;
+ mMaxHFRFrameHeight = maxHFRFrameHeight;
+ mMaxHFRMode = maxHFRMode;
}
};
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index 8aebe11..cdcd83c 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -215,4 +215,21 @@ interface IAudioService {
int setFocusPropertiesForPolicy(int duckingBehavior, in IAudioPolicyCallback pcb);
void setVolumePolicy(in VolumePolicy policy);
+
+ void setRemoteControlClientBrowsedPlayer();
+
+ void getRemoteControlClientNowPlayingEntries();
+
+ void setRemoteControlClientPlayItem(long uid, int scope);
+
+ void updateRemoteControllerOnExistingMediaPlayers();
+
+ void addMediaPlayerAndUpdateRemoteController(String packageName);
+
+ void removeMediaPlayerAndUpdateRemoteController(String packageName);
+
+ void handleHotwordInput(boolean listening);
+
+ String getCurrentHotwordInputPackageName();
+
}
diff --git a/media/java/android/media/IRemoteControlClient.aidl b/media/java/android/media/IRemoteControlClient.aidl
index aa142d6..d8e73c8 100644
--- a/media/java/android/media/IRemoteControlClient.aidl
+++ b/media/java/android/media/IRemoteControlClient.aidl
@@ -52,11 +52,14 @@ oneway interface IRemoteControlClient
*/
void setCurrentClientGenerationId(int clientGeneration);
- void plugRemoteControlDisplay(IRemoteControlDisplay rcd, int w, int h);
+ void plugRemoteControlDisplay(IRemoteControlDisplay rcd, int w, int h);
void unplugRemoteControlDisplay(IRemoteControlDisplay rcd);
void setBitmapSizeForDisplay(IRemoteControlDisplay rcd, int w, int h);
void setWantsSyncForDisplay(IRemoteControlDisplay rcd, boolean wantsSync);
void enableRemoteControlDisplay(IRemoteControlDisplay rcd, boolean enabled);
void seekTo(int clientGeneration, long timeMs);
void updateMetadata(int clientGeneration, int key, in Rating value);
+ void setPlayItem(int scope, long uid);
+ void setBrowsedPlayer();
+ void getNowPlayingEntries();
} \ No newline at end of file
diff --git a/media/java/android/media/MediaCodecInfo.java b/media/java/android/media/MediaCodecInfo.java
index 4101935..957ba16 100644
--- a/media/java/android/media/MediaCodecInfo.java
+++ b/media/java/android/media/MediaCodecInfo.java
@@ -589,6 +589,13 @@ public final class MediaCodecInfo {
return mDefaultFormat;
}
+ /* Return the capabilities info, so the app can query custom settings
+ * like for VT. */
+ /** @hide */
+ public MediaFormat getCapabilitiesInfoFormat() {
+ return mCapabilitiesInfo;
+ }
+
/**
* Returns the mime type for which this codec-capability object was created.
*/
diff --git a/media/java/android/media/MediaFile.java b/media/java/android/media/MediaFile.java
index 526656a..e91548c 100644
--- a/media/java/android/media/MediaFile.java
+++ b/media/java/android/media/MediaFile.java
@@ -46,6 +46,18 @@ public class MediaFile {
private static final int FIRST_AUDIO_FILE_TYPE = FILE_TYPE_MP3;
private static final int LAST_AUDIO_FILE_TYPE = FILE_TYPE_FLAC;
+ // More audio file types
+ public static final int FILE_TYPE_DTS = 300;
+ public static final int FILE_TYPE_3GPA = 301;
+ public static final int FILE_TYPE_AC3 = 302;
+ public static final int FILE_TYPE_QCP = 303;
+ public static final int FILE_TYPE_PCM = 304;
+ public static final int FILE_TYPE_EC3 = 305;
+ public static final int FILE_TYPE_AIFF = 306;
+ public static final int FILE_TYPE_APE = 307;
+ private static final int FIRST_AUDIO_FILE_TYPE_EXT = FILE_TYPE_DTS;
+ private static final int LAST_AUDIO_FILE_TYPE_EXT = FILE_TYPE_APE;
+
// MIDI file types
public static final int FILE_TYPE_MID = 11;
public static final int FILE_TYPE_SMF = 12;
@@ -69,8 +81,10 @@ public class MediaFile {
// More video file types
public static final int FILE_TYPE_MP2PS = 200;
+ public static final int FILE_TYPE_DIVX = 201;
+ public static final int FILE_TYPE_FLV = 202;
private static final int FIRST_VIDEO_FILE_TYPE2 = FILE_TYPE_MP2PS;
- private static final int LAST_VIDEO_FILE_TYPE2 = FILE_TYPE_MP2PS;
+ private static final int LAST_VIDEO_FILE_TYPE2 = FILE_TYPE_FLV;
// Image file types
public static final int FILE_TYPE_JPEG = 31;
@@ -87,9 +101,10 @@ public class MediaFile {
public static final int FILE_TYPE_PLS = 42;
public static final int FILE_TYPE_WPL = 43;
public static final int FILE_TYPE_HTTPLIVE = 44;
+ public static final int FILE_TYPE_DASH = 45;
private static final int FIRST_PLAYLIST_FILE_TYPE = FILE_TYPE_M3U;
- private static final int LAST_PLAYLIST_FILE_TYPE = FILE_TYPE_HTTPLIVE;
+ private static final int LAST_PLAYLIST_FILE_TYPE = FILE_TYPE_DASH;
// Drm file types
public static final int FILE_TYPE_FL = 51;
@@ -240,13 +255,24 @@ public class MediaFile {
addFileType("ZIP", FILE_TYPE_ZIP, "application/zip");
addFileType("MPG", FILE_TYPE_MP2PS, "video/mp2p");
addFileType("MPEG", FILE_TYPE_MP2PS, "video/mp2p");
+ addFileType("DIVX", FILE_TYPE_DIVX, "video/divx");
+ addFileType("FLV", FILE_TYPE_FLV, "video/flv");
+ addFileType("MPD", FILE_TYPE_DASH, "application/dash+xml");
+ addFileType("QCP", FILE_TYPE_QCP, "audio/qcelp");
+ addFileType("AC3", FILE_TYPE_AC3, "audio/ac3");
+ addFileType("EC3", FILE_TYPE_EC3, "audio/eac3");
+ addFileType("AIF", FILE_TYPE_AIFF, "audio/x-aiff");
+ addFileType("AIFF", FILE_TYPE_AIFF, "audio/x-aiff");
+ addFileType("APE", FILE_TYPE_APE, "audio/x-ape");
}
public static boolean isAudioFileType(int fileType) {
return ((fileType >= FIRST_AUDIO_FILE_TYPE &&
fileType <= LAST_AUDIO_FILE_TYPE) ||
(fileType >= FIRST_MIDI_FILE_TYPE &&
- fileType <= LAST_MIDI_FILE_TYPE));
+ fileType <= LAST_MIDI_FILE_TYPE) ||
+ (fileType >= FIRST_AUDIO_FILE_TYPE_EXT &&
+ fileType <= LAST_AUDIO_FILE_TYPE_EXT));
}
public static boolean isVideoFileType(int fileType) {
diff --git a/media/java/android/media/MediaHTTPConnection.java b/media/java/android/media/MediaHTTPConnection.java
index d6bf421..59eaeef 100644
--- a/media/java/android/media/MediaHTTPConnection.java
+++ b/media/java/android/media/MediaHTTPConnection.java
@@ -19,6 +19,7 @@ package android.media;
import android.net.NetworkUtils;
import android.os.IBinder;
import android.os.StrictMode;
+import android.os.SystemProperties;
import android.util.Log;
import java.io.BufferedInputStream;
@@ -34,8 +35,14 @@ import java.net.NoRouteToHostException;
import java.net.ProtocolException;
import java.net.UnknownServiceException;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
+import java.net.InetSocketAddress;
+import java.net.Proxy;
+import java.net.Socket;
+import java.net.SocketAddress;
+
import static android.media.MediaPlayer.MEDIA_ERROR_UNSUPPORTED;
/** @hide */
@@ -48,10 +55,14 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub {
private long mCurrentOffset = -1;
private URL mURL = null;
+ private int mProxyPort = 0;
+ private String mProxyIP;
private Map<String, String> mHeaders = null;
private HttpURLConnection mConnection = null;
private long mTotalSize = -1;
private InputStream mInputStream = null;
+ private List<String> mCookies = null;
+ private boolean mIsCookieUpdated = false;
private boolean mAllowCrossDomainRedirect = true;
private boolean mAllowCrossProtocolRedirect = true;
@@ -97,10 +108,21 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub {
/* returns true iff header is internal */
private boolean filterOutInternalHeaders(String key, String val) {
+ Log.d(TAG, "filterOutInternalHeaders: key=" + key + ", val=" + val);
if ("android-allow-cross-domain-redirect".equalsIgnoreCase(key)) {
mAllowCrossDomainRedirect = parseBoolean(val);
// cross-protocol redirects are also controlled by this flag
mAllowCrossProtocolRedirect = mAllowCrossDomainRedirect;
+ } else if ("use-proxy".equalsIgnoreCase(key)) {
+ Log.d(TAG, "filterOutInternalHeaders use-proxy " + val);
+ int colonPos = val.indexOf(":");
+ if (colonPos > 0) {
+ mProxyIP = new String((val.substring(0, colonPos)).trim());
+ mProxyPort = Integer.parseInt(val.substring(colonPos + 1));
+ Log.d(TAG, "sta-proxy-ip " + mProxyIP + " port " + mProxyPort);
+ }
+ } else if ("Cookie".equalsIgnoreCase(key) && mIsCookieUpdated) {
+ Log.d(TAG, "filterOutInternalHeaders: Cookie");
} else {
return false;
}
@@ -180,10 +202,19 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub {
boolean noProxy = isLocalHost(url);
while (true) {
- if (noProxy) {
- mConnection = (HttpURLConnection)url.openConnection(Proxy.NO_PROXY);
+
+ Log.d(TAG, "proxy " + mProxyIP +" port "+ mProxyPort);
+ if (mProxyPort > 0) {
+ SocketAddress socketAddr = new InetSocketAddress(mProxyIP, mProxyPort);
+ java.net.Proxy proxy = new java.net.Proxy(java.net.Proxy.Type.HTTP, socketAddr);
+ mConnection = (HttpURLConnection) url.openConnection(proxy);
+ Log.d(TAG, "connection initialized with proxy");
} else {
- mConnection = (HttpURLConnection)url.openConnection();
+ if (noProxy) {
+ mConnection = (HttpURLConnection)url.openConnection(Proxy.NO_PROXY);
+ } else {
+ mConnection = (HttpURLConnection)url.openConnection();
+ }
}
mConnection.setConnectTimeout(CONNECT_TIMEOUT_MS);
@@ -197,6 +228,14 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub {
}
}
+ if (mIsCookieUpdated) {
+ if (VERBOSE)
+ Log.d(TAG, "add Cookie in the request");
+ for (String cookie : mCookies) {
+ mConnection.addRequestProperty("Cookie", cookie.split(";", 2)[0]);
+ }
+ }
+
if (offset > 0) {
mConnection.setRequestProperty(
"Range", "bytes=" + offset + "-");
@@ -283,6 +322,16 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub {
throw new IOException();
} else {
mTotalSize = mConnection.getContentLength();
+ if (mConnection.getHeaderFields().containsKey("Set-Cookie")) {
+ mIsCookieUpdated = SystemProperties.getBoolean(
+ "persist.media.cookie.cust", false);
+ mCookies = mConnection.getHeaderFields().get("Set-Cookie");
+ if (VERBOSE) {
+ for (String cookie : mCookies) {
+ Log.d(TAG, "get Cookie" + cookie);
+ }
+ }
+ }
}
if (offset > 0 && response != HttpURLConnection.HTTP_PARTIAL) {
diff --git a/media/java/android/media/MediaMetadataEditor.java b/media/java/android/media/MediaMetadataEditor.java
index 566b93f..eeb8fe2 100644
--- a/media/java/android/media/MediaMetadataEditor.java
+++ b/media/java/android/media/MediaMetadataEditor.java
@@ -439,7 +439,7 @@ import android.util.SparseIntArray;
protected static final SparseIntArray METADATA_KEYS_TYPE;
static {
- METADATA_KEYS_TYPE = new SparseIntArray(17);
+ METADATA_KEYS_TYPE = new SparseIntArray(18);
// NOTE: if adding to the list below, make sure you increment the array initialization size
// keys with long values
METADATA_KEYS_TYPE.put(
@@ -465,5 +465,7 @@ import android.util.SparseIntArray;
// keys with Rating values
METADATA_KEYS_TYPE.put(RATING_KEY_BY_OTHERS, METADATA_TYPE_RATING);
METADATA_KEYS_TYPE.put(RATING_KEY_BY_USER, METADATA_TYPE_RATING);
+ // Meta data for total number of tracks in Album
+ METADATA_KEYS_TYPE.put(MediaMetadataRetriever.METADATA_KEY_NUM_TRACKS, METADATA_TYPE_LONG);
}
}
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index 587d494..b3f25ee 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -3453,6 +3453,23 @@ public class MediaPlayer implements SubtitleController.Listener
mode == VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING);
}
+ /** @hide
+ */
+ public boolean suspend() {
+ stayAwake(false);
+ return _suspend();
+ }
+
+ private native boolean _suspend();
+
+ /** @hide
+ */
+ public boolean resume() {
+ return _resume();
+ }
+
+ private native boolean _resume();
+
/** @hide */
static class TimeProvider implements MediaPlayer.OnSeekCompleteListener,
MediaTimeProvider {
diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java
index ed2c4cbd..4e405e3 100644
--- a/media/java/android/media/MediaRecorder.java
+++ b/media/java/android/media/MediaRecorder.java
@@ -345,6 +345,13 @@ public class MediaRecorder
/** VP8/VORBIS data in a WEBM container */
public static final int WEBM = 9;
+
+ /** @hide QCP file format */
+ public static final int QCP = 20;
+
+ /** @hide WAVE media file format*/
+ public static final int WAVE = 21;
+
};
/**
@@ -369,6 +376,12 @@ public class MediaRecorder
public static final int AAC_ELD = 5;
/** Ogg Vorbis audio codec */
public static final int VORBIS = 6;
+ /** @hide EVRC audio codec */
+ public static final int EVRC = 10;
+ /** @hide QCELP audio codec */
+ public static final int QCELP = 11;
+ /** @hide Linear PCM audio codec */
+ public static final int LPCM = 12;
}
/**
@@ -385,6 +398,8 @@ public class MediaRecorder
public static final int H264 = 2;
public static final int MPEG_4_SP = 3;
public static final int VP8 = 4;
+ /** @hide **/
+ public static final int H265 = 1001;
}
/**
@@ -436,8 +451,9 @@ public class MediaRecorder
setVideoSize(profile.videoFrameWidth, profile.videoFrameHeight);
setVideoEncodingBitRate(profile.videoBitRate);
setVideoEncoder(profile.videoCodec);
- if (profile.quality >= CamcorderProfile.QUALITY_TIME_LAPSE_LOW &&
- profile.quality <= CamcorderProfile.QUALITY_TIME_LAPSE_QVGA) {
+ if ((profile.quality >= CamcorderProfile.QUALITY_TIME_LAPSE_LOW &&
+ profile.quality <= CamcorderProfile.QUALITY_TIME_LAPSE_2160P) ||
+ profile.quality == CamcorderProfile.QUALITY_TIME_LAPSE_VGA) {
// Nothing needs to be done. Call to setCaptureRate() enables
// time lapse video recording.
} else {
@@ -792,6 +808,10 @@ public class MediaRecorder
*/
public native void start() throws IllegalStateException;
+ /** @hide
+ */
+ public native void pause() throws IllegalStateException;
+
/**
* Stops recording. Call this after start(). Once recording is stopped,
* you will have to configure it again as if it has just been constructed.
diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java
index 9ea6722..ff46398 100644
--- a/media/java/android/media/MediaScanner.java
+++ b/media/java/android/media/MediaScanner.java
@@ -61,6 +61,8 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Locale;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
/**
* Internal service helper that no-one should use directly.
@@ -351,6 +353,11 @@ public class MediaScanner
private final BitmapFactory.Options mBitmapOptions = new BitmapFactory.Options();
+ // For basic VorbisComment DATE tag support. It can take two forms, YYYY
+ // or YYYY-MM. This pattern is used to extract the year for compatibility
+ // with the ID3 YEAR tag.
+ private static final Pattern DATE_YEAR_DETECT_PATTERN = Pattern.compile("^(\\d{4})(-\\d{2})?$");
+
private static class FileEntry {
long mRowId;
String mPath;
@@ -615,6 +622,13 @@ public class MediaScanner
mGenre = getGenreName(value);
} else if (name.equalsIgnoreCase("year") || name.startsWith("year;")) {
mYear = parseSubstring(value, 0, 0);
+ } else if (mYear == 0 && name.equalsIgnoreCase("date") || name.startsWith("date;")) {
+ // Since Android doesn't support DATE tag itself, just use it to extract
+ // the year, if the YEAR tag isn't present.
+ Matcher m = DATE_YEAR_DETECT_PATTERN.matcher(value);
+ if (m.find()) {
+ mYear = parseSubstring(m.group(1), 0, 0);
+ }
} else if (name.equalsIgnoreCase("tracknumber") || name.startsWith("tracknumber;")) {
// track number might be of the form "2/12"
// we just read the number before the slash
@@ -1364,7 +1378,7 @@ public class MediaScanner
// always scan the file, so we can return the content://media Uri for existing files
return mClient.doScanFile(path, mimeType, lastModifiedSeconds, file.length(),
- false, true, MediaScanner.isNoMediaPath(path));
+ file.isDirectory(), true, MediaScanner.isNoMediaPath(path));
} catch (RemoteException e) {
Log.e(TAG, "RemoteException in MediaScanner.scanFile()", e);
return null;
diff --git a/media/java/android/media/RemoteControlClient.java b/media/java/android/media/RemoteControlClient.java
index c9a86d8..07b8c23 100644
--- a/media/java/android/media/RemoteControlClient.java
+++ b/media/java/android/media/RemoteControlClient.java
@@ -707,6 +707,79 @@ import java.lang.IllegalArgumentException;
}
}
+ /**
+ * @hide
+ */
+ public void playItemResponse(boolean success) {
+ Log.e(TAG, "playItemResponse");
+ playItemResponseInt(success);
+ }
+
+ private void playItemResponseInt(boolean success) {
+ Log.d(TAG, "playItemResponseInt");
+ Log.v(TAG, "success: " + success);
+
+ // USE_SESSIONS
+ if (mSession != null) {
+ mSession.playItemResponse(success);
+ }
+ }
+
+ /**
+ * @hide
+ */
+ public void updateNowPlayingEntries(long[] playList) {
+ Log.e(TAG, "updateNowPlayingEntries: Item numbers: " + playList.length);
+ updateNowPlayingEntriesInt(playList);
+ }
+
+ private void updateNowPlayingEntriesInt(long[] playList) {
+ Log.d(TAG, "updateNowPlayingEntriesInt");
+
+ // USE_SESSIONS
+ if (mSession != null) {
+ mSession.updateNowPlayingEntries(playList);
+ }
+ }
+
+ /**
+ * @hide
+ */
+ public void updateFolderInfoBrowsedPlayer(String stringUri) {
+ Log.e(TAG, "updateFolderInfoBrowsedPlayer");
+ synchronized(mCacheLock) {
+ updateFolderInfoBrowsedPlayerInt(stringUri);
+ }
+ }
+
+ private void updateFolderInfoBrowsedPlayerInt(String stringUri) {
+ Log.d(TAG, "updateFolderInfoBrowsedPlayerInt");
+
+ // USE_SESSIONS
+ if (mSession != null) {
+ mSession.updateFolderInfoBrowsedPlayer(stringUri);
+ }
+ }
+
+ /**
+ * @hide
+ */
+ public void updateNowPlayingContentChange() {
+ Log.e(TAG, "updateNowPlayingContentChange");
+ synchronized(mCacheLock) {
+ updateNowPlayingContentChangeInt();
+ }
+ }
+
+ private void updateNowPlayingContentChangeInt() {
+ Log.d(TAG, "updateNowPlayingContentChangeInt");
+
+ // USE_SESSIONS
+ if (mSession != null) {
+ mSession.updateNowPlayingContentChange();
+ }
+ }
+
// TODO investigate if we still need position drift checking
private void onPositionDriftCheck() {
if (DEBUG) { Log.d(TAG, "onPositionDriftCheck()"); }
@@ -798,6 +871,56 @@ import java.lang.IllegalArgumentException;
}
}
+ /**
+ * @hide
+ */
+ public interface OnGetNowPlayingEntriesListener {
+ public abstract void onGetNowPlayingEntries();
+ }
+
+ /**
+ * @hide
+ */
+ public void setNowPlayingEntriesUpdateListener(OnGetNowPlayingEntriesListener l) {
+ Log.d(TAG, "setNowPlayingEntriesUpdateListener");
+ synchronized(mCacheLock) {
+ mGetNowPlayingEntriesListener = l;
+ }
+ }
+
+ /**
+ * @hide
+ */
+ public interface OnSetBrowsedPlayerListener {
+ public abstract void onSetBrowsedPlayer();
+ }
+
+ /**
+ * @hide
+ */
+ public void setBrowsedPlayerUpdateListener(OnSetBrowsedPlayerListener l) {
+ Log.d(TAG, "setBrowsedPlayerUpdateListener");
+ synchronized(mCacheLock) {
+ mSetBrowsedPlayerListener = l;
+ }
+ }
+
+ /**
+ * @hide
+ */
+ public interface OnSetPlayItemListener {
+ public abstract void onSetPlayItem(int scope, long uid);
+ }
+
+ /**
+ * @hide
+ */
+ public void setPlayItemListener(OnSetPlayItemListener l) {
+ Log.d(TAG, "setPlayItemListener");
+ synchronized(mCacheLock) {
+ mSetPlayItemListener = l;
+ }
+ }
/**
* Interface definition for a callback to be invoked when the media playback position is
@@ -946,6 +1069,13 @@ import java.lang.IllegalArgumentException;
/**
* The current remote control client generation ID across the system, as known by this object
*/
+
+ private OnSetBrowsedPlayerListener mSetBrowsedPlayerListener;
+
+ private OnSetPlayItemListener mSetPlayItemListener;
+
+ private OnGetNowPlayingEntriesListener mGetNowPlayingEntriesListener;
+
private int mCurrentClientGenId = -1;
/**
@@ -999,10 +1129,43 @@ import java.lang.IllegalArgumentException;
onUpdateMetadata(mCurrentClientGenId, MetadataEditor.RATING_KEY_BY_USER, rating);
}
}
+
+ @Override
+ public void setPlayItem(int scope, long uid) {
+ // only post messages, we can't block here
+ if (mEventHandler != null) {
+ mEventHandler.removeMessages(MSG_SET_PLAY_ITEM);
+ mEventHandler.sendMessage(mEventHandler.obtainMessage(
+ MSG_SET_PLAY_ITEM, 0 /* arg1 */, scope /* arg2, ignored */,
+ new Long(uid)));
+ }
+ }
+
+ @Override
+ public void getNowPlayingEntries() {
+ // only post messages, we can't block here
+ if (mEventHandler != null) {
+ mEventHandler.removeMessages(MSG_GET_NOW_PLAYING_ENTRIES);
+ mEventHandler.sendMessage(mEventHandler.obtainMessage(
+ MSG_GET_NOW_PLAYING_ENTRIES, 0, 0, null));
+ }
+ }
+
+ @Override
+ public void setBrowsedPlayer() {
+ Log.d(TAG, "setBrowsedPlayer in RemoteControlClient");
+ if (mEventHandler != null) {
+ mEventHandler.sendMessage(mEventHandler.obtainMessage(
+ MSG_SET_BROWSED_PLAYER, 0 /* arg1 */, 0 /* arg2*/, null));
+ }
+ }
};
private EventHandler mEventHandler;
private final static int MSG_POSITION_DRIFT_CHECK = 11;
+ private final static int MSG_SET_BROWSED_PLAYER = 12;
+ private final static int MSG_SET_PLAY_ITEM = 13;
+ private final static int MSG_GET_NOW_PLAYING_ENTRIES = 14;
private class EventHandler extends Handler {
public EventHandler(RemoteControlClient rcc, Looper looper) {
@@ -1015,6 +1178,16 @@ import java.lang.IllegalArgumentException;
case MSG_POSITION_DRIFT_CHECK:
onPositionDriftCheck();
break;
+ case MSG_SET_BROWSED_PLAYER:
+ Log.d(TAG, "MSG_SET_BROWSED_PLAYER in RemoteControlClient");
+ onSetBrowsedPlayer();
+ break;
+ case MSG_SET_PLAY_ITEM:
+ onSetPlayItem(msg.arg2, ((Long)msg.obj).longValue());
+ break;
+ case MSG_GET_NOW_PLAYING_ENTRIES:
+ onGetNowPlayingEntries();
+ break;
default:
Log.e(TAG, "Unknown event " + msg.what + " in RemoteControlClient handler");
}
@@ -1040,6 +1213,36 @@ import java.lang.IllegalArgumentException;
}
}
+ private void onSetPlayItem(int scope, long uid) {
+ Log.d(TAG, "onSetPlayItem");
+ synchronized (mCacheLock) {
+ if (mSetPlayItemListener != null) {
+ Log.d(TAG, "mSetPlayItemListener.onSetPlayItem");
+ mSetPlayItemListener.onSetPlayItem(scope, uid);
+ }
+ }
+ }
+
+ private void onSetBrowsedPlayer() {
+ Log.d(TAG, "onSetBrowsedPlayer");
+ synchronized (mCacheLock) {
+ if (mSetBrowsedPlayerListener != null) {
+ Log.d(TAG, "mSetBrowsedPlayerListener.onSetBrowsedPlayer");
+ mSetBrowsedPlayerListener.onSetBrowsedPlayer();
+ }
+ }
+ }
+
+ private void onGetNowPlayingEntries() {
+ Log.d(TAG, "onGetNowPlayingEntries");
+ synchronized (mCacheLock) {
+ if (mGetNowPlayingEntriesListener != null) {
+ Log.d(TAG, "mGetNowPlayingEntriesListener.onGetNowPlayingEntries");
+ mGetNowPlayingEntriesListener.onGetNowPlayingEntries();
+ }
+ }
+ }
+
//===========================================================
// Internal utilities
diff --git a/media/java/android/media/RemoteController.java b/media/java/android/media/RemoteController.java
index d84cf30..aba7ad6 100644
--- a/media/java/android/media/RemoteController.java
+++ b/media/java/android/media/RemoteController.java
@@ -88,6 +88,7 @@ import java.util.List;
private boolean mIsRegistered = false;
private PendingIntent mClientPendingIntentCurrent;
private OnClientUpdateListener mOnClientUpdateListener;
+ private OnClientAvrcpUpdateListener mOnClientAvrcpUpdateListener;
private PlaybackInfo mLastPlaybackInfo;
private int mArtworkWidth = -1;
private int mArtworkHeight = -1;
@@ -150,6 +151,25 @@ import java.util.List;
}
}
+ /**
+ * @hide
+ */
+ public RemoteController(Context context, OnClientUpdateListener updateListener, Looper looper,
+ OnClientAvrcpUpdateListener avrcpUpdateListener) throws IllegalArgumentException {
+ this(context, updateListener, looper);
+ mOnClientAvrcpUpdateListener = avrcpUpdateListener;
+ }
+
+ /**
+ * @hide
+ */
+ public interface OnClientAvrcpUpdateListener {
+ public void onClientFolderInfoBrowsedPlayer(String stringUri);
+ public void onClientUpdateNowPlayingEntries(long[] playList);
+ public void onClientNowPlayingContentChange();
+ public void onClientPlayItemResponse(boolean success);
+ };
+
/**
* Interface definition for the callbacks to be invoked whenever media events, metadata
@@ -355,6 +375,7 @@ import java.util.List;
* @throws IllegalArgumentException
*/
public boolean seekTo(long timeMs) throws IllegalArgumentException {
+ Log.e(TAG, "seekTo() in RemoteController");
if (!mEnabled) {
Log.e(TAG, "Cannot use seekTo() from a disabled RemoteController");
return false;
@@ -370,6 +391,69 @@ import java.util.List;
return true;
}
+ /**
+ * @hide
+ * Request the user of a RemoteControlClient to play the requested item.
+ * @param generationId the RemoteControlClient generation counter for which this request is
+ * issued.
+ * @param uid uid of the song to be played.
+ * @scope scope of the file system to use
+ */
+ public void setRemoteControlClientPlayItem(long uid, int scope) {
+ Log.e(TAG, "setRemoteControlClientPlayItem()");
+ if (!mEnabled) {
+ Log.e(TAG, "Cannot use setRemoteControlClientPlayItem()" +
+ " from a disabled RemoteController");
+ return;
+ }
+ synchronized (mInfoLock) {
+ if (mCurrentSession != null) {
+ mCurrentSession.getTransportControls().setRemoteControlClientPlayItem(uid, scope);
+ }
+ }
+ return;
+ }
+
+ /**
+ * @hide
+ * Request the user of a RemoteControlClient to provide with the now playing list entries.
+ * @param generationId the RemoteControlClient generation counter for which this request is
+ * issued.
+ */
+ public void getRemoteControlClientNowPlayingEntries() {
+ Log.e(TAG, "getRemoteControlClientNowPlayingEntries()");
+ if (!mEnabled) {
+ Log.e(TAG, "Cannot use getRemoteControlClientNowPlayingEntries()" +
+ " from a disabled RemoteController");
+ return;
+ }
+ synchronized (mInfoLock) {
+ if (mCurrentSession != null) {
+ mCurrentSession.getTransportControls().getRemoteControlClientNowPlayingEntries();
+ }
+ }
+ return;
+ }
+
+ /**
+ * @hide
+ * Request the user of a RemoteControlClient to set the music player as current browsed player.
+ * @param packageName package name of the targeted media player.
+ */
+ public void setRemoteControlClientBrowsedPlayer() {
+ Log.e(TAG, "setRemoteControlClientBrowsedPlayer()");
+ if (!mEnabled) {
+ Log.e(TAG, "Cannot use setRemoteControlClientBrowsedPlayer()" +
+ " from a disabled RemoteController");
+ return;
+ }
+ synchronized (mInfoLock) {
+ if (mCurrentSession != null) {
+ mCurrentSession.getTransportControls().setRemoteControlClientBrowsedPlayer();
+ }
+ }
+ return;
+ }
/**
* @hide
@@ -704,6 +788,30 @@ import java.util.List;
public void onMetadataChanged(MediaMetadata metadata) {
onNewMediaMetadata(metadata);
}
+
+ @Override
+ public void onUpdateFolderInfoBrowsedPlayer(String stringUri) {
+ Log.d(TAG, "MediaControllerCallback: onUpdateFolderInfoBrowsedPlayer");
+ onFolderInfoBrowsedPlayer(stringUri);
+ }
+
+ @Override
+ public void onUpdateNowPlayingEntries(long[] playList) {
+ Log.d(TAG, "MediaControllerCallback: onUpdateNowPlayingEntries");
+ onNowPlayingEntriesUpdate(playList);
+ }
+
+ @Override
+ public void onUpdateNowPlayingContentChange() {
+ Log.d(TAG, "MediaControllerCallback: onUpdateNowPlayingContentChange");
+ onNowPlayingContentChange();
+ }
+
+ @Override
+ public void onPlayItemResponse(boolean success) {
+ Log.d(TAG, "MediaControllerCallback: onPlayItemResponse");
+ onSetPlayItemResponse(success);
+ }
}
/**
@@ -980,6 +1088,8 @@ import java.util.List;
synchronized (mInfoLock) {
if (controller == null) {
if (mCurrentSession != null) {
+ Log.v(TAG, "Updating current controller as null");
+ mAudioManager.updateMediaPlayerList(mCurrentSession.getPackageName(), false);
mCurrentSession.unregisterCallback(mSessionCb);
mCurrentSession = null;
sendMsg(mEventHandler, MSG_CLIENT_CHANGE, SENDMSG_REPLACE,
@@ -989,13 +1099,21 @@ import java.util.List;
|| !controller.getSessionToken()
.equals(mCurrentSession.getSessionToken())) {
if (mCurrentSession != null) {
+ Log.v(TAG, "Updating current controller package as " +
+ controller.getPackageName() + " from " + mCurrentSession.getPackageName());
mCurrentSession.unregisterCallback(mSessionCb);
+ } else {
+ Log.v(TAG, "Updating current controller package as " +
+ controller.getPackageName() + " from null");
}
+
sendMsg(mEventHandler, MSG_CLIENT_CHANGE, SENDMSG_REPLACE,
0 /* genId */, 0 /* clearing */, null /* obj */, 0 /* delay */);
mCurrentSession = controller;
mCurrentSession.registerCallback(mSessionCb, mEventHandler);
+ mAudioManager.updateMediaPlayerList(mCurrentSession.getPackageName(), true);
+
PlaybackState state = controller.getPlaybackState();
sendMsg(mEventHandler, MSG_NEW_PLAYBACK_STATE, SENDMSG_REPLACE,
0 /* genId */, 0, state /* obj */, 0 /* delay */);
@@ -1052,6 +1170,74 @@ import java.util.List;
}
}
+ private void onFolderInfoBrowsedPlayer(String stringUri) {
+ Log.d(TAG, "RemoteController: onFolderInfoBrowsedPlayer");
+ final OnClientAvrcpUpdateListener l;
+
+ synchronized(mInfoLock) {
+ l = mOnClientAvrcpUpdateListener;
+ }
+
+ try {
+ if (l != null) {
+ l.onClientFolderInfoBrowsedPlayer(stringUri);
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "Error Updating AVRCP on receiving Browsed player response", e);
+ }
+ }
+
+ private void onNowPlayingEntriesUpdate(long[] playList) {
+ Log.d(TAG, "RemoteController: onUpdateNowPlayingEntries");
+ final OnClientAvrcpUpdateListener l;
+
+ synchronized(mInfoLock) {
+ l = mOnClientAvrcpUpdateListener;
+ }
+
+ try {
+ if (l != null) {
+ l.onClientUpdateNowPlayingEntries(playList);
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "Error Updating AVRCP on receiving Now Playing Entries", e);
+ }
+ }
+
+ private void onNowPlayingContentChange() {
+ Log.d(TAG, "RemoteController: onNowPlayingContentChange");
+ final OnClientAvrcpUpdateListener l;
+
+ synchronized(mInfoLock) {
+ l = mOnClientAvrcpUpdateListener;
+ }
+
+ try {
+ if (l != null) {
+ l.onClientNowPlayingContentChange();
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "Error Updating AVRCP on Now Playing Content Change", e);
+ }
+ }
+
+ private void onSetPlayItemResponse(boolean success) {
+ Log.d(TAG, "RemoteController: onPlayItemResponse");
+ final OnClientAvrcpUpdateListener l;
+
+ synchronized(mInfoLock) {
+ l = mOnClientAvrcpUpdateListener;
+ }
+
+ try {
+ if (l != null) {
+ l.onClientPlayItemResponse(success);
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "Error Updating AVRCP on receiving Play Item response", e);
+ }
+ }
+
//==================================================
private static class PlaybackInfo {
int mState;
diff --git a/media/java/android/media/RingtoneManager.java b/media/java/android/media/RingtoneManager.java
index 025029e..01cae5c 100644
--- a/media/java/android/media/RingtoneManager.java
+++ b/media/java/android/media/RingtoneManager.java
@@ -184,6 +184,16 @@ public class RingtoneManager {
*/
public static final String EXTRA_RINGTONE_PICKED_URI =
"android.intent.extra.ringtone.PICKED_URI";
+
+ /**
+ * Set the resource id theme to use for the dialog picker activity.<br/>
+ * The default theme is <code>com.android.internal.R.Theme_Holo_Dialog_Alert</code>.
+ *
+ * @see #ACTION_RINGTONE_PICKER
+ * @hide
+ */
+ public static final String EXTRA_RINGTONE_DIALOG_THEME =
+ "android.intent.extra.ringtone.DIALOG_THEME";
// Make sure the column ordering and then ..._COLUMN_INDEX are in sync
diff --git a/media/java/android/media/ToneGenerator.java b/media/java/android/media/ToneGenerator.java
index 4661226..05e4471 100644
--- a/media/java/android/media/ToneGenerator.java
+++ b/media/java/android/media/ToneGenerator.java
@@ -728,13 +728,24 @@ public class ToneGenerator
* @see #ToneGenerator(int, int)
*/
public static final int TONE_CDMA_SIGNAL_OFF = 98;
+ /**
+ * SUPERVISORY_CH - 440Hz
+ *
+ * @hide #ToneGenerator(int, int)
+ */
+ public static final int TONE_SUPERVISORY_CH = 100;
+ /**
+ * HOLD_RECALL - 440Hz
+ *
+ * @hide #ToneGenerator(int, int)
+ */
+ public static final int TONE_HOLD_RECALL = 101;
/** Maximum volume, for use with {@link #ToneGenerator(int,int)} */
public static final int MAX_VOLUME = 100;
/** Minimum volume setting, for use with {@link #ToneGenerator(int,int)} */
public static final int MIN_VOLUME = 0;
-
/**
* ToneGenerator class contructor specifying output stream type and volume.
*
diff --git a/media/java/android/media/session/ISession.aidl b/media/java/android/media/session/ISession.aidl
index bd0019f..34eadcb 100644
--- a/media/java/android/media/session/ISession.aidl
+++ b/media/java/android/media/session/ISession.aidl
@@ -45,6 +45,10 @@ interface ISession {
void setQueueTitle(CharSequence title);
void setExtras(in Bundle extras);
void setRatingType(int type);
+ void playItemResponse(boolean success);
+ void updateNowPlayingEntries(in long[] playList);
+ void updateFolderInfoBrowsedPlayer(String stringUri);
+ void updateNowPlayingContentChange();
// These commands relate to volume handling
void setPlaybackToLocal(in AudioAttributes attributes);
diff --git a/media/java/android/media/session/ISessionCallback.aidl b/media/java/android/media/session/ISessionCallback.aidl
index adb6b06..ed13ff6 100644
--- a/media/java/android/media/session/ISessionCallback.aidl
+++ b/media/java/android/media/session/ISessionCallback.aidl
@@ -41,6 +41,9 @@ oneway interface ISessionCallback {
void onFastForward();
void onRewind();
void onSeekTo(long pos);
+ void setRemoteControlClientBrowsedPlayer();
+ void setRemoteControlClientPlayItem(long uid, int scope);
+ void getRemoteControlClientNowPlayingEntries();
void onRate(in Rating rating);
void onCustomAction(String action, in Bundle args);
diff --git a/media/java/android/media/session/ISessionController.aidl b/media/java/android/media/session/ISessionController.aidl
index 285e5f7..006ffac 100644
--- a/media/java/android/media/session/ISessionController.aidl
+++ b/media/java/android/media/session/ISessionController.aidl
@@ -62,6 +62,9 @@ interface ISessionController {
void fastForward();
void rewind();
void seekTo(long pos);
+ void setRemoteControlClientBrowsedPlayer();
+ void setRemoteControlClientPlayItem(long uid, int scope);
+ void getRemoteControlClientNowPlayingEntries();
void rate(in Rating rating);
void sendCustomAction(String action, in Bundle args);
MediaMetadata getMetadata();
diff --git a/media/java/android/media/session/ISessionControllerCallback.aidl b/media/java/android/media/session/ISessionControllerCallback.aidl
index cf31767..a5ad913 100644
--- a/media/java/android/media/session/ISessionControllerCallback.aidl
+++ b/media/java/android/media/session/ISessionControllerCallback.aidl
@@ -36,4 +36,8 @@ oneway interface ISessionControllerCallback {
void onQueueTitleChanged(CharSequence title);
void onExtrasChanged(in Bundle extras);
void onVolumeInfoChanged(in ParcelableVolumeInfo info);
+ void onPlayItemResponse(boolean success);
+ void onUpdateNowPlayingEntries(in long[] playList);
+ void onUpdateFolderInfoBrowsedPlayer(String stringUri);
+ void onUpdateNowPlayingContentChange();
}
diff --git a/media/java/android/media/session/MediaController.java b/media/java/android/media/session/MediaController.java
index b1a51a5..f1f9516 100644
--- a/media/java/android/media/session/MediaController.java
+++ b/media/java/android/media/session/MediaController.java
@@ -64,6 +64,10 @@ public final class MediaController {
private static final int MSG_UPDATE_QUEUE_TITLE = 6;
private static final int MSG_UPDATE_EXTRAS = 7;
private static final int MSG_DESTROYED = 8;
+ private static final int MSG_FOLDER_INFO_BROWSED_PLAYER = 9;
+ private static final int MSG_UPDATE_NOWPLAYING_ENTRIES = 10;
+ private static final int MSG_UPDATE_NOWPLAYING_CONTENT_CHANGE = 11;
+ private static final int MSG_PLAY_ITEM_RESPONSE = 12;
private final ISessionController mSessionBinder;
@@ -579,6 +583,31 @@ public final class MediaController {
*/
public void onAudioInfoChanged(PlaybackInfo info) {
}
+
+ /**
+ * @hide
+ */
+ public void onUpdateFolderInfoBrowsedPlayer(String stringUri) {
+ }
+
+ /**
+ * @hide
+ */
+ public void onUpdateNowPlayingEntries(long[] playList) {
+ }
+
+ /**
+ * @hide
+ */
+ public void onUpdateNowPlayingContentChange() {
+ }
+
+ /**
+ * @hide
+ */
+ public void onPlayItemResponse(boolean success) {
+ }
+
}
/**
@@ -704,6 +733,7 @@ public final class MediaController {
* @param pos Position to move to, in milliseconds.
*/
public void seekTo(long pos) {
+ Log.d(TAG, "seekTo in TransportControls");
try {
mSessionBinder.seekTo(pos);
} catch (RemoteException e) {
@@ -712,6 +742,42 @@ public final class MediaController {
}
/**
+ * @hide
+ */
+ public void setRemoteControlClientBrowsedPlayer() {
+ Log.d(TAG, "setRemoteControlClientBrowsedPlayer in TransportControls");
+ try {
+ mSessionBinder.setRemoteControlClientBrowsedPlayer();
+ } catch (RemoteException e) {
+ Log.wtf(TAG, "Error calling setRemoteControlClientBrowsedPlayer.", e);
+ }
+ }
+
+ /**
+ * @hide
+ */
+ public void setRemoteControlClientPlayItem(long uid, int scope) {
+ Log.d(TAG, "setRemoteControlClientPlayItem in TransportControls");
+ try {
+ mSessionBinder.setRemoteControlClientPlayItem(uid, scope);
+ } catch (RemoteException e) {
+ Log.wtf(TAG, "Error calling setRemoteControlClientPlayItem.", e);
+ }
+ }
+
+ /**
+ * @hide
+ */
+ public void getRemoteControlClientNowPlayingEntries() {
+ Log.d(TAG, "getRemoteControlClientNowPlayingEntries in TransportControls");
+ try {
+ mSessionBinder.getRemoteControlClientNowPlayingEntries();
+ } catch (RemoteException e) {
+ Log.wtf(TAG, "Error calling getRemoteControlClientNowPlayingEntries.", e);
+ }
+ }
+
+ /**
* Start fast forwarding. If playback is already fast forwarding this
* may increase the rate.
*/
@@ -973,6 +1039,42 @@ public final class MediaController {
}
}
+ @Override
+ public void onUpdateFolderInfoBrowsedPlayer(String stringUri) {
+ Log.d(TAG, "CallBackStub: onUpdateFolderInfoBrowsedPlayer");
+ MediaController controller = mController.get();
+ if (controller != null) {
+ controller.postMessage(MSG_FOLDER_INFO_BROWSED_PLAYER, stringUri, null);
+ }
+ }
+
+ @Override
+ public void onUpdateNowPlayingEntries(long[] playList) {
+ Log.d(TAG, "CallBackStub: onUpdateNowPlayingEntries");
+ MediaController controller = mController.get();
+ if (controller != null) {
+ controller.postMessage(MSG_UPDATE_NOWPLAYING_ENTRIES, playList, null);
+ }
+ }
+
+ @Override
+ public void onUpdateNowPlayingContentChange() {
+ Log.d(TAG, "CallBackStub: onUpdateNowPlayingContentChange");
+ MediaController controller = mController.get();
+ if (controller != null) {
+ controller.postMessage(MSG_UPDATE_NOWPLAYING_CONTENT_CHANGE, null, null);
+ }
+ }
+
+ @Override
+ public void onPlayItemResponse(boolean success) {
+ Log.d(TAG, "CallBackStub: onPlayItemResponse");
+ MediaController controller = mController.get();
+ if (controller != null) {
+ controller.postMessage(MSG_PLAY_ITEM_RESPONSE, new Boolean(success), null);
+ }
+ }
+
}
private final static class MessageHandler extends Handler {
@@ -1014,6 +1116,18 @@ public final class MediaController {
case MSG_DESTROYED:
mCallback.onSessionDestroyed();
break;
+ case MSG_FOLDER_INFO_BROWSED_PLAYER:
+ mCallback.onUpdateFolderInfoBrowsedPlayer((String) msg.obj);
+ break;
+ case MSG_UPDATE_NOWPLAYING_ENTRIES:
+ mCallback.onUpdateNowPlayingEntries((long[]) msg.obj);
+ break;
+ case MSG_UPDATE_NOWPLAYING_CONTENT_CHANGE:
+ mCallback.onUpdateNowPlayingContentChange();
+ break;
+ case MSG_PLAY_ITEM_RESPONSE:
+ mCallback.onPlayItemResponse(((Boolean)(msg.obj)).booleanValue());
+ break;
}
}
diff --git a/media/java/android/media/session/MediaSession.java b/media/java/android/media/session/MediaSession.java
index e1e9b79..be89dfc 100644
--- a/media/java/android/media/session/MediaSession.java
+++ b/media/java/android/media/session/MediaSession.java
@@ -493,6 +493,58 @@ public final class MediaSession {
}
/**
+ * @hide
+ */
+ public void playItemResponse(boolean success) {
+ Log.d(TAG, "MediaSession: playItemResponse");
+
+ try {
+ mBinder.playItemResponse(success);
+ } catch (RemoteException e) {
+ Log.wtf(TAG, "Dead object in playItemResponse.", e);
+ }
+ }
+
+ /**
+ * @hide
+ */
+ public void updateNowPlayingEntries(long[] playList) {
+ Log.d(TAG, "MediaSession: updateNowPlayingEntries");
+
+ try {
+ mBinder.updateNowPlayingEntries(playList);
+ } catch (RemoteException e) {
+ Log.wtf(TAG, "Dead object in updateNowPlayingEntries.", e);
+ }
+ }
+
+ /**
+ * @hide
+ */
+ public void updateFolderInfoBrowsedPlayer(String stringUri) {
+ Log.d(TAG, "MediaSession: updateFolderInfoBrowsedPlayer");
+
+ try {
+ mBinder.updateFolderInfoBrowsedPlayer(stringUri);
+ } catch (RemoteException e) {
+ Log.wtf(TAG, "Dead object in updateFolderInfoBrowsedPlayer.", e);
+ }
+ }
+
+ /**
+ * @hide
+ */
+ public void updateNowPlayingContentChange() {
+ Log.d(TAG, "MediaSession: updateNowPlayingContentChange");
+
+ try {
+ mBinder.updateNowPlayingContentChange();
+ } catch (RemoteException e) {
+ Log.wtf(TAG, "Dead object in updateNowPlayingContentChange.", e);
+ }
+ }
+
+ /**
* Notify the system that the remote volume changed.
*
* @param provider The provider that is handling volume changes.
@@ -572,6 +624,34 @@ public final class MediaSession {
postToCallback(CallbackMessageHandler.MSG_MEDIA_BUTTON, mediaButtonIntent);
}
+ private void dispatchSetBrowsedPlayerCommand() {
+ postToCallback(CallbackMessageHandler.MSG_SET_BROWSED_PLAYER);
+ }
+
+ private void dispatchSetPlayItemCommand(long uid, int scope) {
+ PlayItemToken playItemToken = new PlayItemToken(uid, scope);
+ postToCallback(CallbackMessageHandler.MSG_SET_PLAY_ITEM, playItemToken);
+ }
+
+ private class PlayItemToken {
+ private long mUid;
+ private int mScope;
+ public PlayItemToken(long uid, int scope) {
+ mUid = uid;
+ mScope = scope;
+ }
+ public int getScope() {
+ return mScope;
+ }
+ public long getUid() {
+ return mUid;
+ }
+ }
+
+ private void dispatchGetNowPlayingItemsCommand() {
+ postToCallback(CallbackMessageHandler.MSG_GET_NOW_PLAYING_ITEMS);
+ }
+
private void dispatchAdjustVolume(int direction) {
postToCallback(CallbackMessageHandler.MSG_ADJUST_VOLUME, direction);
}
@@ -894,6 +974,25 @@ public final class MediaSession {
*/
public void onCustomAction(@NonNull String action, @Nullable Bundle extras) {
}
+
+ /**
+ * @hide
+ */
+ public void setBrowsedPlayer() {
+ }
+
+ /**
+ * @hide
+ */
+ public void setPlayItem(int scope, long uid) {
+ }
+
+ /**
+ * @hide
+ */
+ public void getNowPlayingEntries() {
+ }
+
}
/**
@@ -1034,6 +1133,33 @@ public final class MediaSession {
}
@Override
+ public void setRemoteControlClientBrowsedPlayer() throws RemoteException {
+ Log.d(TAG, "setRemoteControlClientBrowsedPlayer in CallbackStub");
+ MediaSession session = mMediaSession.get();
+ if (session != null) {
+ session.dispatchSetBrowsedPlayerCommand();
+ }
+ }
+
+ @Override
+ public void setRemoteControlClientPlayItem(long uid, int scope) throws RemoteException {
+ Log.d(TAG, "setRemoteControlClientPlayItem in CallbackStub");
+ MediaSession session = mMediaSession.get();
+ if (session != null) {
+ session.dispatchSetPlayItemCommand(uid, scope);
+ }
+ }
+
+ @Override
+ public void getRemoteControlClientNowPlayingEntries() throws RemoteException {
+ Log.d(TAG, "getRemoteControlClientNowPlayingEntries in CallbackStub");
+ MediaSession session = mMediaSession.get();
+ if (session != null) {
+ session.dispatchGetNowPlayingItemsCommand();
+ }
+ }
+
+ @Override
public void onCustomAction(String action, Bundle args) {
MediaSession session = mMediaSession.get();
if (session != null) {
@@ -1173,6 +1299,9 @@ public final class MediaSession {
private static final int MSG_ADJUST_VOLUME = 16;
private static final int MSG_SET_VOLUME = 17;
private static final int MSG_PLAY_URI = 18;
+ private static final int MSG_SET_BROWSED_PLAYER = 19;
+ private static final int MSG_SET_PLAY_ITEM = 20;
+ private static final int MSG_GET_NOW_PLAYING_ITEMS = 21;
private MediaSession.Callback mCallback;
@@ -1267,6 +1396,18 @@ public final class MediaSession {
if (vp != null) {
vp.onSetVolumeTo((int) msg.obj);
}
+ case MSG_SET_BROWSED_PLAYER:
+ Log.d(TAG, "MSG_SET_BROWSED_PLAYER received in CallbackMessageHandler");
+ mCallback.setBrowsedPlayer();
+ break;
+ case MSG_SET_PLAY_ITEM:
+ Log.d(TAG, "MSG_SET_PLAY_ITEM received in CallbackMessageHandler");
+ PlayItemToken playItemToken = (PlayItemToken) msg.obj;
+ mCallback.setPlayItem(playItemToken.getScope(), playItemToken.getUid());
+ break;
+ case MSG_GET_NOW_PLAYING_ITEMS:
+ Log.d(TAG, "MSG_GET_NOW_PLAYING_ITEMS received in CallbackMessageHandler");
+ mCallback.getNowPlayingEntries();
break;
}
}
diff --git a/media/java/android/media/session/MediaSessionLegacyHelper.java b/media/java/android/media/session/MediaSessionLegacyHelper.java
index c61d7ad..22082b9 100644
--- a/media/java/android/media/session/MediaSessionLegacyHelper.java
+++ b/media/java/android/media/session/MediaSessionLegacyHelper.java
@@ -549,6 +549,27 @@ public class MediaSessionLegacyHelper {
mRccListener.onSetRating(rating);
}
}
+
+ @Override
+ public void setBrowsedPlayer() {
+ if (mRccListener != null) {
+ mRccListener.setBrowsedPlayer();
+ }
+ }
+
+ @Override
+ public void setPlayItem(int scope, long uid) {
+ if (mRccListener != null) {
+ mRccListener.setPlayItem(scope, uid);
+ }
+ }
+
+ @Override
+ public void getNowPlayingEntries() {
+ if (mRccListener != null) {
+ mRccListener.getNowPlayingEntries();
+ }
+ }
}
}
}
diff --git a/media/java/android/mtp/MtpServer.java b/media/java/android/mtp/MtpServer.java
index 3814630..e830afd 100644
--- a/media/java/android/mtp/MtpServer.java
+++ b/media/java/android/mtp/MtpServer.java
@@ -56,6 +56,10 @@ public class MtpServer implements Runnable {
native_send_device_property_changed(property);
}
+ public void sendObjectUpdated(int handle) {
+ native_send_object_updated(handle);
+ }
+
public void addStorage(MtpStorage storage) {
native_add_storage(storage);
}
@@ -70,6 +74,7 @@ public class MtpServer implements Runnable {
private native final void native_send_object_added(int handle);
private native final void native_send_object_removed(int handle);
private native final void native_send_device_property_changed(int property);
+ private native final void native_send_object_updated(int handle);
private native final void native_add_storage(MtpStorage storage);
private native final void native_remove_storage(int storageId);
}
diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp
index d8041f4..88670ea 100644
--- a/media/jni/android_media_MediaPlayer.cpp
+++ b/media/jni/android_media_MediaPlayer.cpp
@@ -49,6 +49,7 @@
#include <gui/Surface.h>
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
+#include <dlfcn.h>
#include "android_util_Binder.h"
// ----------------------------------------------------------------------------
@@ -137,6 +138,153 @@ void JNIMediaPlayerListener::notify(int msg, int ext1, int ext2, const Parcel *o
}
}
+
+static const char *EXTMEDIAJNI_LIB_NAME = "libextmedia_jni.so";
+static const char *kCreateJNIExtMediaPlayerListener = "CreateJNIExtMediaPlayerListener";
+static const char *kCheckExtMedia = "checkExtMedia";
+static const char *kCreateNativeQCMediaPlayer = "CreateNativeQCMediaPlayer";
+typedef MediaPlayerListener* (*CreateJNIExtMediaPlayerListenerFn)(JNIEnv *, jobject, jobject, sp<MediaPlayerListener> listener);
+typedef bool (*CheckExtMediaFn)(JNIEnv *env, jobject);
+typedef MediaPlayer* (*CreateNativeQCMediaPlayerFn)();
+
+
+
+class JNIMediaPlayerFactory {
+ public:
+ JNIMediaPlayerFactory() {};
+ static bool CheckAndCreateExtMediaPlayer(JNIEnv *env, jobject thiz, jobject weak_this, sp<MediaPlayerListener> &listener, sp<MediaPlayer> &mp);
+ private:
+ static void *mLibHandle;
+ static void loadLib();
+
+ static CreateJNIExtMediaPlayerListenerFn loadJNIExtMediaPlayerListener();
+ static CreateJNIExtMediaPlayerListenerFn sExtDashListnerFnPtr;
+
+ static CheckExtMediaFn sExtMediaFn;
+ static CheckExtMediaFn loadExtMedia();
+
+ static CreateNativeQCMediaPlayerFn sNativeQCMediaPlayerFn;
+ static CreateNativeQCMediaPlayerFn loadNativeQCMediaPlayer();
+
+ static sp<MediaPlayerListener> createExtMediaPlayerListener(JNIEnv *env, jobject thiz, jobject weak_this, sp<MediaPlayerListener> listener);
+ static bool checkExtMedia(JNIEnv *env, jobject thiz);
+ static void CreateNativeQCMediaPlayer(sp<MediaPlayer> &mp);
+};
+
+void *JNIMediaPlayerFactory::mLibHandle = NULL;
+
+CreateJNIExtMediaPlayerListenerFn JNIMediaPlayerFactory::sExtDashListnerFnPtr =
+ JNIMediaPlayerFactory::loadJNIExtMediaPlayerListener();
+
+CheckExtMediaFn JNIMediaPlayerFactory::sExtMediaFn =
+ JNIMediaPlayerFactory::loadExtMedia();
+
+CreateNativeQCMediaPlayerFn JNIMediaPlayerFactory::sNativeQCMediaPlayerFn =
+ JNIMediaPlayerFactory::loadNativeQCMediaPlayer();
+
+
+void JNIMediaPlayerFactory::loadLib()
+{
+ if (!mLibHandle) {
+ mLibHandle = ::dlopen(EXTMEDIAJNI_LIB_NAME, RTLD_LAZY);
+ if (!mLibHandle) {
+ ALOGV("%s", dlerror());
+ return;
+ }
+ ALOGV("Opened %s", EXTMEDIAJNI_LIB_NAME);
+ }
+}
+
+CreateJNIExtMediaPlayerListenerFn JNIMediaPlayerFactory::loadJNIExtMediaPlayerListener()
+{
+ loadLib();
+ CreateJNIExtMediaPlayerListenerFn pCreateExtDashListnerFnPtr = NULL;
+ if (mLibHandle != NULL) {
+ pCreateExtDashListnerFnPtr = (CreateJNIExtMediaPlayerListenerFn)
+ dlsym(mLibHandle, kCreateJNIExtMediaPlayerListener);
+ if (pCreateExtDashListnerFnPtr == NULL) {
+ ALOGW("Failed to load symbol %s : %s", kCreateJNIExtMediaPlayerListener, dlerror());
+ }
+ }
+ return pCreateExtDashListnerFnPtr;
+}
+
+CheckExtMediaFn JNIMediaPlayerFactory::loadExtMedia()
+{
+ loadLib();
+ CheckExtMediaFn pCheckExtMediaFnPtr = NULL;
+ if (mLibHandle != NULL) {
+ pCheckExtMediaFnPtr = (CheckExtMediaFn)dlsym(mLibHandle, kCheckExtMedia);
+ if (pCheckExtMediaFnPtr == NULL) {
+ ALOGW("Failed to load symbol %s : %s", kCheckExtMedia, dlerror());
+ }
+ }
+ return pCheckExtMediaFnPtr;
+}
+
+CreateNativeQCMediaPlayerFn JNIMediaPlayerFactory::loadNativeQCMediaPlayer()
+{
+ loadLib();
+ CreateNativeQCMediaPlayerFn pCreateNativeQCMediaPlayerFnPtr = NULL;
+ if (mLibHandle != NULL) {
+ pCreateNativeQCMediaPlayerFnPtr = (CreateNativeQCMediaPlayerFn)
+ dlsym(mLibHandle, kCreateNativeQCMediaPlayer);
+ if (pCreateNativeQCMediaPlayerFnPtr == NULL) {
+ ALOGW("Failed to load symbol %s : %s", kCreateNativeQCMediaPlayer, dlerror());
+ }
+ }
+ return pCreateNativeQCMediaPlayerFnPtr;
+}
+
+
+sp<MediaPlayerListener> JNIMediaPlayerFactory::createExtMediaPlayerListener(JNIEnv *env, jobject thiz, jobject weak_this, sp<MediaPlayerListener> listener)
+{
+ if (checkExtMedia(env, thiz)) {
+ if (sExtDashListnerFnPtr ) {
+ listener = (*sExtDashListnerFnPtr)(env, thiz, weak_this, listener);
+ if (listener != NULL) {
+ ALOGE("JNIMediaPlayerFactory: createExtMediaPlayerListener : success");
+ }
+ }
+ }
+ return listener;
+}
+
+void JNIMediaPlayerFactory::CreateNativeQCMediaPlayer(sp<MediaPlayer> &mp)
+{
+ if (sNativeQCMediaPlayerFn) {
+ mp = (*sNativeQCMediaPlayerFn)();
+ if (mp != NULL) {
+ ALOGE("JNIMediaPlayerFactory: CreateNativeQCMediaPlayer : Success");
+ }
+ }
+}
+
+
+bool JNIMediaPlayerFactory::checkExtMedia(JNIEnv *env, jobject thiz)
+{
+ bool bIsQCMediaPlayerPresent = false;
+ if (sExtMediaFn) {
+ bIsQCMediaPlayerPresent = (*sExtMediaFn)(env, thiz);
+ }
+ ALOGE("JNIMediaPlayerFactory: bIsQCMediaPlayerPresent %d", bIsQCMediaPlayerPresent);
+ return bIsQCMediaPlayerPresent;
+}
+
+bool JNIMediaPlayerFactory::CheckAndCreateExtMediaPlayer(
+ JNIEnv *env, jobject thiz, jobject weak_this, sp<MediaPlayerListener> &listener, sp<MediaPlayer> &mp)
+{
+ bool bOk = false;
+ listener = createExtMediaPlayerListener(env, thiz, weak_this, listener);
+ if (listener != NULL && checkExtMedia(env,thiz)) {
+ CreateNativeQCMediaPlayer(mp);
+ if (mp != NULL) {
+ bOk = true;
+ }
+ }
+ return bOk;
+}
+
// ----------------------------------------------------------------------------
static sp<MediaPlayer> getMediaPlayer(JNIEnv* env, jobject thiz)
@@ -868,14 +1016,26 @@ static void
android_media_MediaPlayer_native_setup(JNIEnv *env, jobject thiz, jobject weak_this)
{
ALOGV("native_setup");
- sp<MediaPlayer> mp = new MediaPlayer();
+
+ sp<MediaPlayer> mp = NULL;
+
+ bool bOk = false;
+ JNIMediaPlayerFactory *jniMediaPlayerFactory = new JNIMediaPlayerFactory();
+
+ sp<MediaPlayerListener> listener = new JNIMediaPlayerListener(env, thiz, weak_this);
+
+ if (jniMediaPlayerFactory) {
+ bOk = jniMediaPlayerFactory->CheckAndCreateExtMediaPlayer(env, thiz, weak_this, listener, mp);
+ delete(jniMediaPlayerFactory);
+ }
+
+ if (!bOk){
+ mp = new MediaPlayer();
+ }
if (mp == NULL) {
jniThrowException(env, "java/lang/RuntimeException", "Out of memory");
return;
}
-
- // create new listener and give it to MediaPlayer
- sp<JNIMediaPlayerListener> listener = new JNIMediaPlayerListener(env, thiz, weak_this);
mp->setListener(listener);
// Stow our new C++ MediaPlayer in an opaque field in the Java object.
@@ -1031,6 +1191,38 @@ android_media_MediaPlayer_setNextMediaPlayer(JNIEnv *env, jobject thiz, jobject
;
}
+static jboolean
+android_media_MediaPlayer_suspend(JNIEnv *env, jobject thiz)
+{
+ sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
+ if (mp == NULL) {
+ jniThrowException(env, "java/lang/IllegalStateException", NULL);
+ return false;
+ }
+
+ if (mp->suspend() != OK) {
+ return false;
+ }
+
+ return true;
+}
+
+static jboolean
+android_media_MediaPlayer_resume(JNIEnv *env, jobject thiz)
+{
+ sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
+ if (mp == NULL) {
+ jniThrowException(env, "java/lang/IllegalStateException", NULL);
+ return false;
+ }
+
+ if (mp->resume() != OK) {
+ return false;
+ }
+
+ return true;
+}
+
// ----------------------------------------------------------------------------
static JNINativeMethod gMethods[] = {
@@ -1080,6 +1272,8 @@ static JNINativeMethod gMethods[] = {
{"native_pullBatteryData", "(Landroid/os/Parcel;)I", (void *)android_media_MediaPlayer_pullBatteryData},
{"native_setRetransmitEndpoint", "(Ljava/lang/String;I)I", (void *)android_media_MediaPlayer_setRetransmitEndpoint},
{"setNextMediaPlayer", "(Landroid/media/MediaPlayer;)V", (void *)android_media_MediaPlayer_setNextMediaPlayer},
+ {"_suspend", "()Z", (void *)android_media_MediaPlayer_suspend},
+ {"_resume", "()Z", (void *)android_media_MediaPlayer_resume},
};
// This function only registers the native methods
diff --git a/media/jni/android_media_MediaProfiles.cpp b/media/jni/android_media_MediaProfiles.cpp
index ca9db91..30fd4c4 100644
--- a/media/jni/android_media_MediaProfiles.cpp
+++ b/media/jni/android_media_MediaProfiles.cpp
@@ -92,12 +92,17 @@ android_media_MediaProfiles_native_get_video_encoder_cap(JNIEnv *env, jobject /*
int maxFrameWidth = sProfiles->getVideoEncoderParamByName("enc.vid.width.max", encoder);
int minFrameHeight = sProfiles->getVideoEncoderParamByName("enc.vid.height.min", encoder);
int maxFrameHeight = sProfiles->getVideoEncoderParamByName("enc.vid.height.max", encoder);
+ int maxHFRFrameWidth = sProfiles->getVideoEncoderParamByName("enc.vid.hfr.width.max", encoder);
+ int maxHFRFrameHeight = sProfiles->getVideoEncoderParamByName("enc.vid.hfr.height.max", encoder);
+ int maxHFRMode = sProfiles->getVideoEncoderParamByName("enc.vid.hfr.mode.max", encoder);
// Check on the values retrieved
if ((minBitRate == -1 || maxBitRate == -1) ||
(minFrameRate == -1 || maxFrameRate == -1) ||
(minFrameWidth == -1 || maxFrameWidth == -1) ||
- (minFrameHeight == -1 || maxFrameHeight == -1)) {
+ (minFrameHeight == -1 || maxFrameHeight == -1) ||
+ (maxHFRFrameWidth == -1 || maxHFRFrameHeight == -1) ||
+ (maxHFRMode == -1)) {
jniThrowException(env, "java/lang/RuntimeException", "Error retrieving video encoder capability params");
return NULL;
@@ -105,14 +110,16 @@ android_media_MediaProfiles_native_get_video_encoder_cap(JNIEnv *env, jobject /*
// Construct an instance of the VideoEncoderCap and set its member variables
jclass videoEncoderCapClazz = env->FindClass("android/media/EncoderCapabilities$VideoEncoderCap");
- jmethodID videoEncoderCapConstructorMethodID = env->GetMethodID(videoEncoderCapClazz, "<init>", "(IIIIIIIII)V");
+ jmethodID videoEncoderCapConstructorMethodID = env->GetMethodID(videoEncoderCapClazz, "<init>", "(IIIIIIIIIIII)V");
jobject cap = env->NewObject(videoEncoderCapClazz,
videoEncoderCapConstructorMethodID,
static_cast<int>(encoder),
minBitRate, maxBitRate,
minFrameRate, maxFrameRate,
minFrameWidth, maxFrameWidth,
- minFrameHeight, maxFrameHeight);
+ minFrameHeight, maxFrameHeight,
+ maxHFRFrameWidth, maxHFRFrameHeight,
+ maxHFRMode);
return cap;
}
@@ -170,7 +177,9 @@ static bool isCamcorderQualityKnown(int quality)
(quality >= CAMCORDER_QUALITY_TIME_LAPSE_LIST_START &&
quality <= CAMCORDER_QUALITY_TIME_LAPSE_LIST_END) ||
(quality >= CAMCORDER_QUALITY_HIGH_SPEED_LIST_START &&
- quality <= CAMCORDER_QUALITY_HIGH_SPEED_LIST_END));
+ quality <= CAMCORDER_QUALITY_HIGH_SPEED_LIST_END) ||
+ (quality >= CAMCORDER_QUALITY_VENDOR_START &&
+ quality <= CAMCORDER_QUALITY_VENDOR_END));
}
static jobject
diff --git a/media/jni/android_media_MediaRecorder.cpp b/media/jni/android_media_MediaRecorder.cpp
index f60af63..69da951 100644
--- a/media/jni/android_media_MediaRecorder.cpp
+++ b/media/jni/android_media_MediaRecorder.cpp
@@ -40,6 +40,7 @@
#include <system/audio.h>
#include <android_runtime/android_view_Surface.h>
+#include "SeempLog.h"
// ----------------------------------------------------------------------------
@@ -219,7 +220,9 @@ static void
android_media_MediaRecorder_setVideoEncoder(JNIEnv *env, jobject thiz, jint ve)
{
ALOGV("setVideoEncoder(%d)", ve);
- if (ve < VIDEO_ENCODER_DEFAULT || ve >= VIDEO_ENCODER_LIST_END) {
+ if (ve < VIDEO_ENCODER_DEFAULT ||
+ (ve >= VIDEO_ENCODER_LIST_END && ve <= VIDEO_ENCODER_LIST_VENDOR_START) ||
+ ve >= VIDEO_ENCODER_LIST_VENDOR_END) {
jniThrowException(env, "java/lang/IllegalArgumentException", "Invalid video encoder");
return;
}
@@ -391,6 +394,14 @@ android_media_MediaRecorder_start(JNIEnv *env, jobject thiz)
}
static void
+android_media_MediaRecorder_pause(JNIEnv *env, jobject thiz)
+{
+ ALOGV("pause");
+ sp<MediaRecorder> mr = getMediaRecorder(env, thiz);
+ process_media_recorder_call(env, mr->pause(), "java/lang/RuntimeException", "pause failed.");
+}
+
+static void
android_media_MediaRecorder_stop(JNIEnv *env, jobject thiz)
{
ALOGV("stop");
@@ -527,6 +538,7 @@ static JNINativeMethod gMethods[] = {
{"getSurface", "()Landroid/view/Surface;", (void *)android_media_MediaRecorder_getSurface},
{"getMaxAmplitude", "()I", (void *)android_media_MediaRecorder_native_getMaxAmplitude},
{"start", "()V", (void *)android_media_MediaRecorder_start},
+ {"pause", "()V", (void *)android_media_MediaRecorder_pause},
{"stop", "()V", (void *)android_media_MediaRecorder_stop},
{"native_reset", "()V", (void *)android_media_MediaRecorder_native_reset},
{"release", "()V", (void *)android_media_MediaRecorder_release},
diff --git a/media/jni/android_mtp_MtpServer.cpp b/media/jni/android_mtp_MtpServer.cpp
index 2ce2a90..b481b46 100644
--- a/media/jni/android_mtp_MtpServer.cpp
+++ b/media/jni/android_mtp_MtpServer.cpp
@@ -130,6 +130,18 @@ android_mtp_MtpServer_send_device_property_changed(JNIEnv *env, jobject thiz, ji
}
static void
+android_mtp_MtpServer_send_object_updated(JNIEnv *env, jobject thiz, jint handle)
+{
+ Mutex::Autolock autoLock(sMutex);
+
+ MtpServer* server = getMtpServer(env, thiz);
+ if (server)
+ server->sendObjectUpdated(handle);
+ else
+ ALOGE("server is null in send_object_updated");
+}
+
+static void
android_mtp_MtpServer_add_storage(JNIEnv *env, jobject thiz, jobject jstorage)
{
Mutex::Autolock autoLock(sMutex);
@@ -188,6 +200,7 @@ static JNINativeMethod gMethods[] = {
{"native_send_object_removed", "(I)V", (void *)android_mtp_MtpServer_send_object_removed},
{"native_send_device_property_changed", "(I)V",
(void *)android_mtp_MtpServer_send_device_property_changed},
+ {"native_send_object_updated", "(I)V", (void *)android_mtp_MtpServer_send_object_updated},
{"native_add_storage", "(Landroid/mtp/MtpStorage;)V",
(void *)android_mtp_MtpServer_add_storage},
{"native_remove_storage", "(I)V", (void *)android_mtp_MtpServer_remove_storage},
diff --git a/media/jni/audioeffect/android_media_AudioEffect.cpp b/media/jni/audioeffect/android_media_AudioEffect.cpp
index aba4bbe..c392034 100644
--- a/media/jni/audioeffect/android_media_AudioEffect.cpp
+++ b/media/jni/audioeffect/android_media_AudioEffect.cpp
@@ -162,6 +162,15 @@ static void effectCallback(int event, void* user, void *info) {
ALOGV("EVENT_PARAMETER_CHANGED");
break;
case AudioEffect::EVENT_ERROR:
+ if (info == 0) {
+ ALOGW("EVENT_ERROR info == NULL");
+ goto effectCallback_Exit;
+ }
+ status_t status = *(status_t *)info;
+ if (status == DEAD_OBJECT) {
+ ALOGE("effectCallback: Client died, no need to send callback");
+ goto effectCallback_Exit;
+ }
ALOGW("EVENT_ERROR");
break;
}
diff --git a/media/jni/audioeffect/android_media_Visualizer.cpp b/media/jni/audioeffect/android_media_Visualizer.cpp
index 0557019..10df3ae 100644
--- a/media/jni/audioeffect/android_media_Visualizer.cpp
+++ b/media/jni/audioeffect/android_media_Visualizer.cpp
@@ -248,6 +248,7 @@ static sp<Visualizer> setVisualizer(JNIEnv* env, jobject thiz,
v->incStrong((void*)setVisualizer);
}
if (old != 0) {
+ old->cancelCaptureCallBack();
old->decStrong((void*)setVisualizer);
}
env->SetLongField(thiz, fields.fidNativeVisualizer, (jlong)v.get());
diff --git a/obex/javax/obex/ClientOperation.java b/obex/javax/obex/ClientOperation.java
index 883c8c6..afa9dab 100644
--- a/obex/javax/obex/ClientOperation.java
+++ b/obex/javax/obex/ClientOperation.java
@@ -52,7 +52,7 @@ public final class ClientOperation implements Operation, BaseStream {
private static final String TAG = "ClientOperation";
- private static final boolean V = ObexHelper.VDBG;
+ private static final boolean V = Log.isLoggable(ObexHelper.LOG_TAG, Log.VERBOSE);
private ClientSession mParent;
@@ -632,21 +632,32 @@ public final class ClientOperation implements Operation, BaseStream {
if (mGetOperation) {
if (!mOperationDone) {
- mReplyHeader.responseCode = ResponseCodes.OBEX_HTTP_CONTINUE;
- while ((more) && (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE)) {
- more = sendRequest(ObexHelper.OBEX_OPCODE_GET);
- }
- // For GET we need to loop until all headers have been sent,
- // And then we wait for the first continue package with the
- // reply.
- if (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE) {
- mParent.sendRequest(ObexHelper.OBEX_OPCODE_GET_FINAL,
- null, mReplyHeader, mPrivateInput, mSrmActive);
- }
- if (mReplyHeader.responseCode != ResponseCodes.OBEX_HTTP_CONTINUE) {
- mOperationDone = true;
+ if (!mGetFinalFlag) {
+ mReplyHeader.responseCode = ResponseCodes.OBEX_HTTP_CONTINUE;
+ while ((more) && (mReplyHeader.responseCode ==
+ ResponseCodes.OBEX_HTTP_CONTINUE)) {
+ more = sendRequest(ObexHelper.OBEX_OPCODE_GET);
+ }
+ // For GET we need to loop until all headers have been sent,
+ // And then we wait for the first continue package with the
+ // reply.
+ if (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE) {
+ mParent.sendRequest(ObexHelper.OBEX_OPCODE_GET_FINAL,
+ null, mReplyHeader, mPrivateInput, mSrmActive);
+ }
+ if (mReplyHeader.responseCode != ResponseCodes.OBEX_HTTP_CONTINUE) {
+ mOperationDone = true;
+ } else {
+ checkForSrm();
+ }
} else {
- checkForSrm();
+ more = sendRequest(ObexHelper.OBEX_OPCODE_GET_FINAL);
+
+ if (more) {
+ throw new IOException("FINAL_GET forced, data didn't fit into one packet");
+ }
+
+ mOperationDone = true;
}
}
} else {
@@ -705,7 +716,15 @@ public final class ClientOperation implements Operation, BaseStream {
if (mPrivateInput == null) {
mPrivateInput = new PrivateInputStream(this);
}
- sendRequest(ObexHelper.OBEX_OPCODE_GET);
+
+ if (!mGetFinalFlag) {
+ sendRequest(ObexHelper.OBEX_OPCODE_GET);
+ } else {
+ sendRequest(ObexHelper.OBEX_OPCODE_GET_FINAL);
+ }
+ if (mReplyHeader.responseCode != ResponseCodes.OBEX_HTTP_CONTINUE) {
+ mOperationDone = true;
+ }
return true;
} else if (mOperationDone) {
diff --git a/obex/javax/obex/ClientSession.java b/obex/javax/obex/ClientSession.java
index 272a920..f360944 100644
--- a/obex/javax/obex/ClientSession.java
+++ b/obex/javax/obex/ClientSession.java
@@ -48,6 +48,7 @@ import android.util.Log;
public final class ClientSession extends ObexSession {
private static final String TAG = "ClientSession";
+ private static final boolean V = Log.isLoggable(ObexHelper.LOG_TAG, Log.VERBOSE);
private boolean mOpen;
@@ -68,7 +69,7 @@ public final class ClientSession extends ObexSession {
private final OutputStream mOutput;
- private final boolean mLocalSrmSupported;
+ private boolean mLocalSrmSupported;
private final ObexTransport mTransport;
@@ -613,4 +614,9 @@ public final class ClientSession extends ObexSession {
public boolean isSrmSupported() {
return mLocalSrmSupported;
}
+
+ public void setLocalSrmStatus(boolean SrmEnabled) {
+ mLocalSrmSupported = SrmEnabled;
+ if (V) Log.v(TAG, "setLocalSrmStatus: " + mLocalSrmSupported);
+ }
}
diff --git a/obex/javax/obex/ObexHelper.java b/obex/javax/obex/ObexHelper.java
index fa50943..431525e 100644
--- a/obex/javax/obex/ObexHelper.java
+++ b/obex/javax/obex/ObexHelper.java
@@ -52,7 +52,8 @@ import android.util.Log;
public final class ObexHelper {
private static final String TAG = "ObexHelper";
- public static final boolean VDBG = false;
+ public static final String LOG_TAG = "BluetoothObex";
+ public static final boolean VDBG = Log.isLoggable(LOG_TAG, Log.VERBOSE);
/**
* Defines the basic packet length used by OBEX. Every OBEX packet has the
* same basic format:<BR>
@@ -190,6 +191,7 @@ public final class ObexHelper {
try {
while (index < headerArray.length) {
headerID = 0xFF & headerArray[index];
+ if (VDBG) Log.v(TAG,"updateHeaderSet headerID = " + headerID);
switch (headerID & (0xC0)) {
/*
@@ -375,8 +377,9 @@ public final class ObexHelper {
* Determine if there is a connection ID to send. If there is,
* then it should be the first header in the packet.
*/
+ if (VDBG) Log.v(TAG,"createHeader = " + head);
if ((headImpl.mConnectionID != null) && (headImpl.getHeader(HeaderSet.TARGET) == null)) {
-
+ if (VDBG) Log.v(TAG," Add Header = " + HeaderSet.CONNECTION_ID);
out.write((byte)HeaderSet.CONNECTION_ID);
out.write(headImpl.mConnectionID);
}
@@ -384,6 +387,7 @@ public final class ObexHelper {
// Count Header
intHeader = (Long)headImpl.getHeader(HeaderSet.COUNT);
if (intHeader != null) {
+ if (VDBG) Log.v(TAG," Add Header = " + HeaderSet.COUNT);
out.write((byte)HeaderSet.COUNT);
value = ObexHelper.convertToByteArray(intHeader.longValue());
out.write(value);
@@ -395,6 +399,7 @@ public final class ObexHelper {
// Name Header
stringHeader = (String)headImpl.getHeader(HeaderSet.NAME);
if (stringHeader != null) {
+ if (VDBG) Log.v(TAG," Add Header = " + HeaderSet.NAME);
out.write((byte)HeaderSet.NAME);
value = ObexHelper.convertToUnicodeByteArray(stringHeader);
length = value.length + 3;
@@ -415,6 +420,7 @@ public final class ObexHelper {
// Type Header
stringHeader = (String)headImpl.getHeader(HeaderSet.TYPE);
if (stringHeader != null) {
+ if (VDBG) Log.v(TAG," Add Header = " + HeaderSet.TYPE);
out.write((byte)HeaderSet.TYPE);
try {
value = stringHeader.getBytes("ISO8859_1");
@@ -436,6 +442,7 @@ public final class ObexHelper {
// Length Header
intHeader = (Long)headImpl.getHeader(HeaderSet.LENGTH);
if (intHeader != null) {
+ if (VDBG) Log.v(TAG," Add Header = " + HeaderSet.LENGTH);
out.write((byte)HeaderSet.LENGTH);
value = ObexHelper.convertToByteArray(intHeader.longValue());
out.write(value);
@@ -447,7 +454,7 @@ public final class ObexHelper {
// Time ISO Header
dateHeader = (Calendar)headImpl.getHeader(HeaderSet.TIME_ISO_8601);
if (dateHeader != null) {
-
+ if (VDBG) Log.v(TAG," Add dateHeader = " + HeaderSet.TIME_ISO_8601);
/*
* The ISO Header should take the form YYYYMMDDTHHMMSSZ. The
* 'Z' will only be included if it is a UTC time.
@@ -509,6 +516,7 @@ public final class ObexHelper {
// Time 4 Byte Header
dateHeader = (Calendar)headImpl.getHeader(HeaderSet.TIME_4_BYTE);
if (dateHeader != null) {
+ if (VDBG) Log.v(TAG," Add dateHeader = " + HeaderSet.TIME_4_BYTE);
out.write(HeaderSet.TIME_4_BYTE);
/*
@@ -543,6 +551,7 @@ public final class ObexHelper {
// Target Header
value = (byte[])headImpl.getHeader(HeaderSet.TARGET);
if (value != null) {
+ if (VDBG) Log.v(TAG," Add Header = " + HeaderSet.TARGET);
out.write((byte)HeaderSet.TARGET);
length = value.length + 3;
lengthArray[0] = (byte)(255 & (length >> 8));
@@ -571,6 +580,7 @@ public final class ObexHelper {
// Who Header
value = (byte[])headImpl.getHeader(HeaderSet.WHO);
if (value != null) {
+ if (VDBG) Log.v(TAG," Add Header = " + HeaderSet.WHO);
out.write((byte)HeaderSet.WHO);
length = value.length + 3;
lengthArray[0] = (byte)(255 & (length >> 8));
@@ -582,9 +592,10 @@ public final class ObexHelper {
}
}
- // Connection ID Header
+ // Application Parameter Header
value = (byte[])headImpl.getHeader(HeaderSet.APPLICATION_PARAMETER);
if (value != null) {
+ if (VDBG) Log.v(TAG," Add APP PARAM Header = " + HeaderSet.APPLICATION_PARAMETER);
out.write((byte)HeaderSet.APPLICATION_PARAMETER);
length = value.length + 3;
lengthArray[0] = (byte)(255 & (length >> 8));
@@ -623,6 +634,7 @@ public final class ObexHelper {
lengthArray[1] = (byte)(255 & length);
out.write(lengthArray);
out.write(value);
+ if (VDBG) Log.v(TAG," Add Unicode String value = " + value);
if (nullOut) {
headImpl.setHeader(i + 0x30, null);
}
@@ -637,6 +649,7 @@ public final class ObexHelper {
lengthArray[1] = (byte)(255 & length);
out.write(lengthArray);
out.write(value);
+ if (VDBG) Log.v(TAG," Add ByteSeq value = " + value);
if (nullOut) {
headImpl.setHeader(i + 0x70, null);
}
@@ -647,6 +660,7 @@ public final class ObexHelper {
if (byteHeader != null) {
out.write((byte)i + 0xB0);
out.write(byteHeader.byteValue());
+ if (VDBG) Log.v(TAG," Add ByteHeader value = " + byteHeader.byteValue());
if (nullOut) {
headImpl.setHeader(i + 0xB0, null);
}
@@ -657,6 +671,7 @@ public final class ObexHelper {
if (intHeader != null) {
out.write((byte)i + 0xF0);
out.write(ObexHelper.convertToByteArray(intHeader.longValue()));
+ if (VDBG) Log.v(TAG," Add Int value = " + intHeader.longValue());
if (nullOut) {
headImpl.setHeader(i + 0xF0, null);
}
@@ -671,6 +686,7 @@ public final class ObexHelper {
lengthArray[1] = (byte)(255 & length);
out.write(lengthArray);
out.write(headImpl.mAuthChall);
+ if (VDBG) Log.v(TAG," Add mAuthChall value = " + headImpl.mAuthChall);
if (nullOut) {
headImpl.mAuthChall = null;
}
@@ -684,6 +700,7 @@ public final class ObexHelper {
lengthArray[1] = (byte)(255 & length);
out.write(lengthArray);
out.write(headImpl.mAuthResp);
+ if (VDBG) Log.v(TAG," Add mAuthChall value = " + headImpl.mAuthResp);
if (nullOut) {
headImpl.mAuthResp = null;
}
@@ -699,8 +716,10 @@ public final class ObexHelper {
// Add the SRM header
byteHeader = (Byte)headImpl.getHeader(HeaderSet.SINGLE_RESPONSE_MODE);
if (byteHeader != null) {
+ if (VDBG) Log.v(TAG," Add SRM Header = " + HeaderSet.SINGLE_RESPONSE_MODE);
out.write((byte)HeaderSet.SINGLE_RESPONSE_MODE);
out.write(byteHeader.byteValue());
+ if (VDBG) Log.v(TAG," Add SRM value = " + byteHeader.byteValue());
if (nullOut) {
headImpl.setHeader(HeaderSet.SINGLE_RESPONSE_MODE, null);
}
@@ -709,6 +728,7 @@ public final class ObexHelper {
// Add the SRM parameter header
byteHeader = (Byte)headImpl.getHeader(HeaderSet.SINGLE_RESPONSE_MODE_PARAMETER);
if (byteHeader != null) {
+ if (VDBG) Log.v(TAG," Add Header = " + HeaderSet.SINGLE_RESPONSE_MODE_PARAMETER);
out.write((byte)HeaderSet.SINGLE_RESPONSE_MODE_PARAMETER);
out.write(byteHeader.byteValue());
if (nullOut) {
diff --git a/obex/javax/obex/ObexSession.java b/obex/javax/obex/ObexSession.java
index 542b9c8..f5e607c 100644
--- a/obex/javax/obex/ObexSession.java
+++ b/obex/javax/obex/ObexSession.java
@@ -50,7 +50,7 @@ import android.util.Log;
public class ObexSession {
private static final String TAG = "ObexSession";
- private static final boolean V = ObexHelper.VDBG;
+ private static final boolean V = Log.isLoggable(ObexHelper.LOG_TAG, Log.VERBOSE);
protected Authenticator mAuthenticator;
diff --git a/obex/javax/obex/ServerOperation.java b/obex/javax/obex/ServerOperation.java
index 56a675a..87943bf 100644
--- a/obex/javax/obex/ServerOperation.java
+++ b/obex/javax/obex/ServerOperation.java
@@ -59,7 +59,7 @@ public final class ServerOperation implements Operation, BaseStream {
private static final String TAG = "ServerOperation";
- private static final boolean V = ObexHelper.VDBG; // Verbose debugging
+ private static final boolean V = Log.isLoggable(ObexHelper.LOG_TAG, Log.VERBOSE);
public boolean isAborted;
@@ -124,6 +124,7 @@ public final class ServerOperation implements Operation, BaseStream {
*/
public ServerOperation(ServerSession p, InputStream in, int request, int maxSize,
ServerRequestHandler listen) throws IOException {
+ if (V) Log.v(TAG, "ServerOperation");
isAborted = false;
mParent = p;
@@ -195,7 +196,12 @@ public final class ServerOperation implements Operation, BaseStream {
if(!handleObexPacket(packet)) {
return;
}
- if (!mHasBody) {
+ /* Don't Pre-Send continue when Remote requested for SRM
+ * Let the Application confirm.
+ */
+ if(V) Log.v(TAG, "Get App confirmation if SRM ENABLED case: " + mSrmEnabled
+ + " not hasBody case: " + mHasBody);
+ if (!mHasBody && !mSrmEnabled) {
while ((!mGetOperation) && (!finalBitSet)) {
sendReply(ResponseCodes.OBEX_HTTP_CONTINUE);
if (mPrivateInput.available() > 0) {
@@ -204,8 +210,13 @@ public final class ServerOperation implements Operation, BaseStream {
}
}
}
-
- while ((!mGetOperation) && (!finalBitSet) && (mPrivateInput.available() == 0)) {
+ /* Don't Pre-Send continue when Remote requested for SRM
+ * Let the Application confirm.
+ */
+ if(V) Log.v(TAG, "Get App confirmation if SRM ENABLED case: " + mSrmEnabled
+ + " not finalPacket: " + finalBitSet + " not GETOp Case: " + mGetOperation);
+ while ((!mSrmEnabled) && (!mGetOperation) && (!finalBitSet)
+ && (mPrivateInput.available() == 0)) {
sendReply(ResponseCodes.OBEX_HTTP_CONTINUE);
if (mPrivateInput.available() > 0) {
break;
@@ -330,14 +341,17 @@ public final class ServerOperation implements Operation, BaseStream {
*/
public synchronized boolean continueOperation(boolean sendEmpty, boolean inStream)
throws IOException {
+ if (V) Log.v(TAG, "continueOperation");
if (!mGetOperation) {
if (!finalBitSet) {
if (sendEmpty) {
sendReply(ResponseCodes.OBEX_HTTP_CONTINUE);
+ if (V) Log.v(TAG, "continueOperation:ServerSet SRM sendEmpty clause");
return true;
} else {
if ((mResponseSize > 3) || (mPrivateOutput.size() > 0)) {
sendReply(ResponseCodes.OBEX_HTTP_CONTINUE);
+ if (V) Log.v(TAG, "continueOperation: Server setting SRM");
return true;
} else {
return false;
@@ -347,6 +361,7 @@ public final class ServerOperation implements Operation, BaseStream {
return false;
}
} else {
+ if (V) Log.v(TAG, "Get continueOperation ");
sendReply(ResponseCodes.OBEX_HTTP_CONTINUE);
return true;
}
@@ -395,6 +410,8 @@ public final class ServerOperation implements Operation, BaseStream {
bodyLength = mPrivateOutput.size();
orginalBodyLength = bodyLength;
}
+ if(V)Log.v(TAG, "mMaxPcKLen : " + mMaxPacketLength);
+ if(V)Log.v(TAG, "headerArryLen : " + headerArray.length);
if ((ObexHelper.BASE_PACKET_LENGTH + headerArray.length) > mMaxPacketLength) {
diff --git a/obex/javax/obex/ServerSession.java b/obex/javax/obex/ServerSession.java
index acee5dd..34a75f4 100644
--- a/obex/javax/obex/ServerSession.java
+++ b/obex/javax/obex/ServerSession.java
@@ -47,7 +47,7 @@ import java.io.OutputStream;
public final class ServerSession extends ObexSession implements Runnable {
private static final String TAG = "Obex ServerSession";
- private static final boolean V = ObexHelper.VDBG;
+ private static final boolean V = Log.isLoggable(ObexHelper.LOG_TAG, Log.VERBOSE);
private ObexTransport mTransport;
@@ -175,7 +175,7 @@ public final class ServerSession extends ObexSession implements Runnable {
mInput.read();
}
code = mListener.onAbort(request, reply);
- Log.v(TAG, "onAbort request handler return value- " + code);
+ Log.d(TAG, "onAbort request handler return value- " + code);
code = validateResponseCode(code);
}
sendResponse(code, null);
@@ -195,6 +195,7 @@ public final class ServerSession extends ObexSession implements Runnable {
* @throws IOException if an error occurred at the transport layer
*/
private void handlePutRequest(int type) throws IOException {
+ if (V) Log.v(TAG, "handlePutRequest");
ServerOperation op = new ServerOperation(this, mInput, type, mMaxPacketLength, mListener);
try {
int response = -1;
@@ -206,10 +207,12 @@ public final class ServerSession extends ObexSession implements Runnable {
response = validateResponseCode(mListener.onPut(op));
}
if (response != ResponseCodes.OBEX_HTTP_OK && !op.isAborted) {
+ if (V) Log.v(TAG, "handlePutRequest pre != HTTP_OK sendReply");
op.sendReply(response);
} else if (!op.isAborted) {
// wait for the final bit
while (!op.finalBitSet) {
+ if (V) Log.v(TAG, "handlePutRequest pre looped sendReply");
op.sendReply(ResponseCodes.OBEX_HTTP_CONTINUE);
}
op.sendReply(response);
@@ -220,7 +223,7 @@ public final class ServerSession extends ObexSession implements Runnable {
*internal error should not be sent because server has already replied with
*OK response in "sendReply")
*/
- if(V) Log.d(TAG,"Exception occured - sending OBEX_HTTP_INTERNAL_ERROR reply",e);
+ if(V) Log.w(TAG,"Exception occured - sending OBEX_HTTP_INTERNAL_ERROR reply",e);
if (!op.isAborted) {
sendResponse(ResponseCodes.OBEX_HTTP_INTERNAL_ERROR, null);
}
@@ -241,6 +244,7 @@ public final class ServerSession extends ObexSession implements Runnable {
* @throws IOException if an error occurred at the transport layer
*/
private void handleGetRequest(int type) throws IOException {
+ if (V) Log.v(TAG, "handleGetRequest");
ServerOperation op = new ServerOperation(this, mInput, type, mMaxPacketLength, mListener);
try {
int response = validateResponseCode(mListener.onGet(op));
@@ -263,6 +267,7 @@ public final class ServerSession extends ObexSession implements Runnable {
public void sendResponse(int code, byte[] header) throws IOException {
int totalLength = 3;
byte[] data = null;
+ if (V) Log.v(TAG,"sendResponse code " + code + " header : " + header);
OutputStream op = mOutput;
if (op == null) {
return;
@@ -270,6 +275,7 @@ public final class ServerSession extends ObexSession implements Runnable {
if (header != null) {
totalLength += header.length;
+ if (V) Log.v(TAG, "header != null totalLength = " + totalLength);
data = new byte[totalLength];
data[0] = (byte)code;
data[1] = (byte)(totalLength >> 8);
@@ -658,6 +664,12 @@ public final class ServerSession extends ObexSession implements Runnable {
*/
byte[] sendData = new byte[totalLength];
int maxRxLength = ObexHelper.getMaxRxPacketSize(mTransport);
+ //PTS expects least of maxPacketLen
+ if(maxRxLength > mMaxPacketLength) {
+ if(V) Log.v(TAG,"Set maxRxLength to min of maxRxServrLen:" + maxRxLength +
+ " and MaxNegotiated from Client: " + mMaxPacketLength);
+ maxRxLength = mMaxPacketLength;
+ }
sendData[0] = (byte)code;
sendData[1] = length[2];
sendData[2] = length[3];
diff --git a/packages/CaptivePortalLogin/AndroidManifest.xml b/packages/CaptivePortalLogin/AndroidManifest.xml
index aea8585..2e73119 100644
--- a/packages/CaptivePortalLogin/AndroidManifest.xml
+++ b/packages/CaptivePortalLogin/AndroidManifest.xml
@@ -32,6 +32,10 @@
<action android:name="android.net.conn.CAPTIVE_PORTAL"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
+ <intent-filter>
+ <action android:name="android.net.action.captive_portal_login"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ </intent-filter>
</activity>
</application>
</manifest>
diff --git a/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java b/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
index 0fe5509..ed95bff 100644
--- a/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
+++ b/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
@@ -20,8 +20,10 @@ import android.app.Activity;
import android.app.LoadedApk;
import android.content.Context;
import android.content.Intent;
+import android.content.res.ColorStateList;
import android.graphics.Bitmap;
import android.net.CaptivePortal;
+import android.graphics.drawable.ColorDrawable;
import android.net.ConnectivityManager;
import android.net.ConnectivityManager.NetworkCallback;
import android.net.Network;
@@ -32,6 +34,7 @@ import android.net.Uri;
import android.net.http.SslError;
import android.os.Bundle;
import android.provider.Settings;
+import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.Log;
import android.util.TypedValue;
@@ -57,6 +60,11 @@ import java.util.Random;
public class CaptivePortalLoginActivity extends Activity {
private static final String TAG = "CaptivePortalLogin";
private static final String DEFAULT_SERVER = "connectivitycheck.gstatic.com";
+
+ private static final String EXTRA_STATUS_BAR_COLOR = "status_bar_color";
+ private static final String EXTRA_ACTION_BAR_COLOR = "action_bar_color";
+ private static final String EXTRA_PROGRESS_COLOR = "progress_bar_color";
+
private static final int SOCKET_TIMEOUT_MS = 10000;
private enum Result { DISMISSED, UNWANTED, WANTED_AS_IS };
@@ -81,11 +89,26 @@ public class CaptivePortalLoginActivity extends Activity {
} catch (MalformedURLException e) {
// System misconfigured, bail out in a way that at least provides network access.
Log.e(TAG, "Invalid captive portal URL, server=" + server);
+ setResult(Activity.RESULT_CANCELED);
done(Result.WANTED_AS_IS);
}
mNetwork = getIntent().getParcelableExtra(ConnectivityManager.EXTRA_NETWORK);
mCaptivePortal = getIntent().getParcelableExtra(ConnectivityManager.EXTRA_CAPTIVE_PORTAL);
+ final Intent intent = getIntent();
+ if (intent.hasExtra(EXTRA_STATUS_BAR_COLOR)) {
+ int color = intent.getIntExtra(EXTRA_STATUS_BAR_COLOR, -1);
+ if (color != -1) {
+ getWindow().setStatusBarColor(color);
+ }
+ }
+ if (intent.hasExtra(EXTRA_ACTION_BAR_COLOR)) {
+ int color = intent.getIntExtra(EXTRA_ACTION_BAR_COLOR, -1);
+ if (color != -1) {
+ getActionBar().setBackgroundDrawable(new ColorDrawable(color));
+ }
+ }
+
// Also initializes proxy system properties.
mCm.bindProcessToNetwork(mNetwork);
@@ -95,6 +118,14 @@ public class CaptivePortalLoginActivity extends Activity {
getActionBar().setDisplayShowHomeEnabled(false);
+ ProgressBar myProgressBar = (ProgressBar) findViewById(R.id.progress_bar);
+ if (intent.hasExtra(EXTRA_PROGRESS_COLOR)) {
+ int color = intent.getIntExtra(EXTRA_PROGRESS_COLOR, -1);
+ if (color != -1) {
+ myProgressBar.setProgressTintList(ColorStateList.valueOf(color));
+ }
+ }
+
// Exit app if Network disappears.
final NetworkCapabilities networkCapabilities = mCm.getNetworkCapabilities(mNetwork);
if (networkCapabilities == null) {
@@ -165,6 +196,7 @@ public class CaptivePortalLoginActivity extends Activity {
mCaptivePortal.useNetwork();
break;
}
+ setResult(Activity.RESULT_OK);
finish();
}
@@ -298,6 +330,11 @@ public class CaptivePortalLoginActivity extends Activity {
} else if (mPagesLoaded == 2) {
// Prevent going back to empty first page.
view.clearHistory();
+ } else {
+ if (TextUtils.isEmpty(view.getUrl()) || view.getUrl().contains("text/html")) {
+ setResult(Activity.RESULT_CANCELED);
+ finish();
+ }
}
testForCaptivePortal();
}
diff --git a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
index cc1e01a..055da3e 100644
--- a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
+++ b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
@@ -189,6 +189,7 @@ public class DefaultContainerService extends IntentService {
ret.recommendedInstallLocation = PackageHelper.resolveInstallLocation(context,
pkg.packageName, pkg.installLocation, sizeBytes, flags);
ret.multiArch = pkg.multiArch;
+ ret.isTheme = pkg.isTheme;
return ret;
}
diff --git a/packages/DocumentsUI/res/layout/activity.xml b/packages/DocumentsUI/res/layout/activity.xml
index 32431e3..3de76d0 100644
--- a/packages/DocumentsUI/res/layout/activity.xml
+++ b/packages/DocumentsUI/res/layout/activity.xml
@@ -63,7 +63,7 @@
android:layout_gravity="start"
android:orientation="vertical"
android:elevation="16dp"
- android:background="@*android:color/white">
+ android:background="@color/drawer_background_color">
<Toolbar
android:id="@+id/roots_toolbar"
diff --git a/packages/DocumentsUI/res/layout/item_doc_grid.xml b/packages/DocumentsUI/res/layout/item_doc_grid.xml
index d62d050..90938ae 100644
--- a/packages/DocumentsUI/res/layout/item_doc_grid.xml
+++ b/packages/DocumentsUI/res/layout/item_doc_grid.xml
@@ -66,7 +66,7 @@
android:ellipsize="middle"
android:textAlignment="viewStart"
android:textAppearance="@android:style/TextAppearance.Material.Subhead"
- android:textColor="@*android:color/primary_text_default_material_dark" />
+ android:textColor="@color/font_color_doc_grid" />
<ImageView
android:id="@android:id/icon1"
@@ -95,7 +95,7 @@
android:ellipsize="end"
android:textAlignment="viewStart"
android:textAppearance="@android:style/TextAppearance.Material.Caption"
- android:textColor="@*android:color/primary_text_default_material_dark" />
+ android:textColor="@color/font_color_doc_grid" />
<TextView
android:id="@+id/size"
@@ -107,7 +107,7 @@
android:ellipsize="end"
android:textAlignment="viewStart"
android:textAppearance="@android:style/TextAppearance.Material.Caption"
- android:textColor="@*android:color/primary_text_default_material_dark" />
+ android:textColor="@color/font_color_doc_grid" />
<ImageView
android:id="@android:id/icon2"
diff --git a/packages/DocumentsUI/res/values/cm_colors.xml b/packages/DocumentsUI/res/values/cm_colors.xml
new file mode 100644
index 0000000..1fa1a80
--- /dev/null
+++ b/packages/DocumentsUI/res/values/cm_colors.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2015 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.
+-->
+<resources>
+
+ <!-- adding new exposed theme components -->
+ <color name="drawer_background_color">#ffffffff</color>
+ <color name="font_color_doc_grid">#ffffffff</color>
+
+</resources>
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
index 0d326ec..9a86c8e 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
@@ -530,8 +530,10 @@ public class DirectoryFragment extends Fragment {
for (int i = 0; i < size; i++) {
if (checked.valueAt(i)) {
final Cursor cursor = mAdapter.getItem(checked.keyAt(i));
- final DocumentInfo doc = DocumentInfo.fromDirectoryCursor(cursor);
- docs.add(doc);
+ if (cursor != null) {
+ final DocumentInfo doc = DocumentInfo.fromDirectoryCursor(cursor);
+ docs.add(doc);
+ }
}
}
diff --git a/packages/Keyguard/Android.mk b/packages/Keyguard/Android.mk
index 9083212..ad33536f 100644
--- a/packages/Keyguard/Android.mk
+++ b/packages/Keyguard/Android.mk
@@ -18,6 +18,8 @@ include $(CLEAR_VARS)
LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-subdir-Iaidl-files)
+LOCAL_STATIC_JAVA_LIBRARIES := org.cyanogenmod.platform.sdk
+
LOCAL_MODULE := Keyguard
LOCAL_CERTIFICATE := platform
diff --git a/packages/Keyguard/res/values/strings.xml b/packages/Keyguard/res/values/strings.xml
index d1e84f5..5270831 100644
--- a/packages/Keyguard/res/values/strings.xml
+++ b/packages/Keyguard/res/values/strings.xml
@@ -48,6 +48,9 @@
to unlock the keyguard. Displayed in one line in a large font. -->
<string name="keyguard_password_wrong_pin_code">Incorrect PIN code.</string>
+ <!-- Shown in the lock screen when there is SIM card IO error. -->
+ <string name="lockscreen_sim_error_message_short">Invalid Card.</string>
+
<!-- When the lock screen is showing, the phone is plugged in and the battery is fully
charged, say that it is charged. -->
<string name="keyguard_charged">Charged</string>
@@ -74,6 +77,8 @@
<!-- SIM messages --><skip />
<!-- When the user inserts a sim card from an unsupported network, it becomes network locked -->
<string name="keyguard_network_locked_message">Network locked</string>
+ <!-- When the user inserts a sim card with some personalization enabled -->
+ <string name="keyguard_perso_locked_message">SIM card is Perso locked</string>
<!-- Shown when there is no SIM card. -->
<string name="keyguard_missing_sim_message_short">No SIM card</string>
<!-- Shown when there is no SIM card. -->
@@ -355,4 +360,10 @@
<!-- Fingerprint hint message when finger was not recognized.-->
<string name="fingerprint_not_recognized">Not recognized</string>
+ <!-- Instructions telling the user remaining times when enter SIM PIN view. -->
+ <plurals name="kg_password_default_pin_message">
+ <item quantity="one">Enter SIM PIN, you have <xliff:g id="number">%d</xliff:g> remaining attempt before you must contact your carrier to unlock your device.</item>
+ <item quantity="other">Enter SIM PIN, you have <xliff:g id="number">%d</xliff:g> remaining attempts.</item>
+ </plurals>
+
</resources>
diff --git a/packages/Keyguard/src/com/android/keyguard/CarrierText.java b/packages/Keyguard/src/com/android/keyguard/CarrierText.java
index 159ac4c..230ad42 100644
--- a/packages/Keyguard/src/com/android/keyguard/CarrierText.java
+++ b/packages/Keyguard/src/com/android/keyguard/CarrierText.java
@@ -28,6 +28,7 @@ import android.net.ConnectivityManager;
import android.net.wifi.WifiManager;
import android.telephony.ServiceState;
import android.telephony.SubscriptionInfo;
+import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.text.method.SingleLineTransformationMethod;
import android.util.AttributeSet;
@@ -39,6 +40,7 @@ import com.android.internal.telephony.IccCardConstants;
import com.android.internal.telephony.IccCardConstants.State;
import com.android.internal.telephony.TelephonyIntents;
import com.android.settingslib.WirelessUtils;
+import android.telephony.TelephonyManager;
public class CarrierText extends TextView {
private static final boolean DEBUG = KeyguardConstants.DEBUG;
@@ -52,6 +54,8 @@ public class CarrierText extends TextView {
private WifiManager mWifiManager;
+ private boolean[] mSimErrorState = new boolean[TelephonyManager.getDefault().getPhoneCount()];
+
private KeyguardUpdateMonitorCallback mCallback = new KeyguardUpdateMonitorCallback() {
@Override
public void onRefreshCarrierInfo() {
@@ -65,6 +69,22 @@ public class CarrierText extends TextView {
public void onStartedWakingUp() {
setSelected(true);
};
+
+ public void onSimStateChanged(int subId, int slotId, IccCardConstants.State simState) {
+ if (slotId < 0) {
+ Log.d(TAG, "onSimStateChanged() - slotId invalid: " + slotId);
+ return;
+ }
+
+ Log.d(TAG,"onSimStateChanged: " + getStatusForIccState(simState));
+ if (getStatusForIccState(simState) == StatusMode.SimIoError) {
+ mSimErrorState[slotId] = true;
+ updateCarrierText();
+ } else if (mSimErrorState[slotId]) {
+ mSimErrorState[slotId] = false;
+ updateCarrierText();
+ }
+ };
};
/**
* The status of this lock screen. Primarily used for widgets on LockScreen.
@@ -77,7 +97,8 @@ public class CarrierText extends TextView {
SimPukLocked, // SIM card is PUK locked because SIM entered wrong too many times
SimLocked, // SIM card is currently locked
SimPermDisabled, // SIM card is permanently disabled due to PUK unlock failure
- SimNotReady; // SIM is not ready yet. May never be on devices w/o a SIM.
+ SimNotReady, // SIM is not ready yet. May never be on devices w/o a SIM.
+ SimIoError; //The sim card is faulty
}
public CarrierText(Context context) {
@@ -101,18 +122,91 @@ public class CarrierText extends TextView {
mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
}
+ /**
+ * Checks if there are faulty cards. Adds the text depending on the slot of the card
+ * @param text: current carrier text based on the sim state
+ * @param noSims: whether a valid sim card is inserted
+ * @return text
+ */
+ private CharSequence updateCarrierTextWithSimIoError(CharSequence text, boolean noSims) {
+ final CharSequence carrier = "";
+ CharSequence carrierTextForSimState = getCarrierTextForSimState(
+ IccCardConstants.State.CARD_IO_ERROR, carrier);
+ for (int index = 0; index < mSimErrorState.length; index++) {
+ if (mSimErrorState[index]) {
+ // In the case when no sim cards are detected but a faulty card is inserted
+ // overwrite the text and only show "Invalid card"
+ if (noSims) {
+ return concatenate(carrierTextForSimState,
+ getContext().getText(com.android.internal.R.string.emergency_calls_only));
+ } else if (index == 0) {
+ // prepend "Invalid card" when faulty card is inserted in slot 0
+ text = concatenate(carrierTextForSimState, text);
+ } else {
+ // concatenate "Invalid card" when faulty card is inserted in slot 1
+ text = concatenate(text, carrierTextForSimState);
+ }
+ }
+ }
+ return text;
+ }
+
protected void updateCarrierText() {
boolean allSimsMissing = true;
boolean anySimReadyAndInService = false;
+ boolean showLocale = getContext().getResources().getBoolean(
+ com.android.internal.R.bool.config_monitor_locale_change);
+ boolean showRat = getContext().getResources().getBoolean(
+ com.android.internal.R.bool.config_display_rat);
CharSequence displayText = null;
List<SubscriptionInfo> subs = mKeyguardUpdateMonitor.getSubscriptionInfo(false);
final int N = subs.size();
if (DEBUG) Log.d(TAG, "updateCarrierText(): " + N);
for (int i = 0; i < N; i++) {
+ CharSequence networkClass = "";
int subId = subs.get(i).getSubscriptionId();
State simState = mKeyguardUpdateMonitor.getSimState(subId);
+ if (showRat) {
+ ServiceState ss = mKeyguardUpdateMonitor.mServiceStates.get(subId);
+ TelephonyManager tm = new TelephonyManager(getContext());
+ if (ss != null && (ss.getDataRegState() == ServiceState.STATE_IN_SERVICE
+ || ss.getVoiceRegState() == ServiceState.STATE_IN_SERVICE)) {
+ int networkType = TelephonyManager.NETWORK_TYPE_UNKNOWN;
+ if (ss.getRilDataRadioTechnology() !=
+ ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN) {
+ networkType = ss.getDataNetworkType();
+ } else if (ss.getRilVoiceRadioTechnology() !=
+ ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN) {
+ networkType = ss.getVoiceNetworkType();
+ }
+ networkClass = tm.networkClassToString(networkType);
+ }
+ }
CharSequence carrierName = subs.get(i).getCarrierName();
+ if (showLocale || showRat) {
+ String[] names = carrierName.toString().split(mSeparator.toString(), 2);
+ StringBuilder newCarrierName = new StringBuilder();
+ for (int j = 0; j < names.length; j++) {
+ if (showLocale) {
+ names[j] = android.util.NativeTextHelper.getLocalString(getContext(),
+ names[j], com.android.internal.R.array.origin_carrier_names,
+ com.android.internal.R.array.locale_carrier_names);
+ }
+ if (!TextUtils.isEmpty(names[j])) {
+ if (!TextUtils.isEmpty(networkClass) && showRat) {
+ names[j] = new StringBuilder().append(names[j]).append(" ")
+ .append(networkClass).toString();
+ }
+ if (j > 0 && names[j].equals(names[j-1])) {
+ continue;
+ }
+ if (j > 0) newCarrierName.append(mSeparator);
+ newCarrierName.append(names[j]);
+ }
+ }
+ carrierName = newCarrierName.toString();
+ }
CharSequence carrierTextForSimState = getCarrierTextForSimState(simState, carrierName);
if (DEBUG) {
Log.d(TAG, "Handling (subId=" + subId + "): " + simState + " " + carrierName);
@@ -179,6 +273,7 @@ public class CarrierText extends TextView {
}
}
+ displayText = updateCarrierTextWithSimIoError(displayText, allSimsMissing);
// APM (airplane mode) != no carrier state. There are carrier services
// (e.g. WFC = Wi-Fi calling) which may operate in APM.
if (!anySimReadyAndInService && WirelessUtils.isAirplaneModeOn(mContext)) {
@@ -243,7 +338,7 @@ public class CarrierText extends TextView {
case NetworkLocked:
carrierText = makeCarrierStringOnEmergencyCapable(
- mContext.getText(R.string.keyguard_network_locked_message), text);
+ getContext().getText(R.string.keyguard_perso_locked_message), text);
break;
case SimMissing:
@@ -270,6 +365,11 @@ public class CarrierText extends TextView {
getContext().getText(R.string.keyguard_sim_puk_locked_message),
text);
break;
+ case SimIoError:
+ carrierText = makeCarrierStringOnEmergencyCapable(
+ getContext().getText(R.string.lockscreen_sim_error_message_short),
+ text);
+ break;
}
return carrierText;
@@ -306,7 +406,7 @@ public class CarrierText extends TextView {
case ABSENT:
return StatusMode.SimMissing;
case NETWORK_LOCKED:
- return StatusMode.SimMissingLocked;
+ return StatusMode.NetworkLocked;
case NOT_READY:
return StatusMode.SimNotReady;
case PIN_REQUIRED:
@@ -319,6 +419,8 @@ public class CarrierText extends TextView {
return StatusMode.SimPermDisabled;
case UNKNOWN:
return StatusMode.SimMissing;
+ case CARD_IO_ERROR:
+ return StatusMode.SimIoError;
}
return StatusMode.SimMissing;
}
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardPINView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardPINView.java
index 4abb795..b909a60 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardPINView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardPINView.java
@@ -19,16 +19,25 @@ package com.android.keyguard;
import android.animation.Animator;
import android.animation.ObjectAnimator;
import android.content.Context;
+import android.provider.Settings;
import android.util.AttributeSet;
import android.view.RenderNode;
import android.view.RenderNodeAnimator;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.AnimationUtils;
+import android.widget.LinearLayout;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
import com.android.settingslib.animation.AppearAnimationUtils;
import com.android.settingslib.animation.DisappearAnimationUtils;
+import cyanogenmod.providers.CMSettings;
+
/**
* Displays a PIN pad for unlocking.
*/
@@ -45,6 +54,8 @@ public class KeyguardPINView extends KeyguardPinBasedInputView {
private int mDisappearYTranslation;
private View[][] mViews;
+ private static List<Integer> sNumbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 0);
+
public KeyguardPINView(Context context) {
this(context, null);
}
@@ -102,6 +113,33 @@ public class KeyguardPINView extends KeyguardPinBasedInputView {
new View[]{
null, mEcaView, null
}};
+
+ boolean scramblePin = (CMSettings.System.getInt(getContext().getContentResolver(),
+ CMSettings.System.LOCKSCREEN_PIN_SCRAMBLE_LAYOUT, 0) == 1);
+
+ if (scramblePin) {
+ Collections.shuffle(sNumbers);
+ // get all children who are NumPadKey's
+ LinearLayout container = (LinearLayout) findViewById(R.id.container);
+ List<NumPadKey> views = new ArrayList<NumPadKey>();
+ for (int i = 0; i < container.getChildCount(); i++) {
+ if (container.getChildAt(i) instanceof LinearLayout) {
+ LinearLayout nestedLayout = ((LinearLayout) container.getChildAt(i));
+ for (int j = 0; j < nestedLayout.getChildCount(); j++){
+ View view = nestedLayout.getChildAt(j);
+ if (view.getClass() == NumPadKey.class) {
+ views.add((NumPadKey) view);
+ }
+ }
+ }
+ }
+
+ // reset the digits in the views
+ for (int i = 0; i < sNumbers.size(); i++) {
+ NumPadKey view = views.get(i);
+ view.setDigit(sNumbers.get(i));
+ }
+ }
}
@Override
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardSimPinView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardSimPinView.java
index 2033159..1d10b57 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardSimPinView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardSimPinView.java
@@ -50,7 +50,8 @@ public class KeyguardSimPinView extends KeyguardPinBasedInputView {
private ProgressDialog mSimUnlockProgressDialog = null;
private CheckSimPin mCheckSimPinThread;
-
+ private boolean mShowDefaultMessage = true;
+ private int mRemainingAttempts = -1;
private AlertDialog mRemainingAttemptsDialog;
private int mSubId;
private ImageView mSimImageView;
@@ -74,25 +75,8 @@ public class KeyguardSimPinView extends KeyguardPinBasedInputView {
public void resetState() {
super.resetState();
if (DEBUG) Log.v(TAG, "Resetting state");
- KeyguardUpdateMonitor monitor = KeyguardUpdateMonitor.getInstance(mContext);
- mSubId = monitor.getNextSubIdForState(IccCardConstants.State.PIN_REQUIRED);
- if (SubscriptionManager.isValidSubscriptionId(mSubId)) {
- int count = TelephonyManager.getDefault().getSimCount();
- Resources rez = getResources();
- final String msg;
- int color = Color.WHITE;
- if (count < 2) {
- msg = rez.getString(R.string.kg_sim_pin_instructions);
- } else {
- SubscriptionInfo info = monitor.getSubscriptionInfoForSubId(mSubId);
- CharSequence displayName = info != null ? info.getDisplayName() : ""; // don't crash
- msg = rez.getString(R.string.kg_sim_pin_instructions_multi, displayName);
- if (info != null) {
- color = info.getIconTint();
- }
- }
- mSecurityMessageDisplay.setMessage(msg, true);
- mSimImageView.setImageTintList(ColorStateList.valueOf(color));
+ if (mShowDefaultMessage) {
+ showDefaultMessage();
}
}
@@ -108,17 +92,19 @@ public class KeyguardSimPinView extends KeyguardPinBasedInputView {
return 0;
}
- private String getPinPasswordErrorMessage(int attemptsRemaining) {
+ private String getPinPasswordErrorMessage(int attemptsRemaining, boolean isDefault) {
String displayMessage;
-
+ int msgId;
if (attemptsRemaining == 0) {
displayMessage = getContext().getString(R.string.kg_password_wrong_pin_code_pukked);
} else if (attemptsRemaining > 0) {
+ msgId = isDefault ? R.plurals.kg_password_default_pin_message :
+ R.plurals.kg_password_wrong_pin_code;
displayMessage = getContext().getResources()
- .getQuantityString(R.plurals.kg_password_wrong_pin_code, attemptsRemaining,
- attemptsRemaining);
+ .getQuantityString(msgId, attemptsRemaining, attemptsRemaining);
} else {
- displayMessage = getContext().getString(R.string.kg_password_pin_failed);
+ msgId = isDefault ? R.string.kg_sim_pin_instructions : R.string.kg_password_pin_failed;
+ displayMessage = getContext().getString(msgId);
}
if (DEBUG) Log.d(LOG_TAG, "getPinPasswordErrorMessage:"
+ " attemptsRemaining=" + attemptsRemaining + " displayMessage=" + displayMessage);
@@ -150,6 +136,9 @@ public class KeyguardSimPinView extends KeyguardPinBasedInputView {
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
+ if (mShowDefaultMessage) {
+ showDefaultMessage();
+ }
KeyguardUpdateMonitor.getInstance(mContext).registerCallback(mUpdateMonitorCallback);
}
@@ -228,7 +217,7 @@ public class KeyguardSimPinView extends KeyguardPinBasedInputView {
}
private Dialog getSimRemainingAttemptsDialog(int remaining) {
- String msg = getPinPasswordErrorMessage(remaining);
+ String msg = getPinPasswordErrorMessage(remaining, false);
if (mRemainingAttemptsDialog == null) {
Builder builder = new AlertDialog.Builder(mContext);
builder.setMessage(msg);
@@ -262,6 +251,7 @@ public class KeyguardSimPinView extends KeyguardPinBasedInputView {
void onSimCheckResponse(final int result, final int attemptsRemaining) {
post(new Runnable() {
public void run() {
+ mRemainingAttempts = attemptsRemaining;
if (mSimUnlockProgressDialog != null) {
mSimUnlockProgressDialog.hide();
}
@@ -269,8 +259,12 @@ public class KeyguardSimPinView extends KeyguardPinBasedInputView {
if (result == PhoneConstants.PIN_RESULT_SUCCESS) {
KeyguardUpdateMonitor.getInstance(getContext())
.reportSimUnlocked(mSubId);
- mCallback.dismiss(true);
+ mRemainingAttempts = -1;
+ if (mCallback != null) {
+ mCallback.dismiss(true);
+ }
} else {
+ mShowDefaultMessage = false;
if (result == PhoneConstants.PIN_PASSWORD_INCORRECT) {
if (attemptsRemaining <= 2) {
// this is getting critical - show dialog
@@ -278,7 +272,8 @@ public class KeyguardSimPinView extends KeyguardPinBasedInputView {
} else {
// show message
mSecurityMessageDisplay.setMessage(
- getPinPasswordErrorMessage(attemptsRemaining), true);
+ getPinPasswordErrorMessage(
+ attemptsRemaining, false), true);
}
} else {
// "PIN operation failed!" - no idea what this was and no way to
@@ -309,5 +304,47 @@ public class KeyguardSimPinView extends KeyguardPinBasedInputView {
public boolean startDisappearAnimation(Runnable finishRunnable) {
return false;
}
+
+ private void showDefaultMessage() {
+ KeyguardUpdateMonitor monitor = KeyguardUpdateMonitor.getInstance(mContext);
+ mSubId = monitor.getNextSubIdForState(IccCardConstants.State.PIN_REQUIRED);
+ if (!SubscriptionManager.isValidSubscriptionId(mSubId)) {
+ return;
+ }
+ if (mRemainingAttempts >= 0) {
+ mSecurityMessageDisplay.setMessage(getPinPasswordErrorMessage(
+ mRemainingAttempts, true), true);
+ return;
+ }
+
+ int count = TelephonyManager.getDefault().getSimCount();
+ Resources rez = getResources();
+ final String msg;
+ int color = Color.WHITE;
+ if (count < 2) {
+ msg = rez.getString(R.string.kg_sim_pin_instructions);
+ } else {
+ SubscriptionInfo info = monitor.getSubscriptionInfoForSubId(mSubId);
+ CharSequence displayName = info != null ? info.getDisplayName() : ""; // don't crash
+ msg = rez.getString(R.string.kg_sim_pin_instructions_multi, displayName);
+ if (info != null) {
+ color = info.getIconTint();
+ }
+ }
+ mSecurityMessageDisplay.setMessage(msg, true);
+ mSimImageView.setImageTintList(ColorStateList.valueOf(color));
+
+ new CheckSimPin("", mSubId) {
+ void onSimCheckResponse(final int result, final int attemptsRemaining) {
+ Log.d(LOG_TAG, "onSimCheckResponse " + " dummy One result" + result +
+ " attemptsRemaining=" + attemptsRemaining);
+ if (attemptsRemaining >= 0) {
+ mRemainingAttempts = attemptsRemaining;
+ mSecurityMessageDisplay.setMessage(
+ getPinPasswordErrorMessage(attemptsRemaining, true), true);
+ }
+ }
+ }.start();
+ }
}
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardSimPukView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardSimPukView.java
index af88239..7ba952b 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardSimPukView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardSimPukView.java
@@ -50,6 +50,7 @@ public class KeyguardSimPukView extends KeyguardPinBasedInputView {
private ProgressDialog mSimUnlockProgressDialog = null;
private CheckSimPuk mCheckSimPukThread;
+ private boolean mShowDefaultMessage = true;
private String mPukText;
private String mPinText;
private StateMachine mStateMachine = new StateMachine();
@@ -133,7 +134,10 @@ public class KeyguardSimPukView extends KeyguardPinBasedInputView {
color = info.getIconTint();
}
}
- mSecurityMessageDisplay.setMessage(msg, true);
+ if (mShowDefaultMessage) {
+ mSecurityMessageDisplay.setMessage(msg, true);
+ }
+ mShowDefaultMessage = true;
mSimImageView.setImageTintList(ColorStateList.valueOf(color));
}
mPasswordEntry.requestFocus();
@@ -328,6 +332,7 @@ public class KeyguardSimPukView extends KeyguardPinBasedInputView {
.reportSimUnlocked(mSubId);
mCallback.dismiss(true);
} else {
+ mShowDefaultMessage = false;
if (result == PhoneConstants.PIN_PASSWORD_INCORRECT) {
if (attemptsRemaining <= 2) {
// this is getting critical - show dialog
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 57ee319..e82db97 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -136,6 +136,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
private static final int MSG_SERVICE_STATE_CHANGE = 330;
private static final int MSG_SCREEN_TURNED_ON = 331;
private static final int MSG_SCREEN_TURNED_OFF = 332;
+ private static final int MSG_LOCALE_CHANGED = 500;
/** Fingerprint state: Not listening to fingerprint. */
private static final int FINGERPRINT_STATE_STOPPED = 0;
@@ -274,6 +275,9 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
case MSG_SCREEN_TURNED_OFF:
handleScreenTurnedOff();
break;
+ case MSG_LOCALE_CHANGED:
+ handleLocaleChanged();
+ break;
}
}
};
@@ -650,6 +654,8 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
}
mHandler.sendMessage(
mHandler.obtainMessage(MSG_SERVICE_STATE_CHANGE, subId, 0, serviceState));
+ } else if (Intent.ACTION_LOCALE_CHANGED.equals(action)) {
+ mHandler.sendEmptyMessage(MSG_LOCALE_CHANGED);
}
}
};
@@ -772,11 +778,13 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
state = IccCardConstants.State.PIN_REQUIRED;
} else if (IccCardConstants.INTENT_VALUE_LOCKED_ON_PUK.equals(lockedReason)) {
state = IccCardConstants.State.PUK_REQUIRED;
+ } else if (IccCardConstants.INTENT_VALUE_LOCKED_NETWORK.equals(lockedReason)) {
+ state = IccCardConstants.State.NETWORK_LOCKED;
} else {
state = IccCardConstants.State.UNKNOWN;
}
- } else if (IccCardConstants.INTENT_VALUE_LOCKED_NETWORK.equals(stateExtra)) {
- state = IccCardConstants.State.NETWORK_LOCKED;
+ } else if (IccCardConstants.INTENT_VALUE_ICC_CARD_IO_ERROR.equals(stateExtra)) {
+ state = IccCardConstants.State.CARD_IO_ERROR;
} else if (IccCardConstants.INTENT_VALUE_ICC_LOADED.equals(stateExtra)
|| IccCardConstants.INTENT_VALUE_ICC_IMSI.equals(stateExtra)) {
// This is required because telephony doesn't return to "READY" after
@@ -976,6 +984,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
filter.addAction(Intent.ACTION_BATTERY_CHANGED);
filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
+ filter.addAction(Intent.ACTION_LOCALE_CHANGED);
filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
filter.addAction(TelephonyIntents.ACTION_SERVICE_STATE_CHANGED);
filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
@@ -1316,6 +1325,18 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
}
/**
+ * Handle {@link #MSG_LOCALE_CHANGED}
+ */
+ private void handleLocaleChanged() {
+ for (int j = 0; j < mCallbacks.size(); j++) {
+ KeyguardUpdateMonitorCallback cb = mCallbacks.get(j).get();
+ if (cb != null) {
+ cb.onRefreshCarrierInfo();
+ }
+ }
+ }
+
+ /**
* Handle {@link #MSG_SERVICE_STATE_CHANGE}
*/
private void handleServiceStateChange(int subId, ServiceState serviceState) {
diff --git a/packages/Keyguard/src/com/android/keyguard/NumPadKey.java b/packages/Keyguard/src/com/android/keyguard/NumPadKey.java
index ef8bb0b..839c165 100644
--- a/packages/Keyguard/src/com/android/keyguard/NumPadKey.java
+++ b/packages/Keyguard/src/com/android/keyguard/NumPadKey.java
@@ -20,6 +20,7 @@ import android.content.Context;
import android.content.res.TypedArray;
import android.os.PowerManager;
import android.os.SystemClock;
+import android.provider.Settings;
import android.util.AttributeSet;
import android.view.HapticFeedbackConstants;
import android.view.LayoutInflater;
@@ -29,6 +30,8 @@ import android.widget.TextView;
import com.android.internal.widget.LockPatternUtils;
+import cyanogenmod.providers.CMSettings;
+
public class NumPadKey extends ViewGroup {
// list of "ABC", etc per digit, starting with '0'
static String sKlondike[];
@@ -73,7 +76,6 @@ public class NumPadKey extends ViewGroup {
public NumPadKey(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
setFocusable(true);
-
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.NumPadKey);
try {
@@ -88,7 +90,6 @@ public class NumPadKey extends ViewGroup {
setAccessibilityDelegate(new ObscureSpeechDelegate(context));
mEnableHaptics = new LockPatternUtils(context).isTactileFeedbackEnabled();
-
mPM = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(
Context.LAYOUT_INFLATER_SERVICE);
@@ -98,32 +99,44 @@ public class NumPadKey extends ViewGroup {
mDigitText.setText(Integer.toString(mDigit));
mKlondikeText = (TextView) findViewById(R.id.klondike_text);
+ updateText();
+ setBackground(mContext.getDrawable(R.drawable.ripple_drawable));
+ setContentDescription(mDigitText.getText().toString());
+ }
+
+ @Override
+ public void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+
+ // Reset the "announced headset" flag when detached.
+ ObscureSpeechDelegate.sAnnouncedHeadset = false;
+ }
+
+ public void setDigit(int digit) {
+ mDigit = digit;
+ updateText();
+ }
+
+ private void updateText() {
+ boolean scramblePin = (CMSettings.System.getInt(getContext().getContentResolver(),
+ CMSettings.System.LOCKSCREEN_PIN_SCRAMBLE_LAYOUT, 0) == 1);
if (mDigit >= 0) {
+ mDigitText.setText(Integer.toString(mDigit));
if (sKlondike == null) {
sKlondike = getResources().getStringArray(R.array.lockscreen_num_pad_klondike);
}
if (sKlondike != null && sKlondike.length > mDigit) {
String klondike = sKlondike[mDigit];
final int len = klondike.length();
- if (len > 0) {
+ if (len > 0 || scramblePin) {
mKlondikeText.setText(klondike);
} else {
mKlondikeText.setVisibility(View.INVISIBLE);
}
}
}
-
- setBackground(mContext.getDrawable(R.drawable.ripple_drawable));
- setContentDescription(mDigitText.getText().toString());
}
- @Override
- public void onDetachedFromWindow() {
- super.onDetachedFromWindow();
-
- // Reset the "announced headset" flag when detached.
- ObscureSpeechDelegate.sAnnouncedHeadset = false;
- }
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
diff --git a/packages/PrintSpooler/res/values-zh-rCN/arrays.xml b/packages/PrintSpooler/res/values-zh-rCN/arrays.xml
new file mode 100644
index 0000000..4fc75db
--- /dev/null
+++ b/packages/PrintSpooler/res/values-zh-rCN/arrays.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<resources>
+
+ <string-array name="pdf_printer_media_sizes" translatable="false">
+ <item>ROC_8K</item>
+ <item>ROC_16K</item>
+ <item>PRC_1</item>
+ <item>PRC_2</item>
+ <item>PRC_3</item>
+ <item>PRC_4</item>
+ <item>PRC_5</item>
+ <item>PRC_6</item>
+ <item>PRC_7</item>
+ <item>PRC_8</item>
+ <item>PRC_9</item>
+ <item>PRC_10</item>
+ <item>PRC_16K</item>
+ <item>OM_PA_KAI</item>
+ <item>OM_DAI_PA_KAI</item>
+ <item>OM_JUURO_KU_KAI</item>
+ </string-array>
+
+</resources>
diff --git a/packages/PrintSpooler/src/com/android/printspooler/renderer/PdfManipulationService.java b/packages/PrintSpooler/src/com/android/printspooler/renderer/PdfManipulationService.java
index 7db2074..11a9a0e 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/renderer/PdfManipulationService.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/renderer/PdfManipulationService.java
@@ -56,6 +56,7 @@ public final class PdfManipulationService extends Service {
private static final int MILS_PER_INCH = 1000;
private static final int POINTS_IN_INCH = 72;
+ private final Object mLock = new Object();
@Override
public IBinder onBind(Intent intent) {
@@ -74,8 +75,6 @@ public final class PdfManipulationService extends Service {
}
private final class PdfRendererImpl extends IPdfRenderer.Stub {
- private final Object mLock = new Object();
-
private Bitmap mBitmap;
private PdfRenderer mRenderer;
@@ -209,8 +208,6 @@ public final class PdfManipulationService extends Service {
}
private final class PdfEditorImpl extends IPdfEditor.Stub {
- private final Object mLock = new Object();
-
private PdfEditor mEditor;
@Override
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
index e8a5e43..1fb84b4 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
@@ -371,6 +371,22 @@ public class PrintActivity extends Activity implements RemotePrintDocument.Updat
}
@Override
+ protected void onDestroy() {
+ if (mState != STATE_INITIALIZING) {
+ mPrintPreviewController.destroy(new Runnable() {
+ @Override
+ public void run() {
+ finish();
+ }
+ });
+ } else {
+ finish();
+ }
+
+ super.onDestroy();
+ }
+
+ @Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
event.startTracking();
diff --git a/packages/SettingsLib/res/drawable-hdpi/activities_icon.png b/packages/SettingsLib/res/drawable-hdpi/activities_icon.png
new file mode 100644
index 0000000..d4fb5cb
--- /dev/null
+++ b/packages/SettingsLib/res/drawable-hdpi/activities_icon.png
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-mdpi/activities_icon.png b/packages/SettingsLib/res/drawable-mdpi/activities_icon.png
new file mode 100644
index 0000000..db3f889
--- /dev/null
+++ b/packages/SettingsLib/res/drawable-mdpi/activities_icon.png
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-xhdpi/activities_icon.png b/packages/SettingsLib/res/drawable-xhdpi/activities_icon.png
new file mode 100644
index 0000000..b649acb
--- /dev/null
+++ b/packages/SettingsLib/res/drawable-xhdpi/activities_icon.png
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-xxhdpi/activities_icon.png b/packages/SettingsLib/res/drawable-xxhdpi/activities_icon.png
new file mode 100644
index 0000000..295bba3
--- /dev/null
+++ b/packages/SettingsLib/res/drawable-xxhdpi/activities_icon.png
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-xxxhdpi/activities_icon.png b/packages/SettingsLib/res/drawable-xxxhdpi/activities_icon.png
new file mode 100644
index 0000000..0b05aef
--- /dev/null
+++ b/packages/SettingsLib/res/drawable-xxxhdpi/activities_icon.png
Binary files differ
diff --git a/packages/SettingsLib/res/values/cm_dimens.xml b/packages/SettingsLib/res/values/cm_dimens.xml
new file mode 100644
index 0000000..0ab24d0
--- /dev/null
+++ b/packages/SettingsLib/res/values/cm_dimens.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2015 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
+ -->
+<resources>
+ <dimen name="shortcut_picker_left_padding">40dip</dimen>
+</resources>
diff --git a/packages/SettingsLib/res/values/cm_strings.xml b/packages/SettingsLib/res/values/cm_strings.xml
new file mode 100644
index 0000000..a8348b4
--- /dev/null
+++ b/packages/SettingsLib/res/values/cm_strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2015 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.
+*/
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="profile_applist_title">Apps</string>
+ <string name="picker_activities">Activities</string>
+ <string name="select_custom_app_title">Select custom app</string>
+ <string name="select_custom_activity_title">Select custom activity</string>
+ <string name="lockscreen_targets_message">Lock screen shortcuts</string>
+</resources>
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index b03f100..c110321 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -123,6 +123,8 @@
<string name="bluetooth_profile_map">Message Access</string>
<!-- Bluetooth settings. The user-visible string that is used whenever referring to the SAP profile (sharing SIM card). -->
<string name="bluetooth_profile_sap">SIM Access</string>
+ <!-- Bluetooth settings. The user-visible string that is used whenever referring to the dun profile. -->
+ <string name="bluetooth_profile_dun">Dial-up Network Access</string>
<!-- Bluetooth settings. Connection options screen. The summary for the A2DP checkbox preference when A2DP is connected. -->
<string name="bluetooth_a2dp_profile_summary_connected">Connected to media audio</string>
@@ -142,6 +144,8 @@
<string name="bluetooth_pan_user_profile_summary_connected">Connected to device for Internet access</string>
<!-- Bluetooth settings. Connection options screen. The summary for the checkbox preference when PAN is connected (NAP role). [CHAR LIMIT=25]-->
<string name="bluetooth_pan_nap_profile_summary_connected">Sharing local Internet connection with device</string>
+ <!-- Bluetooth settings. Connection options screen. The summary for the DUN checkbox preference when DUN is connected. -->
+ <string name="bluetooth_dun_profile_summary_connected">Connected to Dun Server</string>
<!-- Bluetooth settings. Connection options screen. The summary
for the PAN checkbox preference that describes how checking it
@@ -161,6 +165,8 @@
for the HID checkbox preference that describes how checking it
will set the HID profile as preferred. -->
<string name="bluetooth_hid_profile_summary_use_for">Use for input</string>
+ <!-- Bluetooth settings. Connection options screen. The summary for the dun checkbox preference that describes how checking it will set the dun profile as preferred. -->
+ <string name="bluetooth_dun_profile_summary_use_for">Use for Dial-up Network access</string>
<!-- Button text for accepting an incoming pairing request. [CHAR LIMIT=20] -->
<string name="bluetooth_pairing_accept">Pair</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
index 9608daa..873d392 100755..100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
@@ -116,7 +116,11 @@ public final class A2dpProfile implements LocalBluetoothProfile {
List<BluetoothDevice> sinks = getConnectedDevices();
if (sinks != null) {
for (BluetoothDevice sink : sinks) {
- mService.disconnect(sink);
+ if (sink.equals(device)) {
+ // Connect to same device, Ignore it
+ Log.d(TAG,"Not disconnecting device = " + sink);
+ return true;
+ }
}
}
return mService.connect(device);
@@ -124,18 +128,36 @@ public final class A2dpProfile implements LocalBluetoothProfile {
public boolean disconnect(BluetoothDevice device) {
if (mService == null) return false;
- // Downgrade priority as user is disconnecting the headset.
- if (mService.getPriority(device) > BluetoothProfile.PRIORITY_ON){
- mService.setPriority(device, BluetoothProfile.PRIORITY_ON);
+ List<BluetoothDevice> deviceList = mService.getConnectedDevices();
+ if (!deviceList.isEmpty()) {
+ for (BluetoothDevice dev : deviceList) {
+ if (dev.equals(device)) {
+ if (V) Log.d(TAG,"Downgrade priority as user" +
+ "is disconnecting the headset");
+ // Downgrade priority as user is disconnecting the headset.
+ if (mService.getPriority(device) > BluetoothProfile.PRIORITY_ON) {
+ mService.setPriority(device, BluetoothProfile.PRIORITY_ON);
+ }
+ return mService.disconnect(device);
+ }
+ }
}
- return mService.disconnect(device);
+ return false;
}
public int getConnectionStatus(BluetoothDevice device) {
if (mService == null) {
return BluetoothProfile.STATE_DISCONNECTED;
}
- return mService.getConnectionState(device);
+ List<BluetoothDevice> deviceList = mService.getConnectedDevices();
+ if (!deviceList.isEmpty()) {
+ for (BluetoothDevice dev : deviceList) {
+ if (dev.equals(device)) {
+ return mService.getConnectionState(device);
+ }
+ }
+ }
+ return BluetoothProfile.STATE_DISCONNECTED;
}
public boolean isPreferred(BluetoothDevice device) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpSinkProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpSinkProfile.java
new file mode 100755
index 0000000..fd76d81
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpSinkProfile.java
@@ -0,0 +1,223 @@
+/*
+ * 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.settingslib.bluetooth;
+
+import android.bluetooth.BluetoothA2dpSink;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothClass;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothProfile;
+import android.bluetooth.BluetoothUuid;
+import android.content.Context;
+import android.os.ParcelUuid;
+import android.util.Log;
+
+import com.android.settingslib.R;
+
+import java.util.ArrayList;
+import java.util.List;
+
+final class A2dpSinkProfile implements LocalBluetoothProfile {
+ private static final String TAG = "A2dpSinkProfile";
+ private static boolean V = true;
+
+ private BluetoothA2dpSink mService;
+ private boolean mIsProfileReady;
+
+ private final LocalBluetoothAdapter mLocalAdapter;
+ private final CachedBluetoothDeviceManager mDeviceManager;
+
+ static final ParcelUuid[] SRC_UUIDS = {
+ BluetoothUuid.AudioSource,
+ BluetoothUuid.AdvAudioDist,
+ };
+
+ static final String NAME = "A2DPSink";
+ private final LocalBluetoothProfileManager mProfileManager;
+
+ // Order of this profile in device profiles list
+ private static final int ORDINAL = 5;
+
+ // These callbacks run on the main thread.
+ private final class A2dpSinkServiceListener
+ implements BluetoothProfile.ServiceListener {
+
+ public void onServiceConnected(int profile, BluetoothProfile proxy) {
+ if (V) Log.d(TAG,"Bluetooth service connected");
+ mService = (BluetoothA2dpSink) proxy;
+ // We just bound to the service, so refresh the UI for any connected A2DP devices.
+ List<BluetoothDevice> deviceList = mService.getConnectedDevices();
+ while (!deviceList.isEmpty()) {
+ BluetoothDevice nextDevice = deviceList.remove(0);
+ CachedBluetoothDevice device = mDeviceManager.findDevice(nextDevice);
+ // we may add a new device here, but generally this should not happen
+ if (device == null) {
+ Log.w(TAG, "A2dpSinkProfile found new device: " + nextDevice);
+ device = mDeviceManager.addDevice(mLocalAdapter, mProfileManager, nextDevice);
+ }
+ device.onProfileStateChanged(A2dpSinkProfile.this, BluetoothProfile.STATE_CONNECTED);
+ device.refresh();
+ }
+ mIsProfileReady=true;
+ }
+
+ public void onServiceDisconnected(int profile) {
+ if (V) Log.d(TAG,"Bluetooth service disconnected");
+ mIsProfileReady=false;
+ }
+ }
+
+ public boolean isProfileReady() {
+ return mIsProfileReady;
+ }
+
+ A2dpSinkProfile(Context context, LocalBluetoothAdapter adapter,
+ CachedBluetoothDeviceManager deviceManager,
+ LocalBluetoothProfileManager profileManager) {
+ mLocalAdapter = adapter;
+ mDeviceManager = deviceManager;
+ mProfileManager = profileManager;
+ mLocalAdapter.getProfileProxy(context, new A2dpSinkServiceListener(),
+ BluetoothProfile.A2DP_SINK);
+ }
+
+ public boolean isConnectable() {
+ return true;
+ }
+
+ public boolean isAutoConnectable() {
+ return true;
+ }
+
+ public List<BluetoothDevice> getConnectedDevices() {
+ if (mService == null) return new ArrayList<BluetoothDevice>(0);
+ return mService.getDevicesMatchingConnectionStates(
+ new int[] {BluetoothProfile.STATE_CONNECTED,
+ BluetoothProfile.STATE_CONNECTING,
+ BluetoothProfile.STATE_DISCONNECTING});
+ }
+
+ public boolean connect(BluetoothDevice device) {
+ if (mService == null) return false;
+ List<BluetoothDevice> srcs = getConnectedDevices();
+ if (srcs != null) {
+ for (BluetoothDevice src : srcs) {
+ if (src.equals(device)) {
+ // Connect to same device, Ignore it
+ Log.d(TAG,"Ignoring Connect");
+ return true;
+ }
+ }
+ for (BluetoothDevice src : srcs) {
+ mService.disconnect(src);
+ }
+ }
+ return mService.connect(device);
+ }
+
+ public boolean disconnect(BluetoothDevice device) {
+ if (mService == null) return false;
+ // Downgrade priority as user is disconnecting the headset.
+ if (mService.getPriority(device) > BluetoothProfile.PRIORITY_ON){
+ mService.setPriority(device, BluetoothProfile.PRIORITY_ON);
+ }
+ return mService.disconnect(device);
+ }
+
+ public int getConnectionStatus(BluetoothDevice device) {
+ if (mService == null) {
+ return BluetoothProfile.STATE_DISCONNECTED;
+ }
+ return mService.getConnectionState(device);
+ }
+
+ public boolean isPreferred(BluetoothDevice device) {
+ if (mService == null) return false;
+ return mService.getPriority(device) > BluetoothProfile.PRIORITY_OFF;
+ }
+
+ public int getPreferred(BluetoothDevice device) {
+ if (mService == null) return BluetoothProfile.PRIORITY_OFF;
+ return mService.getPriority(device);
+ }
+
+ public void setPreferred(BluetoothDevice device, boolean preferred) {
+ if (mService == null) return;
+ if (preferred) {
+ if (mService.getPriority(device) < BluetoothProfile.PRIORITY_ON) {
+ mService.setPriority(device, BluetoothProfile.PRIORITY_ON);
+ }
+ } else {
+ mService.setPriority(device, BluetoothProfile.PRIORITY_OFF);
+ }
+ }
+
+ boolean isA2dpPlaying() {
+ if (mService == null) return false;
+ List<BluetoothDevice> srcs = mService.getConnectedDevices();
+ if (!srcs.isEmpty()) {
+ if (mService.isA2dpPlaying(srcs.get(0))) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public String toString() {
+ return NAME;
+ }
+
+ public int getOrdinal() {
+ return ORDINAL;
+ }
+
+ public int getNameResource(BluetoothDevice device) {
+ // we need to have same string in UI for even SINK Media Audio.
+ return R.string.bluetooth_profile_a2dp;
+ }
+
+ public int getSummaryResourceForDevice(BluetoothDevice device) {
+ int state = getConnectionStatus(device);
+ switch (state) {
+ case BluetoothProfile.STATE_DISCONNECTED:
+ return R.string.bluetooth_a2dp_profile_summary_use_for;
+
+ case BluetoothProfile.STATE_CONNECTED:
+ return R.string.bluetooth_a2dp_profile_summary_connected;
+
+ default:
+ return Utils.getConnectionStateSummary(state);
+ }
+ }
+
+ public int getDrawableResource(BluetoothClass btClass) {
+ return R.drawable.ic_bt_headphones_a2dp;
+ }
+
+ protected void finalize() {
+ if (V) Log.d(TAG, "finalize()");
+ if (mService != null) {
+ try {
+ BluetoothAdapter.getDefaultAdapter().closeProfileProxy(BluetoothProfile.A2DP_SINK,
+ mService);
+ mService = null;
+ }catch (Throwable t) {
+ Log.w(TAG, "Error cleaning up A2DP proxy", t);
+ }
+ }
+ }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothDeviceFilter.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothDeviceFilter.java
index 8dec86a..0bd8dbd 100644..100755
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothDeviceFilter.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothDeviceFilter.java
@@ -112,11 +112,15 @@ public final class BluetoothDeviceFilter {
if (BluetoothUuid.containsAnyUuid(uuids, A2dpProfile.SINK_UUIDS)) {
return true;
}
+ if (BluetoothUuid.containsAnyUuid(uuids, A2dpSinkProfile.SRC_UUIDS)) {
+ return true;
+ }
if (BluetoothUuid.containsAnyUuid(uuids, HeadsetProfile.UUIDS)) {
return true;
}
} else if (btClass != null) {
if (btClass.doesClassMatch(BluetoothClass.PROFILE_A2DP) ||
+ btClass.doesClassMatch(BluetoothClass.PROFILE_A2DP_SINK) ||
btClass.doesClassMatch(BluetoothClass.PROFILE_HEADSET)) {
return true;
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
index 4bcbea7..8dc48b3 100755
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
@@ -196,6 +196,8 @@ public final class BluetoothEventManager {
cachedDevice = mDeviceManager.addDevice(mLocalAdapter, mProfileManager, device);
Log.d(TAG, "DeviceFoundHandler created new CachedBluetoothDevice: "
+ cachedDevice);
+ // callback to UI to create Preference for new device
+ dispatchDeviceAdded(cachedDevice);
}
cachedDevice.setRssi(rssi);
cachedDevice.setBtClass(btClass);
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
index e4b1ed8..a6f873d 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
@@ -135,6 +135,8 @@ public final class CachedBluetoothDevice implements Comparable<CachedBluetoothDe
if (newProfileState == BluetoothProfile.STATE_CONNECTED) {
if (profile instanceof MapProfile) {
profile.setPreferred(mDevice, true);
+ mRemovedProfiles.remove(profile);
+ mProfiles.add(profile);
} else if (!mProfiles.contains(profile)) {
mRemovedProfiles.remove(profile);
mProfiles.add(profile);
@@ -521,7 +523,29 @@ public final class CachedBluetoothDevice implements Comparable<CachedBluetoothDe
* Refreshes the UI when framework alerts us of a UUID change.
*/
void onUuidChanged() {
+ Log.d(TAG, " onUuidChanged, mProfile Size " + mProfiles.size());
+ List<LocalBluetoothProfile> mPrevProfiles =
+ new ArrayList<LocalBluetoothProfile>();
+ mPrevProfiles.clear();
+ mPrevProfiles.addAll(mProfiles);
updateProfiles();
+ /*
+ * Check if new profiles are added
+ */
+ if ((mPrevProfiles.containsAll(mProfiles)) && (!mPrevProfiles.isEmpty())) {
+ Log.d(TAG,"UUID not udpated, returning");
+ mProfiles.clear();
+ mProfiles.addAll(mPrevProfiles);
+ return;
+ }
+ for (int i = 0; i<mProfiles.size(); ++i) {
+ if (!mPrevProfiles.contains(mProfiles.get(i))) {
+ mPrevProfiles.add(mProfiles.get(i));
+ }
+ }
+ mProfiles.clear();
+ mProfiles.addAll(mPrevProfiles);
+
ParcelUuid[] uuids = mDevice.getUuids();
long timeout = MAX_UUID_DELAY_FOR_AUTO_CONNECT;
@@ -846,7 +870,8 @@ public final class CachedBluetoothDevice implements Comparable<CachedBluetoothDe
case BluetoothProfile.STATE_DISCONNECTED:
if (profile.isProfileReady()) {
- if (profile instanceof A2dpProfile) {
+ if ((profile instanceof A2dpProfile)||
+ (profile instanceof A2dpSinkProfile)){
a2dpNotConnected = true;
} else if (profile instanceof HeadsetProfile) {
headsetNotConnected = true;
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/DunServerProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/DunServerProfile.java
new file mode 100644
index 0000000..3c72927
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/DunServerProfile.java
@@ -0,0 +1,162 @@
+/*
+*Copyright (c) 2013, 2015, The Linux Foundation. All rights reserved.
+*
+*Redistribution and use in source and binary forms, with or without
+*modification, are permitted provided that the following conditions are
+*met:
+* * Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+* * Redistributions in binary form must reproduce the above
+* copyright notice, this list of conditions and the following
+* disclaimer in the documentation and/or other materials provided
+* with the distribution.
+* * Neither the name of The Linux Foundation nor the names of its
+* contributors may be used to endorse or promote products derived
+* from this software without specific prior written permission.
+*
+*THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+*WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+*MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+*ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+*BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+*CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+*SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+*BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+*WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+*OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+*IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+package com.android.settingslib.bluetooth;
+
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothClass;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothDun;
+import android.bluetooth.BluetoothProfile;
+import android.content.Context;
+import android.util.Log;
+import java.util.HashMap;
+import java.util.List;
+
+import com.android.settingslib.R;
+
+/**
+ * DunServerProfile handles Bluetooth DUN server profile.
+ */
+final class DunServerProfile implements LocalBluetoothProfile {
+ private static final String TAG = "DunServerProfile";
+ private static boolean V = true;
+
+ private BluetoothDun mService;
+ private boolean mIsProfileReady;
+
+ static final String NAME = "DUN Server";
+
+ // Order of this profile in device profiles list
+ private static final int ORDINAL = 11;
+
+ // These callbacks run on the main thread.
+ private final class DunServiceListener
+ implements BluetoothProfile.ServiceListener {
+
+ public void onServiceConnected(int profile, BluetoothProfile proxy) {
+ if (V) Log.d(TAG,"Bluetooth service connected");
+ mService = (BluetoothDun) proxy;
+ mIsProfileReady = true;
+ }
+
+ public void onServiceDisconnected(int profile) {
+ if (V) Log.d(TAG,"Bluetooth service disconnected");
+ mIsProfileReady = false;
+ }
+ }
+
+ public boolean isProfileReady() {
+ return mIsProfileReady;
+ }
+
+ DunServerProfile(Context context) {
+ BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+ adapter.getProfileProxy(context, new DunServiceListener(),
+ BluetoothProfile.DUN);
+ }
+
+ public boolean isConnectable() {
+ return true;
+ }
+
+ public boolean isAutoConnectable() {
+ return false;
+ }
+
+ public boolean connect(BluetoothDevice device) {
+ return false;
+ }
+
+ public boolean disconnect(BluetoothDevice device) {
+ if (mService == null) return false;
+ return mService.disconnect(device);
+ }
+
+ public int getConnectionStatus(BluetoothDevice device) {
+ if (mService == null) {
+ return BluetoothProfile.STATE_DISCONNECTED;
+ }
+ return mService.getConnectionState(device);
+ }
+
+ public boolean isPreferred(BluetoothDevice device) {
+ return true;
+ }
+
+ public int getPreferred(BluetoothDevice device) {
+ return -1;
+ }
+
+ public void setPreferred(BluetoothDevice device, boolean preferred) {
+ // ignore: isPreferred is always true for DUN
+ }
+
+ public String toString() {
+ return NAME;
+ }
+
+ public int getOrdinal() {
+ return ORDINAL;
+ }
+
+ public int getNameResource(BluetoothDevice device) {
+ return R.string.bluetooth_profile_dun;
+ }
+
+ public int getSummaryResourceForDevice(BluetoothDevice device) {
+ int state = getConnectionStatus(device);
+ switch (state) {
+ case BluetoothProfile.STATE_DISCONNECTED:
+ return R.string.bluetooth_dun_profile_summary_use_for;
+
+ case BluetoothProfile.STATE_CONNECTED:
+ return R.string.bluetooth_dun_profile_summary_connected;
+ default:
+ return Utils.getConnectionStateSummary(state);
+ }
+ }
+
+ public int getDrawableResource(BluetoothClass btClass) {
+ return R.drawable.ic_bt_network_pan;
+ }
+
+ protected void finalize() {
+ if (V) Log.d(TAG, "finalize()");
+ if (mService != null) {
+ try {
+ BluetoothAdapter.getDefaultAdapter().closeProfileProxy
+ (BluetoothProfile.DUN, mService);
+ mService = null;
+ } catch (Throwable t) {
+ Log.w(TAG, "Error cleaning up DUN proxy", t);
+ }
+ }
+ }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothAdapter.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothAdapter.java
index f935f31..9c5abf3 100644..100755
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothAdapter.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothAdapter.java
@@ -162,6 +162,10 @@ public final class LocalBluetoothAdapter {
if (a2dp != null && a2dp.isA2dpPlaying()) {
return;
}
+ A2dpSinkProfile a2dpSink = mProfileManager.getA2dpSinkProfile();
+ if ((a2dpSink != null) && (a2dpSink.isA2dpPlaying())){
+ return;
+ }
}
if (mAdapter.startDiscovery()) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
index 8f5e1f1..3876468 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
@@ -17,11 +17,14 @@
package com.android.settingslib.bluetooth;
import android.bluetooth.BluetoothA2dp;
+import android.bluetooth.BluetoothA2dpSink;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHeadset;
import android.bluetooth.BluetoothMap;
import android.bluetooth.BluetoothInputDevice;
import android.bluetooth.BluetoothPan;
+import android.bluetooth.BluetoothDun;
+import android.bluetooth.BluetoothPbap;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.BluetoothUuid;
import android.content.Context;
@@ -32,6 +35,7 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
+import android.os.SystemProperties;
/**
* LocalBluetoothProfileManager provides access to the LocalBluetoothProfile
@@ -73,11 +77,13 @@ public final class LocalBluetoothProfileManager {
private final BluetoothEventManager mEventManager;
private A2dpProfile mA2dpProfile;
+ private A2dpSinkProfile mA2dpSinkProfile;
private HeadsetProfile mHeadsetProfile;
private MapProfile mMapProfile;
private final HidProfile mHidProfile;
private OppProfile mOppProfile;
private final PanProfile mPanProfile;
+ private DunServerProfile mDunProfile;
private final PbapServerProfile mPbapProfile;
/**
@@ -121,9 +127,17 @@ public final class LocalBluetoothProfileManager {
addProfile(mMapProfile, MapProfile.NAME,
BluetoothMap.ACTION_CONNECTION_STATE_CHANGED);
- //Create PBAP server profile, but do not add it to list of profiles
- // as we do not need to monitor the profile as part of profile list
+ // enable DUN only if the property is set
+ if (SystemProperties.getBoolean("ro.bluetooth.dun", false) == true) {
+ mDunProfile = new DunServerProfile(context);
+ addProfile(mDunProfile, DunServerProfile.NAME,
+ BluetoothDun.ACTION_CONNECTION_STATE_CHANGED);
+ }
+
+ //Create PBAP server profile
mPbapProfile = new PbapServerProfile(context);
+ addProfile(mPbapProfile, PbapServerProfile.NAME,
+ BluetoothPbap.PBAP_STATE_CHANGED_ACTION);
if (DEBUG) Log.d(TAG, "LocalBluetoothProfileManager construction complete");
}
@@ -136,10 +150,10 @@ public final class LocalBluetoothProfileManager {
* @param uuids
*/
void updateLocalProfiles(ParcelUuid[] uuids) {
- // A2DP
+ // A2DP SRC
if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.AudioSource)) {
if (mA2dpProfile == null) {
- if(DEBUG) Log.d(TAG, "Adding local A2DP profile");
+ if(DEBUG) Log.d(TAG, "Adding local A2DP SRC profile");
mA2dpProfile = new A2dpProfile(mContext, mLocalAdapter, mDeviceManager, this);
addProfile(mA2dpProfile, A2dpProfile.NAME,
BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED);
@@ -148,6 +162,17 @@ public final class LocalBluetoothProfileManager {
Log.w(TAG, "Warning: A2DP profile was previously added but the UUID is now missing.");
}
+ if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.AudioSink)) {
+ if (mA2dpSinkProfile == null) {
+ if(DEBUG) Log.d(TAG, "Adding local A2DP Sink profile");
+ mA2dpSinkProfile = new A2dpSinkProfile(mContext, mLocalAdapter, mDeviceManager, this);
+ addProfile(mA2dpSinkProfile, A2dpSinkProfile.NAME,
+ BluetoothA2dpSink.ACTION_CONNECTION_STATE_CHANGED);
+ }
+ } else if (mA2dpSinkProfile != null) {
+ Log.w(TAG, "Warning: A2DP Sink profile was previously added but the UUID is now missing.");
+ }
+
// Headset / Handsfree
if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.Handsfree_AG) ||
BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.HSP_AG)) {
@@ -288,6 +313,10 @@ public final class LocalBluetoothProfileManager {
if (profile != null) {
return profile.isProfileReady();
}
+ profile = mA2dpSinkProfile;
+ if (profile != null) {
+ return profile.isProfileReady();
+ }
return false;
}
@@ -295,6 +324,13 @@ public final class LocalBluetoothProfileManager {
return mA2dpProfile;
}
+ A2dpSinkProfile getA2dpSinkProfile() {
+ if ((mA2dpSinkProfile != null)&&(mA2dpSinkProfile.isProfileReady()))
+ return mA2dpSinkProfile;
+ else
+ return null;
+ }
+
public HeadsetProfile getHeadsetProfile() {
return mHeadsetProfile;
}
@@ -345,6 +381,12 @@ public final class LocalBluetoothProfileManager {
removedProfiles.remove(mA2dpProfile);
}
+ if (BluetoothUuid.containsAnyUuid(uuids, A2dpSinkProfile.SRC_UUIDS) &&
+ mA2dpSinkProfile != null) {
+ profiles.add(mA2dpSinkProfile);
+ removedProfiles.remove(mA2dpSinkProfile);
+ }
+
if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.ObexObjectPush) &&
mOppProfile != null) {
profiles.add(mOppProfile);
@@ -372,6 +414,13 @@ public final class LocalBluetoothProfileManager {
removedProfiles.remove(mMapProfile);
mMapProfile.setPreferred(device, true);
}
+
+ if ((mPbapProfile != null) &&
+ (mPbapProfile.getConnectionStatus(device) == BluetoothProfile.STATE_CONNECTED)) {
+ profiles.add(mPbapProfile);
+ removedProfiles.remove(mPbapProfile);
+ mPbapProfile.setPreferred(device, true);
+ }
}
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapServerProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapServerProfile.java
index 9e76933..fea7b34 100755
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapServerProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapServerProfile.java
@@ -88,8 +88,13 @@ public final class PbapServerProfile implements LocalBluetoothProfile {
}
public boolean disconnect(BluetoothDevice device) {
- if (mService == null) return false;
- return mService.disconnect();
+ if (mService == null || device == null) return false;
+
+ if (getConnectionStatus(device) == BluetoothProfile.STATE_CONNECTED)
+ return mService.disconnect();
+
+ Log.d(TAG, "pbap server not connected to " + device.getAddress());
+ return false;
}
public int getConnectionStatus(BluetoothDevice device) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/cm/ShortcutPickHelper.java b/packages/SettingsLib/src/com/android/settingslib/cm/ShortcutPickHelper.java
new file mode 100644
index 0000000..a18a7e9
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/cm/ShortcutPickHelper.java
@@ -0,0 +1,326 @@
+/*
+ * 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 com.android.settingslib.cm;
+
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.AlertDialog.Builder;
+import android.app.Fragment;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.Intent.ShortcutIconResource;
+import android.content.pm.ActivityInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.os.Bundle;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.BaseExpandableListAdapter;
+import android.widget.ExpandableListView;
+import android.widget.TextView;
+
+import com.android.settingslib.R;
+import com.android.settingslib.cm.ShortcutPickHelper.AppExpandableAdapter.GroupInfo;
+
+public class ShortcutPickHelper {
+
+ private Activity mParent;
+ private AlertDialog mAlertDialog;
+ private OnPickListener mListener;
+ private PackageManager mPackageManager;
+ private static final int REQUEST_PICK_SHORTCUT = 100;
+ private static final int REQUEST_PICK_APPLICATION = 101;
+ private static final int REQUEST_CREATE_SHORTCUT = 102;
+ private int lastFragmentId;
+
+ public interface OnPickListener {
+ void shortcutPicked(String uri, String friendlyName, boolean isApplication);
+ }
+
+ public ShortcutPickHelper(Activity parent, OnPickListener listener) {
+ mParent = parent;
+ mPackageManager = mParent.getPackageManager();
+ mListener = listener;
+ }
+
+ public void onActivityResult(int requestCode, int resultCode, Intent data) {
+ if (resultCode == Activity.RESULT_OK) {
+ switch (requestCode) {
+ case REQUEST_PICK_APPLICATION:
+ completeSetCustomApp(data);
+ break;
+ case REQUEST_CREATE_SHORTCUT:
+ completeSetCustomShortcut(data);
+ break;
+ case REQUEST_PICK_SHORTCUT:
+ processShortcut(data, REQUEST_PICK_APPLICATION, REQUEST_CREATE_SHORTCUT);
+ break;
+ }
+ } else {
+ mListener.shortcutPicked(null, null, false);
+ }
+ }
+
+ public void pickShortcut(String[] names, ShortcutIconResource[] icons, int fragmentId) {
+ Bundle bundle = new Bundle();
+
+ ArrayList<String> shortcutNames = new ArrayList<String>();
+ if (names != null) {
+ for (String s : names) {
+ shortcutNames.add(s);
+ }
+ }
+ shortcutNames.add(mParent.getString(R.string.profile_applist_title));
+ shortcutNames.add(mParent.getString(R.string.picker_activities));
+ bundle.putStringArrayList(Intent.EXTRA_SHORTCUT_NAME, shortcutNames);
+
+ ArrayList<ShortcutIconResource> shortcutIcons = new ArrayList<ShortcutIconResource>();
+ if (icons != null) {
+ for (ShortcutIconResource s : icons) {
+ shortcutIcons.add(s);
+ }
+ }
+ shortcutIcons.add(ShortcutIconResource.fromContext(mParent, android.R.drawable.sym_def_app_icon));
+ shortcutIcons.add(ShortcutIconResource.fromContext(mParent, R.drawable.activities_icon));
+ bundle.putParcelableArrayList(Intent.EXTRA_SHORTCUT_ICON_RESOURCE, shortcutIcons);
+
+ Intent pickIntent = new Intent(Intent.ACTION_PICK_ACTIVITY);
+ pickIntent.putExtra(Intent.EXTRA_INTENT, new Intent(Intent.ACTION_CREATE_SHORTCUT));
+ pickIntent.putExtra(Intent.EXTRA_TITLE, mParent.getText(R.string.select_custom_app_title));
+ pickIntent.putExtras(bundle);
+ lastFragmentId = fragmentId;
+ startFragmentOrActivity(pickIntent, REQUEST_PICK_SHORTCUT);
+ }
+
+ private void startFragmentOrActivity(Intent pickIntent, int requestCode) {
+ if (lastFragmentId == 0) {
+ mParent.startActivityForResult(pickIntent, requestCode);
+ } else {
+ Fragment cFrag = mParent.getFragmentManager().findFragmentById(lastFragmentId);
+ if (cFrag != null) {
+ mParent.startActivityFromFragment(cFrag, pickIntent, requestCode);
+ }
+ }
+ }
+
+ private void processShortcut(final Intent intent, int requestCodeApplication, int requestCodeShortcut) {
+ // Handle case where user selected "Applications"
+ String applicationName = mParent.getString(R.string.profile_applist_title);
+ String application2name = mParent.getString(R.string.picker_activities);
+ String shortcutName = intent.getStringExtra(Intent.EXTRA_SHORTCUT_NAME);
+ if (applicationName != null && applicationName.equals(shortcutName)) {
+ Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
+ mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
+
+ Intent pickIntent = new Intent(Intent.ACTION_PICK_ACTIVITY);
+ pickIntent.putExtra(Intent.EXTRA_INTENT, mainIntent);
+ startFragmentOrActivity(pickIntent, requestCodeApplication);
+ } else if (application2name != null && application2name.equals(shortcutName)){
+ final List<PackageInfo> pInfos = mPackageManager.getInstalledPackages(PackageManager.GET_ACTIVITIES);
+ ExpandableListView appListView = new ExpandableListView(mParent);
+ AppExpandableAdapter appAdapter = new AppExpandableAdapter(pInfos, mParent);
+ appListView.setAdapter(appAdapter);
+ appListView.setOnChildClickListener(new ExpandableListView.OnChildClickListener() {
+ @Override
+ public boolean onChildClick(ExpandableListView parent, View v,
+ int groupPosition, int childPosition, long id) {
+ Intent shortIntent = new Intent(Intent.ACTION_MAIN);
+ String pkgName = ((GroupInfo)parent.getExpandableListAdapter().getGroup(groupPosition))
+ .info.packageName;
+ String actName = ((GroupInfo)parent.getExpandableListAdapter().getGroup(groupPosition))
+ .info.activities[childPosition].name;
+ shortIntent.setClassName(pkgName, actName);
+ completeSetCustomApp(shortIntent);
+ mAlertDialog.dismiss();
+ return true;
+ }
+ });
+ Builder builder = new Builder(mParent);
+ builder.setView(appListView);
+ mAlertDialog = builder.create();
+ mAlertDialog.setTitle(mParent.getString(R.string.select_custom_activity_title));
+ mAlertDialog.show();
+ mAlertDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
+ @Override
+ public void onCancel(DialogInterface dialog) {
+ mListener.shortcutPicked(null, null, false);
+ }
+ });
+ } else {
+ startFragmentOrActivity(intent, requestCodeShortcut);
+ }
+ }
+
+ public class AppExpandableAdapter extends BaseExpandableListAdapter {
+
+ ArrayList<GroupInfo> allList = new ArrayList<GroupInfo>();
+ final int groupPadding;
+
+ public class LabelCompare implements Comparator<GroupInfo>{
+ @Override
+ public int compare(GroupInfo item1, GroupInfo item2) {
+ String rank1 = item1.label.toLowerCase();
+ String rank2 = item2.label.toLowerCase();
+ int result = rank1.compareTo(rank2);
+ if(result == 0) {
+ return 0;
+ } else if(result < 0) {
+ return -1;
+ } else {
+ return +1;
+ }
+ }
+ }
+
+ class GroupInfo {
+ String label;
+ PackageInfo info;
+ GroupInfo (String l, PackageInfo p) {
+ label = l;
+ info = p;
+ }
+ }
+
+ public AppExpandableAdapter(List<PackageInfo> pInfos, Context context) {
+ for (PackageInfo i : pInfos) {
+ allList.add(new GroupInfo(i.applicationInfo.loadLabel(mPackageManager).toString(), i));
+ }
+ Collections.sort(allList, new LabelCompare());
+ groupPadding = context.getResources().getDimensionPixelSize(R.dimen.shortcut_picker_left_padding);
+ }
+
+ public String getChild(int groupPosition, int childPosition) {
+ return allList.get(groupPosition).info.activities[childPosition].name;
+ }
+
+ public long getChildId(int groupPosition, int childPosition) {
+ return childPosition;
+ }
+
+ public int getChildrenCount(int groupPosition) {
+ if (allList.get(groupPosition).info.activities != null) {
+ return allList.get(groupPosition).info.activities.length;
+ } else {
+ return 0;
+ }
+ }
+
+
+ public View getChildView(int groupPosition, int childPosition, boolean isLastChild,
+ View convertView, ViewGroup parent) {
+ if (convertView == null) {
+ convertView = View.inflate(mParent, android.R.layout.simple_list_item_1, null);
+ convertView.setPadding(groupPadding, 0, 0, 0);
+
+ }
+ TextView textView = (TextView)convertView.findViewById(android.R.id.text1);
+ textView.setText(getChild(groupPosition, childPosition).replaceFirst(allList.get(groupPosition).info.packageName + ".", ""));
+ return convertView;
+ }
+
+ public GroupInfo getGroup(int groupPosition) {
+ return allList.get(groupPosition);
+ }
+
+ public int getGroupCount() {
+ return allList.size();
+ }
+
+ public long getGroupId(int groupPosition) {
+ return groupPosition;
+ }
+
+ public View getGroupView(int groupPosition, boolean isExpanded, View convertView,
+ ViewGroup parent) {
+ if (convertView == null) {
+ convertView = View.inflate(mParent, android.R.layout.simple_list_item_1, null);
+ convertView.setPadding(groupPadding, 0, 0, 0);
+ }
+ TextView textView = (TextView)convertView.findViewById(android.R.id.text1);
+ textView.setText(getGroup(groupPosition).label);
+ return convertView;
+ }
+
+ public boolean isChildSelectable(int groupPosition, int childPosition) {
+ return true;
+ }
+
+ public boolean hasStableIds() {
+ return true;
+ }
+
+ }
+
+ private void completeSetCustomApp(Intent data) {
+ mListener.shortcutPicked(data.toUri(0), getFriendlyActivityName(data, false, mPackageManager), true);
+ }
+
+ private void completeSetCustomShortcut(Intent data) {
+ Intent intent = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_INTENT);
+ /* preserve shortcut name, we want to restore it later */
+ intent.putExtra(Intent.EXTRA_SHORTCUT_NAME, data.getStringExtra(Intent.EXTRA_SHORTCUT_NAME));
+ String appUri = intent.toUri(0);
+ appUri = appUri.replaceAll("com.android.contacts.action.QUICK_CONTACT", "android.intent.action.VIEW");
+ mListener.shortcutPicked(appUri, getFriendlyShortcutName(intent, mPackageManager), false);
+ }
+
+ private static String getFriendlyActivityName(Intent intent, boolean labelOnly, PackageManager packageManager) {
+ ActivityInfo ai = intent.resolveActivityInfo(packageManager, PackageManager.GET_ACTIVITIES);
+ String friendlyName = null;
+ if (ai != null) {
+ friendlyName = ai.loadLabel(packageManager).toString();
+ if (friendlyName == null && !labelOnly) {
+ friendlyName = ai.name;
+ }
+ }
+ return friendlyName != null || labelOnly ? friendlyName : intent.toUri(0);
+ }
+
+ private static String getFriendlyShortcutName(Intent intent, PackageManager packageManager) {
+ String activityName = getFriendlyActivityName(intent, true, packageManager);
+ String name = intent.getStringExtra(Intent.EXTRA_SHORTCUT_NAME);
+
+ if (activityName != null && name != null) {
+ return activityName + ": " + name;
+ }
+ return name != null ? name : intent.toUri(0);
+ }
+
+ public static String getFriendlyNameForUri(String uri, PackageManager packageManager) {
+ if (uri == null) {
+ return null;
+ }
+
+ try {
+ Intent intent = Intent.parseUri(uri, 0);
+ if (Intent.ACTION_MAIN.equals(intent.getAction())) {
+ return getFriendlyActivityName(intent, false, packageManager);
+ }
+ return getFriendlyShortcutName(intent, packageManager);
+ } catch (URISyntaxException e) {
+ }
+
+ return uri;
+ }
+} \ No newline at end of file
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
index 632a867..fca6318 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
@@ -336,6 +336,10 @@ public class AccessPoint implements Comparable<AccessPoint> {
return str;
}
+ public int getNetworkId() {
+ return networkId;
+ }
+
public String getConfigName() {
if (mConfig != null && mConfig.isPasspoint()) {
return mConfig.providerFriendlyName;
@@ -640,12 +644,7 @@ public class AccessPoint implements Comparable<AccessPoint> {
} else if (config != null) {
return matches(config);
}
- else {
- // Might be an ephemeral connection with no WifiConfiguration. Try matching on SSID.
- // (Note that we only do this if the WifiConfiguration explicitly equals INVALID).
- // TODO: Handle hex string SSIDs.
- return ssid.equals(removeDoubleQuotes(info.getSSID()));
- }
+ return false;
}
public boolean isSaved() {
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
index c28288e..4f51137 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
@@ -319,7 +319,7 @@ public class WifiTracker {
if (config.selfAdded && config.numAssociation == 0) {
continue;
}
- AccessPoint accessPoint = getCachedOrCreate(config, cachedAccessPoints);
+ AccessPoint accessPoint = new AccessPoint(mContext, config);
if (mLastInfo != null && mLastNetworkInfo != null) {
if (config.isPasspoint() == false) {
accessPoint.update(connectionConfig, mLastInfo, mLastNetworkInfo);
diff --git a/packages/SettingsProvider/Android.mk b/packages/SettingsProvider/Android.mk
index 2b833b2..9c7bcb3 100644
--- a/packages/SettingsProvider/Android.mk
+++ b/packages/SettingsProvider/Android.mk
@@ -7,7 +7,7 @@ LOCAL_SRC_FILES := $(call all-subdir-java-files) \
src/com/android/providers/settings/EventLogTags.logtags
LOCAL_JAVA_LIBRARIES := telephony-common ims-common
-
+LOCAL_STATIC_JAVA_LIBRARIES := org.cyanogenmod.platform.sdk
LOCAL_PACKAGE_NAME := SettingsProvider
LOCAL_CERTIFICATE := platform
LOCAL_PRIVILEGED_MODULE := true
diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml
index 1cd2908..d841573 100644
--- a/packages/SettingsProvider/res/values/defaults.xml
+++ b/packages/SettingsProvider/res/values/defaults.xml
@@ -28,6 +28,13 @@
<bool name="def_auto_time">true</bool>
<bool name="def_auto_time_zone">true</bool>
<bool name="def_accelerometer_rotation">true</bool>
+ <!-- Bitmask of allowed display rotation angles:
+ ROTATION_0_MODE: 1
+ ROTATION_90_MODE: 2
+ ROTATION_180_MODE: 4
+ ROTATION_270_MODE: 8
+ Default to 0, 90, 270. -->
+ <integer name="def_accelerometer_rotation_angles">11</integer>
<!-- Default screen brightness, from 0 to 255. 102 is 40%. -->
<integer name="def_screen_brightness">102</integer>
<bool name="def_screen_brightness_automatic_mode">false</bool>
@@ -192,6 +199,9 @@
<!-- Default for Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS -->
<bool name="def_lock_screen_allow_private_notifications">true</bool>
+ <!-- Default for Settings.Global.SEND_ACTION_APP_ERROR -->
+ <integer name="def_send_action_app_error">0</integer>
+
<!-- Default for Settings.Global.HEADS_UP_NOTIFICATIONS_ENABLED, 1==on -->
<integer name="def_heads_up_enabled">1</integer>
@@ -212,4 +222,13 @@
<!-- Default for Settings.Secure.NFC_PAYMENT_COMPONENT -->
<string name="def_nfc_payment_component"></string>
+
+ <!-- Default for Settings.System.STATUS_BAR_NOTIF_COUNT. -->
+ <integer name="def_notif_count">0</integer>
+
+ <!-- Default protected sms originating address values of Settings.Secure.PROTECTED_SMS_ADDRESSES -->
+ <string-array name="def_protected_sms_list_values"></string-array>
+
+ <!-- Default for Settings.Global.CAPTIVE_PORTAL_DETECTION_ENABLED -->
+ <integer name="def_captive_portal_detection_enabled" translatable="false">1</integer>
</resources>
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index 5a14967..3af1d36 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -23,6 +23,7 @@ import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
+import android.content.res.ThemeConfig;
import android.content.res.XmlResourceParser;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
@@ -40,6 +41,7 @@ import android.os.UserHandle;
import android.provider.Settings;
import android.provider.Settings.Global;
import android.provider.Settings.Secure;
+import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.Log;
@@ -51,11 +53,13 @@ import com.android.internal.util.XmlUtils;
import com.android.internal.widget.LockPatternUtils;
import com.android.internal.widget.LockPatternView;
+import cyanogenmod.providers.CMSettings;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import java.io.File;
import java.io.IOException;
+import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@@ -80,7 +84,7 @@ class DatabaseHelper extends SQLiteOpenHelper {
// database gets upgraded properly. At a minimum, please confirm that 'upgradeVersion'
// is properly propagated through your change. Not doing so will result in a loss of user
// settings.
- private static final int DATABASE_VERSION = 118;
+ private static final int DATABASE_VERSION = 125;
private Context mContext;
private int mUserHandle;
@@ -1388,6 +1392,7 @@ class DatabaseHelper extends SQLiteOpenHelper {
if (upgradeVersion == 88) {
if (mUserHandle == UserHandle.USER_OWNER) {
db.beginTransaction();
+ SQLiteStatement stmt = null;
try {
String[] settingsToMove = {
Settings.Global.BATTERY_DISCHARGE_DURATION_THRESHOLD,
@@ -1407,7 +1412,6 @@ class DatabaseHelper extends SQLiteOpenHelper {
Settings.Global.SYS_STORAGE_FULL_THRESHOLD_BYTES,
Settings.Global.SYNC_MAX_RETRY_DELAY_IN_SECONDS,
Settings.Global.CONNECTIVITY_CHANGE_DELAY,
- Settings.Global.CAPTIVE_PORTAL_DETECTION_ENABLED,
Settings.Global.CAPTIVE_PORTAL_SERVER,
Settings.Global.NSD_ON,
Settings.Global.SET_INSTALL_LOCATION,
@@ -1423,9 +1427,16 @@ class DatabaseHelper extends SQLiteOpenHelper {
Settings.Global.DEFAULT_DNS_SERVER,
};
moveSettingsToNewTable(db, TABLE_SECURE, TABLE_GLOBAL, settingsToMove, true);
+
+ stmt = db.compileStatement("INSERT OR REPLACE INTO global(name,value)"
+ + " VALUES(?,?);");
+ loadIntegerSetting(stmt, Settings.Global.CAPTIVE_PORTAL_DETECTION_ENABLED,
+ R.integer.def_captive_portal_detection_enabled);
+ stmt.close();
db.setTransactionSuccessful();
} finally {
db.endTransaction();
+ if (stmt != null) stmt.close();
}
}
upgradeVersion = 89;
@@ -1871,9 +1882,34 @@ class DatabaseHelper extends SQLiteOpenHelper {
upgradeVersion = 113;
}
- // We skipped 114 to handle a merge conflict with the introduction of theater mode.
+ // We skipped 114 to handle a merge conflict with the introduction of theater mode. Except
+ // in CM we didn't, soooooo...
+ if (upgradeVersion < 114) {
+ // Artificially bump our upgrade version to handle
+ // migration path from cm-11.0 to cm-12.0
+ // without this, heads up would never work if
+ // a user did not wipe data
+ /** CM-13, this option was moved to CMSettings, artificially bump, skip default load.**/
+// upgradeHeadsUpSettingFromNone(db);
+// upgradeDeviceNameFromNone(db);
+
+ // Removal of back/recents is no longer supported
+ // due to pinned apps
+ db.beginTransaction();
+ try {
+ db.execSQL("DELETE FROM system WHERE name='"
+ + CMSettings.System.NAV_BUTTONS + "'");
+ db.setTransactionSuccessful();
+ } finally {
+ db.endTransaction();
+ }
+
+ upgradeVersion = 114;
+ }
if (upgradeVersion < 115) {
+ moveSettingsToNewTable(db, TABLE_SYSTEM, TABLE_SECURE,
+ new String[] { CMSettings.Secure.STATS_COLLECTION }, true);
if (mUserHandle == UserHandle.USER_OWNER) {
db.beginTransaction();
SQLiteStatement stmt = null;
@@ -1892,6 +1928,8 @@ class DatabaseHelper extends SQLiteOpenHelper {
}
if (upgradeVersion < 116) {
+ moveSettingsToNewTable(db, TABLE_SYSTEM, TABLE_SECURE,
+ new String[]{CMSettings.Secure.VOLUME_LINK_NOTIFICATION}, true);
if (mUserHandle == UserHandle.USER_OWNER) {
db.beginTransaction();
SQLiteStatement stmt = null;
@@ -1920,10 +1958,44 @@ class DatabaseHelper extends SQLiteOpenHelper {
} finally {
db.endTransaction();
}
+
+ // CM11 used "holo" as a system default theme. For CM12 and up its been
+ // switched to "system". So change all "holo" references in themeConfig to "system"
+ final String NAME_THEME_CONFIG = "themeConfig";
+ Cursor c = null;
+ try {
+ String[] projection = new String[]{"value"};
+ String selection = "name=?";
+ String[] selectionArgs = new String[] { NAME_THEME_CONFIG };
+ c = db.query(TABLE_SECURE, projection, selection,
+ selectionArgs, null, null, null);
+ if (c != null && c.moveToFirst()) {
+ String jsonConfig = c.getString(0);
+ if (jsonConfig != null) {
+ jsonConfig = jsonConfig.replace(
+ "\"holo\"", '"' + ThemeConfig.SYSTEM_DEFAULT + '"');
+
+ // Now update the entry
+ SQLiteStatement stmt = db.compileStatement(
+ "UPDATE " + TABLE_SECURE + " SET value = ? "
+ + " WHERE name = ?");
+ stmt.bindString(1, jsonConfig);
+ stmt.bindString(2, NAME_THEME_CONFIG);
+ stmt.execute();
+ }
+ }
+ } finally {
+ if (c != null) c.close();
+ }
upgradeVersion = 117;
}
if (upgradeVersion < 118) {
+ String[] settingsToMove = new String[] {
+ CMSettings.Secure.QS_SHOW_BRIGHTNESS_SLIDER,
+ };
+ moveSettingsToNewTable(db, TABLE_SYSTEM, TABLE_SECURE,
+ settingsToMove, true);
// Reset rotation-lock-for-accessibility on upgrade, since it now hides the display
// setting.
db.beginTransaction();
@@ -1940,6 +2012,110 @@ class DatabaseHelper extends SQLiteOpenHelper {
upgradeVersion = 118;
}
+ /** CM-13 CHANGES -- THIS IS TO SUPPORT LEGACY UPGRADES, DO NOT ADD ANY NEW DEFAULTS HERE
+ * INSTEAD UTILIZE THE CMSETTINGS PROVIDER
+ */
+ if (upgradeVersion == 119) {
+ /** CM-13, this option was moved to CMSettings, artificially bump, skip default load.**/
+// db.beginTransaction();
+// SQLiteStatement stmt = null;
+// try {
+// stmt = db.compileStatement("INSERT OR IGNORE INTO secure(name,value) VALUES(?,?);");
+// loadDefaultThemeSettings(stmt);
+// db.setTransactionSuccessful();
+// } finally {
+// db.endTransaction();
+// if (stmt != null) stmt.close();
+// }
+ upgradeVersion = 120;
+ }
+
+ if (upgradeVersion < 121) {
+ String[] settingsToMove = CMSettings.Secure.NAVIGATION_RING_TARGETS;
+
+ moveSettingsToNewTable(db, TABLE_SYSTEM, TABLE_SECURE,
+ settingsToMove, true);
+ upgradeVersion = 121;
+ }
+
+ if (upgradeVersion < 122) {
+ /** CM-13, this option was moved to CMSettings, artificially bump, skip default load.**/
+// db.beginTransaction();
+// SQLiteStatement stmt = null;
+// try {
+// stmt = db.compileStatement("INSERT OR IGNORE INTO secure(name,value)"
+// + " VALUES(?,?);");
+// loadBooleanSetting(stmt, CMSettings.Secure.ADVANCED_MODE,
+// com.android.internal.R.bool.config_advancedSettingsMode);
+// db.setTransactionSuccessful();
+// } finally {
+// db.endTransaction();
+// if (stmt != null) stmt.close();
+// }
+ upgradeVersion = 122;
+ }
+
+ if (upgradeVersion < 123) {
+ // only the owner has access to global table, so we need to check that here
+ if (mUserHandle == UserHandle.USER_OWNER) {
+ String[] globalToSecure = new String[] { CMSettings.Secure.POWER_MENU_ACTIONS };
+
+ moveSettingsToNewTable(db, TABLE_GLOBAL, TABLE_SECURE, globalToSecure, true);
+ }
+
+ String[] systemToSecure = new String[] {
+ CMSettings.Secure.DEV_FORCE_SHOW_NAVBAR,
+ CMSettings.Secure.KEYBOARD_BRIGHTNESS,
+ CMSettings.Secure.BUTTON_BRIGHTNESS,
+ CMSettings.Secure.BUTTON_BACKLIGHT_TIMEOUT
+ };
+ moveSettingsToNewTable(db, TABLE_SYSTEM, TABLE_SECURE, systemToSecure, true);
+
+ upgradeVersion = 123;
+ }
+
+ if (upgradeVersion < 124) {
+ // Migrate from cm-12.0 if there is no entry from cm-11.0
+ /** CM-13, this option was moved to CMSettings, artificially bump, skip default load.**/
+// db.beginTransaction();
+// SQLiteStatement stmt = null;
+// try {
+// stmt = db.compileStatement("INSERT OR IGNORE INTO secure(name,value)"
+// + " VALUES(?,?);");
+// int quickPulldown = getIntValueFromSystem(db,
+// CMSettings.System.STATUS_BAR_QUICK_QS_PULLDOWN,
+// R.integer.def_qs_quick_pulldown);
+// loadSetting(stmt, CMSettings.System.QS_QUICK_PULLDOWN, quickPulldown);
+// db.setTransactionSuccessful();
+// } finally {
+// db.endTransaction();
+// if (stmt != null) stmt.close();
+// }
+ upgradeVersion = 124;
+ }
+
+ if (upgradeVersion < 125) {
+ // Force enable advanced settings if the overlay defaults to true
+ /** CM-13, this option was moved to CMSettings, artificially bump, skip default load.**/
+// if (mContext.getResources().getBoolean(
+// com.android.internal.R.bool.config_advancedSettingsMode)) {
+// db.beginTransaction();
+// SQLiteStatement stmt = null;
+// try {
+// stmt = db.compileStatement("INSERT OR REPLACE INTO secure(name,value)"
+// + " VALUES(?,?);");
+// loadBooleanSetting(stmt, CMSettings.Secure.ADVANCED_MODE,
+// com.android.internal.R.bool.config_advancedSettingsMode);
+// db.setTransactionSuccessful();
+// } finally {
+// db.endTransaction();
+// if (stmt != null) stmt.close();
+// }
+// }
+ upgradeVersion = 125;
+ }
+ /** END CM-13 CHANGES */
+
/*
* IMPORTANT: Do not add any more upgrade steps here as the global,
* secure, and system settings are no longer stored in a database
@@ -2340,6 +2516,16 @@ class DatabaseHelper extends SQLiteOpenHelper {
}
}
+ private void loadProtectedSmsSetting(SQLiteStatement stmt) {
+ String[] regAddresses = mContext.getResources()
+ .getStringArray(R.array.def_protected_sms_list_values);
+ if (regAddresses.length > 0) {
+ loadSetting(stmt,
+ Settings.Secure.PROTECTED_SMS_ADDRESSES,
+ TextUtils.join("|", regAddresses));
+ }
+ }
+
private void loadSettings(SQLiteDatabase db) {
loadSystemSettings(db);
loadSecureSettings(db);
@@ -2380,6 +2566,9 @@ class DatabaseHelper extends SQLiteOpenHelper {
loadBooleanSetting(stmt, Settings.System.ACCELEROMETER_ROTATION,
R.bool.def_accelerometer_rotation);
+ loadIntegerSetting(stmt, Settings.System.ACCELEROMETER_ROTATION_ANGLES,
+ R.integer.def_accelerometer_rotation_angles);
+
loadDefaultHapticSettings(stmt);
loadBooleanSetting(stmt, Settings.System.NOTIFICATION_LIGHT_PULSE,
@@ -2684,13 +2873,37 @@ class DatabaseHelper extends SQLiteOpenHelper {
// Set the preferred network mode to target desired value or Default
// value defined in RILConstants
- int type;
- type = RILConstants.PREFERRED_NETWORK_MODE;
- loadSetting(stmt, Settings.Global.PREFERRED_NETWORK_MODE, type);
+ int phoneCount = TelephonyManager.getDefault().getPhoneCount();
+ final String defVal = SystemProperties.get("ro.telephony.default_network", "");
+ final String[] defNetworkSettings = defVal.split(",");
+ final String[] networkSettings = new String[phoneCount];
+ boolean error = defNetworkSettings.length != phoneCount;
+
+ for (int i = 0; i < phoneCount; i++) {
+ if (i < defNetworkSettings.length) {
+ try {
+ networkSettings[i] = String.valueOf(
+ Integer.parseInt(defNetworkSettings[i]));
+ } catch (NumberFormatException ex) {
+ networkSettings[i] = String.valueOf(RILConstants.PREFERRED_NETWORK_MODE);
+ error = true;
+ }
+ } else {
+ networkSettings[i] = String.valueOf(RILConstants.PREFERRED_NETWORK_MODE);
+ error = true;
+ }
+ }
+
+ if (error) {
+ Log.w(TAG, "Invalid ro.telephony.default_network: " + defVal);
+ }
+
+ loadSetting(stmt, Settings.Global.PREFERRED_NETWORK_MODE, TextUtils.join(",",
+ networkSettings));
// Set the preferred cdma subscription source to target desired value or default
// value defined in CdmaSubscriptionSourceManager
- type = SystemProperties.getInt("ro.telephony.default_cdma_sub",
+ int type = SystemProperties.getInt("ro.telephony.default_cdma_sub",
CdmaSubscriptionSourceManager.PREFERRED_CDMA_SUBSCRIPTION);
loadSetting(stmt, Settings.Global.CDMA_SUBSCRIPTION_MODE, type);
@@ -2705,11 +2918,13 @@ class DatabaseHelper extends SQLiteOpenHelper {
loadSetting(stmt, Settings.Global.DEVICE_NAME, getDefaultDeviceName());
+ loadIntegerSetting(stmt, Settings.Global.SEND_ACTION_APP_ERROR,
+ R.integer.def_send_action_app_error);
+
loadBooleanSetting(stmt, Settings.Global.GUEST_USER_ENABLED,
R.bool.def_guest_user_enabled);
loadSetting(stmt, Settings.Global.ENHANCED_4G_MODE_ENABLED,
ImsConfig.FeatureValueConstants.ON);
-
/*
* IMPORTANT: Do not add any more upgrade steps here as the global,
* secure, and system settings are no longer stored in a database
@@ -2717,6 +2932,8 @@ class DatabaseHelper extends SQLiteOpenHelper {
*
* See: SettingsProvider.UpgradeController#onUpgradeLocked
*/
+ loadIntegerSetting(stmt, Settings.Global.CAPTIVE_PORTAL_DETECTION_ENABLED,
+ R.integer.def_captive_portal_detection_enabled);
} finally {
if (stmt != null) stmt.close();
}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
index b9a9c24..b4543b3 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
@@ -36,8 +36,10 @@ import android.os.UserHandle;
import android.provider.Settings;
import android.util.Log;
+import com.android.internal.util.ArrayUtils;
import com.android.internal.widget.LockPatternUtils;
+import cyanogenmod.providers.CMSettings;
import libcore.io.IoUtils;
import java.io.BufferedOutputStream;
@@ -255,13 +257,13 @@ public class SettingsBackupAgent extends BackupAgentHelper {
// Now build the canonical config key paralleling the WifiConfiguration semantics
final String key;
if (types.get(KeyMgmt.WPA_PSK)) {
- key = bareSsid + KeyMgmt.strings[KeyMgmt.WPA_PSK];
+ key = bareSsid + "-" + KeyMgmt.strings[KeyMgmt.WPA_PSK];
} else if (types.get(KeyMgmt.WPA_EAP) || types.get(KeyMgmt.IEEE8021X)) {
- key = bareSsid + KeyMgmt.strings[KeyMgmt.WPA_EAP];
+ key = bareSsid + "-" + KeyMgmt.strings[KeyMgmt.WPA_EAP];
} else if (hasWepKey) {
- key = bareSsid + "WEP"; // hardcoded this way in WifiConfiguration
+ key = bareSsid + "-WEP"; // hardcoded this way in WifiConfiguration
} else {
- key = bareSsid + KeyMgmt.strings[KeyMgmt.NONE];
+ key = bareSsid + "-" + KeyMgmt.strings[KeyMgmt.NONE];
}
return key;
}
@@ -883,6 +885,37 @@ public class SettingsBackupAgent extends BackupAgentHelper {
Log.d(TAG, "Restored setting: " + destination + " : "+ key + "=" + value);
}
}
+
+ restoreCMSetting(cachedEntries);
+ }
+
+ private void restoreCMSetting(Map<String, String> cachedEntries) {
+ ContentValues cmSettingsValues = new ContentValues();
+ ContentResolver cr = getContentResolver();
+ for (String key : cachedEntries.keySet()) {
+ Uri uri = null;
+ if (ArrayUtils.contains(CMSettings.System.LEGACY_SYSTEM_SETTINGS, key)) {
+ uri = CMSettings.System.CONTENT_URI;
+ } else if (ArrayUtils.contains(CMSettings.Secure.LEGACY_SECURE_SETTINGS, key)) {
+ uri = CMSettings.Secure.CONTENT_URI;
+ } else if (ArrayUtils.contains(CMSettings.Global.LEGACY_GLOBAL_SETTINGS, key)) {
+ uri = CMSettings.Global.CONTENT_URI;
+ }
+ if (uri != null) {
+ String value = cachedEntries.get(key);
+ cmSettingsValues.clear();
+ cmSettingsValues.put(Settings.NameValueTable.NAME, key);
+ cmSettingsValues.put(Settings.NameValueTable.VALUE, value);
+ try {
+ cr.insert(uri, cmSettingsValues);
+ if (DEBUG) {
+ Log.d(TAG, "Restored cm setting: " + key + " : " + key + "=" + value);
+ }
+ } catch (IllegalArgumentException e) {
+ Log.e(TAG, "Failed to migrate " + key + " due to " + e.toString());
+ }
+ }
+ }
}
/**
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 73971ad..3b5d578 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -1856,6 +1856,7 @@ public class SettingsProvider extends ContentProvider {
private final class UpgradeController {
private static final int SETTINGS_VERSION = 122;
+ private static final int CM_SETTINGS_DB_VERSION = 125;
private final int mUserId;
@@ -1869,11 +1870,11 @@ public class SettingsProvider extends ContentProvider {
SettingsRegistry.SETTINGS_TYPE_SECURE, mUserId);
// Try an update from the current state.
- final int oldVersion = secureSettings.getVersionLocked();
+ final int oldVersion = secureSettings.getVersionLocked(); //125
final int newVersion = SETTINGS_VERSION;
// If up do date - done.
- if (oldVersion == newVersion) {
+ if ((oldVersion == newVersion || oldVersion == CM_SETTINGS_DB_VERSION)) {
return;
}
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index b9daf59..f31b19f 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -48,6 +48,8 @@
<uses-permission android:name="android.permission.SET_PREFERRED_APPLICATIONS" />
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
+ <uses-permission android:name="cyanogenmod.permission.WRITE_SETTINGS" />
+ <uses-permission android:name="cyanogenmod.permission.WRITE_SECURE_SETTINGS" />
<uses-permission android:name="android.permission.BROADCAST_STICKY" />
<!-- Development tool permissions granted to the shell. -->
<uses-permission android:name="android.permission.SET_DEBUG_APP" />
@@ -98,7 +100,6 @@
<uses-permission android:name="android.permission.BIND_APPWIDGET" />
<uses-permission android:name="android.permission.UPDATE_APP_OPS_STATS" />
<uses-permission android:name="android.permission.MODIFY_APPWIDGET_BIND_PERMISSIONS"/>
- <uses-permission android:name="android.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS" />
<uses-permission android:name="android.permission.CHANGE_APP_IDLE_STATE" />
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
<uses-permission android:name="android.permission.MOUNT_FORMAT_FILESYSTEMS" />
@@ -107,6 +108,7 @@
<uses-permission android:name="android.permission.REGISTER_CONNECTION_MANAGER" />
<uses-permission android:name="android.permission.REGISTER_SIM_SUBSCRIPTION" />
<uses-permission android:name="android.permission.GET_APP_OPS_STATS" />
+ <uses-permission android:name="android.permission.ACCESS_THEME_MANAGER" />
<application android:label="@string/app_label">
<provider
@@ -142,6 +144,7 @@
android:name=".BugreportReceiver"
android:permission="android.permission.DUMP">
<intent-filter>
+ <action android:name="android.intent.action.BUGREPORT_STARTED" />
<action android:name="android.intent.action.BUGREPORT_FINISHED" />
</intent-filter>
</receiver>
diff --git a/packages/Shell/res/values/cm_strings.xml b/packages/Shell/res/values/cm_strings.xml
new file mode 100644
index 0000000..0d81dd6
--- /dev/null
+++ b/packages/Shell/res/values/cm_strings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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.
+-->
+<resources>
+ <!-- Text to let user know a bug report is currently being collected -->
+ <string name="notification_bug_report_active_title">Collecting bug report\u2026</string>
+ <string name="notification_bug_report_active_text">Please wait a few minutes</string>
+</resources>
diff --git a/packages/Shell/src/com/android/shell/BugreportReceiver.java b/packages/Shell/src/com/android/shell/BugreportReceiver.java
index d83b516..6e39111 100644
--- a/packages/Shell/src/com/android/shell/BugreportReceiver.java
+++ b/packages/Shell/src/com/android/shell/BugreportReceiver.java
@@ -65,6 +65,8 @@ public class BugreportReceiver extends BroadcastReceiver {
private static final String EXTRA_BUGREPORT = "android.intent.extra.BUGREPORT";
private static final String EXTRA_SCREENSHOT = "android.intent.extra.SCREENSHOT";
+ public static final String ACTION_BUGREPORT_STARTED = "android.intent.action.BUGREPORT_STARTED";
+
/**
* Always keep the newest 8 bugreport files; 4 reports and 4 screenshots are
* roughly 17MB of disk space.
@@ -79,6 +81,19 @@ public class BugreportReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
final Configuration conf = context.getResources().getConfiguration();
+ if (ACTION_BUGREPORT_STARTED.equals(intent.getAction())) {
+ Notification.Builder builder = new Notification.Builder(context)
+ .setSmallIcon(com.android.internal.R.drawable.stat_sys_adb)
+ .setOngoing(true)
+ .setProgress(0, 0, true)
+ .setContentTitle(context
+ .getString(R.string.notification_bug_report_active_title))
+ .setContentText(context
+ .getString(R.string.notification_bug_report_active_text));
+ NotificationManager.from(context).notify(TAG, 0, builder.build());
+ return;
+ }
+
final File bugreportFile = getFileExtra(intent, EXTRA_BUGREPORT);
final File screenshotFile = getFileExtra(intent, EXTRA_SCREENSHOT);
diff --git a/packages/SystemUI/Android.mk b/packages/SystemUI/Android.mk
index 51fea2a..49fe595 100644
--- a/packages/SystemUI/Android.mk
+++ b/packages/SystemUI/Android.mk
@@ -6,8 +6,13 @@ LOCAL_MODULE_TAGS := optional
LOCAL_SRC_FILES := $(call all-java-files-under, src) \
src/com/android/systemui/EventLogTags.logtags
-LOCAL_STATIC_JAVA_LIBRARIES := Keyguard
+LOCAL_STATIC_JAVA_LIBRARIES := Keyguard \
+ org.cyanogenmod.platform.sdk \
+ android-support-v7-palette \
+ android-support-v4
+
LOCAL_JAVA_LIBRARIES := telephony-common
+LOCAL_FULL_LIBS_MANIFEST_FILES := $(LOCAL_PATH)/AndroidManifest_cm.xml
LOCAL_PACKAGE_NAME := SystemUI
LOCAL_CERTIFICATE := platform
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 80f4d4c..52cb1d9 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -41,7 +41,6 @@
<uses-permission android:name="android.permission.MANAGE_USERS" />
<uses-permission android:name="android.permission.READ_PROFILE" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
- <uses-permission android:name="android.permission.CONFIGURE_WIFI_DISPLAY" />
<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
<uses-permission android:name="android.permission.GET_APP_OPS_STATS" />
@@ -50,6 +49,7 @@
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.BLUETOOTH_PRIVILEGED" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
+ <uses-permission android:name="android.permission.ACCESS_BLUETOOTH_AVRCP_CT_DATA" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
<uses-permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE" />
@@ -135,6 +135,15 @@
android:protectionLevel="signature" />
<uses-permission android:name="com.android.systemui.permission.SELF" />
+ <!-- LiveDisplay -->
+ <uses-permission android:name="android.permission.HARDWARE_ABSTRACTION_ACCESS" />
+
+ <!-- Weather -->
+ <uses-permission android:name="com.cyanogenmod.lockclock.permission.READ_WEATHER" />
+
+ <!-- blur surface -->
+ <uses-permission android:name="android.permission.ACCESS_SURFACE_FLINGER" />
+
<application
android:name=".SystemUIApplication"
android:persistent="true"
@@ -397,6 +406,20 @@
</intent-filter>
</activity>
+ <activity
+ android:name=".settings.NotificationBrightnessDialog"
+ android:label="@string/quick_settings_brightness_dialog_title"
+ android:theme="@android:style/Theme.DeviceDefault.Dialog"
+ android:finishOnCloseSystemDialogs="true"
+ android:launchMode="singleInstance"
+ android:excludeFromRecents="true"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.SHOW_NOTIFICATION_BRIGHTNESS_DIALOG" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ </activity>
+
<!-- Doze with notifications, run in main sysui process for every user -->
<service
android:name=".doze.DozeService"
@@ -411,5 +434,6 @@
<action android:name="com.android.systemui.action.CLEAR_TUNER" />
</intent-filter>
</receiver>
+
</application>
</manifest>
diff --git a/packages/SystemUI/AndroidManifest_cm.xml b/packages/SystemUI/AndroidManifest_cm.xml
new file mode 100644
index 0000000..187d3dc
--- /dev/null
+++ b/packages/SystemUI/AndroidManifest_cm.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (c) 2015 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.
+ */
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.systemui">
+
+ <uses-permission android:name="cyanogenmod.permission.WRITE_SETTINGS" />
+ <uses-permission android:name="cyanogenmod.permission.WRITE_SECURE_SETTINGS" />
+ <!-- Quick Settings Tile Listener -->
+ <uses-permission android:name="cyanogenmod.permission.BIND_CUSTOM_TILE_LISTENER_SERVICE"/>
+
+ <!-- Development shortcut -->
+ <uses-permission android:name="android.permission.CLEAR_APP_USER_DATA" />
+ <uses-permission android:name="android.permission.FORCE_STOP_PACKAGES" />
+
+ <application>
+ <provider android:name=".cm.SpamMessageProvider"
+ android:permission="android.permission.INTERACT_ACROSS_USERS_FULL"
+ android:exported="true"
+ android:authorities="com.cyanogenmod.spam" />
+
+ <activity
+ android:name=".cm.LockscreenShortcutsActivity"
+ android:icon="@drawable/tuner"
+ android:label="@string/lockscreen_targets_message"
+ android:theme="@android:style/Theme.Material.Settings"
+ android:process=":cmsettings"
+ android:exported="true">
+ </activity>
+ </application>
+</manifest>
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_mini_settings.png b/packages/SystemUI/res/drawable-hdpi/ic_mini_settings.png
new file mode 100755
index 0000000..4759a1c
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/ic_mini_settings.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_notification_overlay.9.png b/packages/SystemUI/res/drawable-hdpi/ic_notification_overlay.9.png
index a93916f..5bde6ef 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_notification_overlay.9.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_notification_overlay.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_add.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_add.png
new file mode 100644
index 0000000..66e0c12
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_add.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_add_land.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_add_land.png
new file mode 100644
index 0000000..63da6d2
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_add_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_add_side.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_add_side.png
new file mode 100644
index 0000000..956ebe4
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_add_side.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_side.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_side.png
new file mode 100644
index 0000000..0d12637
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_side.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_ime_left.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_ime_left.png
new file mode 100755
index 0000000..ad9ae23
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_ime_left.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_ime_right.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_ime_right.png
new file mode 100755
index 0000000..5324ad9
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_ime_right.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_menu_big.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_menu_big.png
new file mode 100644
index 0000000..5b30293
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_menu_big.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_menu_big_land.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_menu_big_land.png
new file mode 100644
index 0000000..99413a8
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_menu_big_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_recent_side.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_recent_side.png
new file mode 100644
index 0000000..24ad426
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_recent_side.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_search.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_search.png
new file mode 100644
index 0000000..b31c2c7
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_search.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_search_land.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_search_land.png
new file mode 100644
index 0000000..5ad767c
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_search_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_search_side.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_search_side.png
new file mode 100644
index 0000000..f8e9b08
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_search_side.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_notify_image.png b/packages/SystemUI/res/drawable-hdpi/stat_notify_image.png
deleted file mode 100644
index 7b0fcc7..0000000
--- a/packages/SystemUI/res/drawable-hdpi/stat_notify_image.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_notify_image_error.png b/packages/SystemUI/res/drawable-hdpi/stat_notify_image_error.png
deleted file mode 100644
index 73e9c96..0000000
--- a/packages/SystemUI/res/drawable-hdpi/stat_notify_image_error.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_idle_1x.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_idle_1x.png
new file mode 100644
index 0000000..818e292
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_idle_1x.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_idle_3g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_idle_3g.png
new file mode 100644
index 0000000..95866b1
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_idle_3g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_idle_4g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_idle_4g.png
new file mode 100644
index 0000000..1aea612
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_idle_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_idle_e.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_idle_e.png
new file mode 100644
index 0000000..016b30b
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_idle_e.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_idle_g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_idle_g.png
new file mode 100644
index 0000000..ec672eb
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_idle_g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_idle_h.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_idle_h.png
new file mode 100644
index 0000000..27bab73
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_idle_h.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_in_1x.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_in_1x.png
new file mode 100644
index 0000000..66fb60e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_in_1x.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_in_3g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_in_3g.png
new file mode 100644
index 0000000..07ea499
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_in_3g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_in_4g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_in_4g.png
new file mode 100644
index 0000000..879c703
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_in_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_in_e.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_in_e.png
new file mode 100644
index 0000000..e39767a
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_in_e.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_in_g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_in_g.png
new file mode 100644
index 0000000..47c1fca
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_in_g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_in_h.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_in_h.png
new file mode 100644
index 0000000..ac80dce
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_in_h.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_inandout_4g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_inandout_4g.png
new file mode 100644
index 0000000..c5edf2c
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_inandout_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_inandout_e.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_inandout_e.png
new file mode 100644
index 0000000..0ef4701
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_inandout_e.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_inandout_h.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_inandout_h.png
new file mode 100644
index 0000000..ed02984
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_inandout_h.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_inout_1x.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_inout_1x.png
new file mode 100644
index 0000000..f88091b
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_inout_1x.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_inout_3g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_inout_3g.png
new file mode 100644
index 0000000..95bb3cd
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_inout_3g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_inout_g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_inout_g.png
new file mode 100644
index 0000000..31b926b
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_inout_g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_out_1x.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_out_1x.png
new file mode 100644
index 0000000..0ee5b08
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_out_1x.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_out_3g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_out_3g.png
new file mode 100644
index 0000000..cac7802
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_out_3g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_out_4g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_out_4g.png
new file mode 100644
index 0000000..ddf88be
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_out_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_out_e.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_out_e.png
new file mode 100644
index 0000000..df6e195
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_out_e.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_out_g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_out_g.png
new file mode 100644
index 0000000..4a2f867
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_out_g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_out_h.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_out_h.png
new file mode 100644
index 0000000..2b4628f
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_out_h.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_no_sim_1.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_no_sim_1.png
new file mode 100644
index 0000000..fbcf293
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_no_sim_1.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_0_fully_sim1_4g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_0_fully_sim1_4g.png
new file mode 100644
index 0000000..ec1a23e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_0_fully_sim1_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_0_fully_sim1_hp.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_0_fully_sim1_hp.png
new file mode 100644
index 0000000..badc93d
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_0_fully_sim1_hp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_0_fully_sim2_4g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_0_fully_sim2_4g.png
new file mode 100644
index 0000000..24be336
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_0_fully_sim2_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_0_fully_sim2_hp.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_0_fully_sim2_hp.png
new file mode 100644
index 0000000..cee81b3
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_0_fully_sim2_hp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_0_sim1_4g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_0_sim1_4g.png
new file mode 100644
index 0000000..76bf51c
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_0_sim1_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_0_sim1_hp.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_0_sim1_hp.png
new file mode 100644
index 0000000..8f536d9
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_0_sim1_hp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_0_sim2_4g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_0_sim2_4g.png
new file mode 100644
index 0000000..222a65f
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_0_sim2_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_0_sim2_hp.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_0_sim2_hp.png
new file mode 100644
index 0000000..42c2b3c
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_0_sim2_hp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_1_fully_sim1_4g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_1_fully_sim1_4g.png
new file mode 100644
index 0000000..4dc30ee
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_1_fully_sim1_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_1_fully_sim1_hp.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_1_fully_sim1_hp.png
new file mode 100644
index 0000000..94dfff0
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_1_fully_sim1_hp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_1_fully_sim2_4g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_1_fully_sim2_4g.png
new file mode 100644
index 0000000..40c0972
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_1_fully_sim2_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_1_fully_sim2_hp.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_1_fully_sim2_hp.png
new file mode 100644
index 0000000..ab40c2f
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_1_fully_sim2_hp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_1_sim1_4g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_1_sim1_4g.png
new file mode 100644
index 0000000..74c614c
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_1_sim1_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_1_sim1_hp.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_1_sim1_hp.png
new file mode 100644
index 0000000..3130da3
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_1_sim1_hp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_1_sim2_4g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_1_sim2_4g.png
new file mode 100644
index 0000000..8a267f0
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_1_sim2_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_1_sim2_hp.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_1_sim2_hp.png
new file mode 100644
index 0000000..b3f07ba
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_1_sim2_hp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_2_fully_sim1_4g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_2_fully_sim1_4g.png
new file mode 100644
index 0000000..046714b
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_2_fully_sim1_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_2_fully_sim1_hp.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_2_fully_sim1_hp.png
new file mode 100644
index 0000000..acf7cfe
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_2_fully_sim1_hp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_2_fully_sim2_4g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_2_fully_sim2_4g.png
new file mode 100644
index 0000000..55f57d6
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_2_fully_sim2_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_2_fully_sim2_hp.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_2_fully_sim2_hp.png
new file mode 100644
index 0000000..659efb4
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_2_fully_sim2_hp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_2_sim1_4g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_2_sim1_4g.png
new file mode 100644
index 0000000..2135915
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_2_sim1_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_2_sim1_hp.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_2_sim1_hp.png
new file mode 100644
index 0000000..aed8179
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_2_sim1_hp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_2_sim2_4g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_2_sim2_4g.png
new file mode 100644
index 0000000..33c4abd
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_2_sim2_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_2_sim2_hp.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_2_sim2_hp.png
new file mode 100644
index 0000000..e76c53f
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_2_sim2_hp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_3_fully_sim1_4g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_3_fully_sim1_4g.png
new file mode 100644
index 0000000..97120a9
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_3_fully_sim1_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_3_fully_sim1_hp.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_3_fully_sim1_hp.png
new file mode 100644
index 0000000..ceb1c2c
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_3_fully_sim1_hp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_3_fully_sim2_4g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_3_fully_sim2_4g.png
new file mode 100644
index 0000000..f3419fd
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_3_fully_sim2_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_3_fully_sim2_hp.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_3_fully_sim2_hp.png
new file mode 100644
index 0000000..c5a0a60
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_3_fully_sim2_hp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_3_sim1_4g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_3_sim1_4g.png
new file mode 100644
index 0000000..ca418ca
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_3_sim1_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_3_sim1_hp.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_3_sim1_hp.png
new file mode 100644
index 0000000..a9a7191
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_3_sim1_hp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_3_sim2_4g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_3_sim2_4g.png
new file mode 100644
index 0000000..a8c6c32
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_3_sim2_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_3_sim2_hp.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_3_sim2_hp.png
new file mode 100644
index 0000000..bdf6790
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_3_sim2_hp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_4_fully_sim1_4g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_4_fully_sim1_4g.png
new file mode 100644
index 0000000..849796a
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_4_fully_sim1_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_4_fully_sim1_hp.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_4_fully_sim1_hp.png
new file mode 100644
index 0000000..0d55f93c
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_4_fully_sim1_hp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_4_fully_sim2_4g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_4_fully_sim2_4g.png
new file mode 100644
index 0000000..012eb8a
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_4_fully_sim2_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_4_fully_sim2_hp.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_4_fully_sim2_hp.png
new file mode 100644
index 0000000..978c284
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_4_fully_sim2_hp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_4_sim1_4g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_4_sim1_4g.png
new file mode 100644
index 0000000..7ee0c63
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_4_sim1_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_4_sim1_hp.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_4_sim1_hp.png
new file mode 100644
index 0000000..73c369f
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_4_sim1_hp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_4_sim2_4g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_4_sim2_4g.png
new file mode 100644
index 0000000..2479783
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_4_sim2_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_4_sim2_hp.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_4_sim2_hp.png
new file mode 100644
index 0000000..8503fbf
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_4_sim2_hp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_2g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_2g.png
new file mode 100644
index 0000000..79aabb7
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_2g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_2g_default.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_2g_default.png
new file mode 100644
index 0000000..750b8db
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_2g_default.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_2g_default_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_2g_default_fully.png
new file mode 100644
index 0000000..e9236b0
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_2g_default_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_2g_default_fully_roam.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_2g_default_fully_roam.png
new file mode 100755
index 0000000..3cf236d
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_2g_default_fully_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_2g_default_roam.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_2g_default_roam.png
new file mode 100755
index 0000000..9550ab5
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_2g_default_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_2g_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_2g_fully.png
new file mode 100644
index 0000000..6339bc3
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_2g_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_4g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_4g.png
new file mode 100755
index 0000000..f5f74f9
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_4g_default.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_4g_default.png
new file mode 100755
index 0000000..a33ac2e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_4g_default.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_4g_default_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_4g_default_fully.png
new file mode 100755
index 0000000..f572200
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_4g_default_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_4g_default_fully_roam.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_4g_default_fully_roam.png
new file mode 100755
index 0000000..44736da
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_4g_default_fully_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_4g_default_roam.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_4g_default_roam.png
new file mode 100755
index 0000000..c09a1c0
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_4g_default_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_4g_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_4g_fully.png
new file mode 100755
index 0000000..d5c25b3
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_4g_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_default_fully_roam.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_default_fully_roam.png
new file mode 100755
index 0000000..fb6cd9d
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_default_fully_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_default_roam.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_default_roam.png
new file mode 100755
index 0000000..fb6cd9d
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_default_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_e.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_e.png
new file mode 100755
index 0000000..651b1ad
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_e.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_e_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_e_fully.png
new file mode 100755
index 0000000..71059aa
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_e_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_e_fully_roam.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_e_fully_roam.png
new file mode 100755
index 0000000..ac814fd
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_e_fully_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_e_roam.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_e_roam.png
new file mode 100755
index 0000000..e8826aa
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_e_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_fully_sim1_4g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_fully_sim1_4g.png
new file mode 100644
index 0000000..68c871a
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_fully_sim1_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_fully_sim1_hp.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_fully_sim1_hp.png
new file mode 100644
index 0000000..11e32c0
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_fully_sim1_hp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_fully_sim2_4g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_fully_sim2_4g.png
new file mode 100644
index 0000000..e17d458
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_fully_sim2_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_fully_sim2_hp.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_fully_sim2_hp.png
new file mode 100644
index 0000000..63fe13d
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_fully_sim2_hp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_gsm.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_gsm.png
new file mode 100755
index 0000000..2a56bce
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_gsm.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_gsm_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_gsm_fully.png
new file mode 100755
index 0000000..415658b
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_gsm_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_sim1_4g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_sim1_4g.png
new file mode 100644
index 0000000..80dcbe2
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_sim1_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_sim1_hp.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_sim1_hp.png
new file mode 100644
index 0000000..abd7f92
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_sim1_hp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_sim2_4g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_sim2_4g.png
new file mode 100644
index 0000000..386a1ac
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_sim2_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_sim2_hp.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_sim2_hp.png
new file mode 100644
index 0000000..c9daf03
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_sim2_hp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_2g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_2g.png
new file mode 100644
index 0000000..8784452
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_2g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_2g_default.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_2g_default.png
new file mode 100644
index 0000000..8bd6786
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_2g_default.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_2g_default_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_2g_default_fully.png
new file mode 100644
index 0000000..38f5704
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_2g_default_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_2g_default_fully_roam.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_2g_default_fully_roam.png
new file mode 100755
index 0000000..48f1af9
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_2g_default_fully_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_2g_default_roam.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_2g_default_roam.png
new file mode 100755
index 0000000..d821549
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_2g_default_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_2g_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_2g_fully.png
new file mode 100644
index 0000000..e201a00
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_2g_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_4g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_4g.png
new file mode 100755
index 0000000..c7d855e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_4g_default.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_4g_default.png
new file mode 100755
index 0000000..42ba3f9
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_4g_default.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_4g_default_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_4g_default_fully.png
new file mode 100755
index 0000000..009fd7d
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_4g_default_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_4g_default_fully_roam.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_4g_default_fully_roam.png
new file mode 100755
index 0000000..d58b9a3
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_4g_default_fully_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_4g_default_roam.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_4g_default_roam.png
new file mode 100755
index 0000000..3ae325b
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_4g_default_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_4g_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_4g_fully.png
new file mode 100755
index 0000000..4ca959f
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_4g_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_default_fully_roam.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_default_fully_roam.png
new file mode 100755
index 0000000..cce1bb4
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_default_fully_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_default_roam.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_default_roam.png
new file mode 100755
index 0000000..41791cb
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_default_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_e.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_e.png
new file mode 100755
index 0000000..660842f
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_e.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_e_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_e_fully.png
new file mode 100755
index 0000000..da72330
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_e_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_e_fully_roam.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_e_fully_roam.png
new file mode 100755
index 0000000..be05ea6
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_e_fully_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_e_roam.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_e_roam.png
new file mode 100755
index 0000000..cb3ec07
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_e_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_fully_sim1_4g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_fully_sim1_4g.png
new file mode 100644
index 0000000..f4327b8
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_fully_sim1_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_fully_sim1_hp.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_fully_sim1_hp.png
new file mode 100644
index 0000000..0cb531e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_fully_sim1_hp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_fully_sim2_4g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_fully_sim2_4g.png
new file mode 100644
index 0000000..ca4769a
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_fully_sim2_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_fully_sim2_hp.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_fully_sim2_hp.png
new file mode 100644
index 0000000..950b936
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_fully_sim2_hp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_gsm.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_gsm.png
new file mode 100755
index 0000000..1628632
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_gsm.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_gsm_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_gsm_fully.png
new file mode 100755
index 0000000..7526746
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_gsm_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_sim1_4g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_sim1_4g.png
new file mode 100644
index 0000000..c8bdad7
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_sim1_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_sim1_hp.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_sim1_hp.png
new file mode 100644
index 0000000..3e27781
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_sim1_hp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_sim2_4g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_sim2_4g.png
new file mode 100644
index 0000000..e917bfd
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_sim2_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_sim2_hp.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_sim2_hp.png
new file mode 100644
index 0000000..6eaa344
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_sim2_hp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_2g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_2g.png
new file mode 100644
index 0000000..7f18a2e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_2g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_2g_default.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_2g_default.png
new file mode 100644
index 0000000..6684255
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_2g_default.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_2g_default_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_2g_default_fully.png
new file mode 100644
index 0000000..d9b7c80
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_2g_default_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_2g_default_fully_roam.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_2g_default_fully_roam.png
new file mode 100755
index 0000000..37d6b53
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_2g_default_fully_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_2g_default_roam.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_2g_default_roam.png
new file mode 100755
index 0000000..b971b3c
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_2g_default_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_2g_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_2g_fully.png
new file mode 100644
index 0000000..5f41237
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_2g_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_4g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_4g.png
new file mode 100755
index 0000000..2d574bf
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_4g_default.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_4g_default.png
new file mode 100755
index 0000000..588b5a9
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_4g_default.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_4g_default_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_4g_default_fully.png
new file mode 100755
index 0000000..3cb4ee0
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_4g_default_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_4g_default_fully_roam.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_4g_default_fully_roam.png
new file mode 100755
index 0000000..4ea7ff2
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_4g_default_fully_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_4g_default_roam.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_4g_default_roam.png
new file mode 100755
index 0000000..e4e842c
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_4g_default_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_4g_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_4g_fully.png
new file mode 100755
index 0000000..758fc22
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_4g_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_default_fully_roam.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_default_fully_roam.png
new file mode 100755
index 0000000..a1f78ef
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_default_fully_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_default_roam.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_default_roam.png
new file mode 100755
index 0000000..74d45b6
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_default_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_e.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_e.png
new file mode 100755
index 0000000..f314c15
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_e.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_e_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_e_fully.png
new file mode 100755
index 0000000..b5cbd09
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_e_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_e_fully_roam.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_e_fully_roam.png
new file mode 100755
index 0000000..20c7362
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_e_fully_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_e_roam.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_e_roam.png
new file mode 100755
index 0000000..aee5871
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_e_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_fully_sim1_4g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_fully_sim1_4g.png
new file mode 100644
index 0000000..58be4c9
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_fully_sim1_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_fully_sim1_hp.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_fully_sim1_hp.png
new file mode 100644
index 0000000..5594991
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_fully_sim1_hp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_fully_sim2_4g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_fully_sim2_4g.png
new file mode 100644
index 0000000..deea9b4
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_fully_sim2_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_fully_sim2_hp.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_fully_sim2_hp.png
new file mode 100644
index 0000000..7af7fe7
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_fully_sim2_hp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_gsm.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_gsm.png
new file mode 100755
index 0000000..2b82165
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_gsm.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_gsm_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_gsm_fully.png
new file mode 100755
index 0000000..91aba68
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_gsm_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_sim1_4g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_sim1_4g.png
new file mode 100644
index 0000000..e4fa22e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_sim1_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_sim1_hp.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_sim1_hp.png
new file mode 100644
index 0000000..5a90d1f
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_sim1_hp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_sim2_4g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_sim2_4g.png
new file mode 100644
index 0000000..a3bf393
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_sim2_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_sim2_hp.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_sim2_hp.png
new file mode 100644
index 0000000..ed316f0
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_sim2_hp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2g_in.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2g_in.png
new file mode 100644
index 0000000..bce78ac
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2g_in.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2g_inout.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2g_inout.png
new file mode 100644
index 0000000..3a90366
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2g_inout.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2g_no.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2g_no.png
new file mode 100644
index 0000000..49e4f07
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2g_no.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2g_out.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2g_out.png
new file mode 100644
index 0000000..9e45681
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2g_out.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_2g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_2g.png
new file mode 100644
index 0000000..53552e4
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_2g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_2g_default.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_2g_default.png
new file mode 100644
index 0000000..e3e8eb4
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_2g_default.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_2g_default_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_2g_default_fully.png
new file mode 100644
index 0000000..4291595
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_2g_default_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_2g_default_fully_roam.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_2g_default_fully_roam.png
new file mode 100755
index 0000000..19c9a3d
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_2g_default_fully_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_2g_default_roam.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_2g_default_roam.png
new file mode 100755
index 0000000..6119135
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_2g_default_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_2g_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_2g_fully.png
new file mode 100644
index 0000000..6d08ace
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_2g_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_4g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_4g.png
new file mode 100755
index 0000000..5090082
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_4g_default.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_4g_default.png
new file mode 100755
index 0000000..112011b
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_4g_default.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_4g_default_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_4g_default_fully.png
new file mode 100755
index 0000000..34d6635
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_4g_default_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_4g_default_fully_roam.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_4g_default_fully_roam.png
new file mode 100755
index 0000000..7334cb6
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_4g_default_fully_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_4g_default_roam.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_4g_default_roam.png
new file mode 100755
index 0000000..c6e4917b
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_4g_default_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_4g_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_4g_fully.png
new file mode 100755
index 0000000..5eaae02
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_4g_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_default_fully_roam.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_default_fully_roam.png
new file mode 100755
index 0000000..ca4db23
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_default_fully_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_default_roam.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_default_roam.png
new file mode 100755
index 0000000..135a412
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_default_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_e.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_e.png
new file mode 100755
index 0000000..9ea742c
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_e.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_e_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_e_fully.png
new file mode 100755
index 0000000..d708edc
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_e_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_e_fully_roam.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_e_fully_roam.png
new file mode 100755
index 0000000..6ffb032
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_e_fully_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_e_roam.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_e_roam.png
new file mode 100755
index 0000000..61c7e2ae
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_e_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_fully_sim1_4g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_fully_sim1_4g.png
new file mode 100644
index 0000000..e49c37c
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_fully_sim1_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_fully_sim1_hp.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_fully_sim1_hp.png
new file mode 100644
index 0000000..52e9bb8
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_fully_sim1_hp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_fully_sim2_4g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_fully_sim2_4g.png
new file mode 100644
index 0000000..e4ea116
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_fully_sim2_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_fully_sim2_hp.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_fully_sim2_hp.png
new file mode 100644
index 0000000..65d87bf
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_fully_sim2_hp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_gsm.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_gsm.png
new file mode 100755
index 0000000..84ae508
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_gsm.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_gsm_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_gsm_fully.png
new file mode 100755
index 0000000..a141e80
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_gsm_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_sim1_4g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_sim1_4g.png
new file mode 100644
index 0000000..1efc1e6
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_sim1_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_sim1_hp.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_sim1_hp.png
new file mode 100644
index 0000000..d737b59
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_sim1_hp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_sim2_4g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_sim2_4g.png
new file mode 100644
index 0000000..1095985
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_sim2_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_sim2_hp.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_sim2_hp.png
new file mode 100644
index 0000000..7da7832
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_sim2_hp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_2g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_2g.png
new file mode 100644
index 0000000..29d6f9d
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_2g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_2g_default.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_2g_default.png
new file mode 100644
index 0000000..761685d
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_2g_default.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_2g_default_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_2g_default_fully.png
new file mode 100644
index 0000000..7f37ccf
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_2g_default_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_2g_default_fully_roam.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_2g_default_fully_roam.png
new file mode 100755
index 0000000..dbde94f
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_2g_default_fully_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_2g_default_roam.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_2g_default_roam.png
new file mode 100755
index 0000000..77bf21f
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_2g_default_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_2g_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_2g_fully.png
new file mode 100644
index 0000000..1f4076c
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_2g_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_4g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_4g.png
new file mode 100755
index 0000000..a381225
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_4g_default.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_4g_default.png
new file mode 100755
index 0000000..b3df2c9
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_4g_default.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_4g_default_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_4g_default_fully.png
new file mode 100755
index 0000000..468c0f7
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_4g_default_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_4g_default_fully_roam.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_4g_default_fully_roam.png
new file mode 100755
index 0000000..7332ddf
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_4g_default_fully_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_4g_default_roam.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_4g_default_roam.png
new file mode 100755
index 0000000..dcce912
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_4g_default_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_4g_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_4g_fully.png
new file mode 100755
index 0000000..6d4f357
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_4g_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_default_fully_roam.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_default_fully_roam.png
new file mode 100755
index 0000000..76a1301
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_default_fully_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_default_roam.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_default_roam.png
new file mode 100755
index 0000000..03ff3b6
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_default_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_e.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_e.png
new file mode 100755
index 0000000..7d5bbfd
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_e.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_e_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_e_fully.png
new file mode 100755
index 0000000..c6657fb
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_e_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_e_fully_roam.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_e_fully_roam.png
new file mode 100755
index 0000000..c1e71a5
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_e_fully_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_e_roam.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_e_roam.png
new file mode 100755
index 0000000..64485e5
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_e_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_fully_sim1_4g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_fully_sim1_4g.png
new file mode 100644
index 0000000..6dd8a68
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_fully_sim1_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_fully_sim1_hp.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_fully_sim1_hp.png
new file mode 100644
index 0000000..d33b99b
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_fully_sim1_hp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_fully_sim2_4g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_fully_sim2_4g.png
new file mode 100644
index 0000000..df1395d
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_fully_sim2_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_fully_sim2_hp.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_fully_sim2_hp.png
new file mode 100644
index 0000000..51ed57e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_fully_sim2_hp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_gsm.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_gsm.png
new file mode 100755
index 0000000..eaa6a53
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_gsm.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_gsm_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_gsm_fully.png
new file mode 100755
index 0000000..c97f738
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_gsm_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_sim1_4g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_sim1_4g.png
new file mode 100644
index 0000000..2585797
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_sim1_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_sim1_hp.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_sim1_hp.png
new file mode 100644
index 0000000..1ece322
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_sim1_hp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_sim2_4g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_sim2_4g.png
new file mode 100644
index 0000000..4ee5031
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_sim2_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_sim2_hp.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_sim2_hp.png
new file mode 100644
index 0000000..ff9ba0b
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_sim2_hp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4g_in.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4g_in.png
new file mode 100755
index 0000000..7ccf35c
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4g_in.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4g_inout.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4g_inout.png
new file mode 100755
index 0000000..ad68409
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4g_inout.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4g_no.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4g_no.png
new file mode 100755
index 0000000..854f9e3
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4g_no.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4g_out.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4g_out.png
new file mode 100755
index 0000000..abe5cef
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4g_out.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_hp_in.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_hp_in.png
new file mode 100644
index 0000000..2a484a7
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_hp_in.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_hp_inout.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_hp_inout.png
new file mode 100644
index 0000000..e1847b2
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_hp_inout.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_hp_no.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_hp_no.png
new file mode 100644
index 0000000..25d1042
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_hp_no.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_hp_out.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_hp_out.png
new file mode 100644
index 0000000..1deef41
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_hp_out.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_in.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_in.png
new file mode 100644
index 0000000..6e84546
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_in.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_null_1.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_null_1.png
new file mode 100644
index 0000000..cb3e630
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_null_1.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_out.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_out.png
new file mode 100644
index 0000000..11ffbde
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_out.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_in.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_in.png
new file mode 100644
index 0000000..2bb923e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_in.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_inout.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_inout.png
new file mode 100644
index 0000000..783ad175
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_inout.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_out.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_out.png
new file mode 100644
index 0000000..e499f9d
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_out.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_mini_settings.png b/packages/SystemUI/res/drawable-mdpi/ic_mini_settings.png
new file mode 100755
index 0000000..878169b
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/ic_mini_settings.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_notification_overlay.9.png b/packages/SystemUI/res/drawable-mdpi/ic_notification_overlay.9.png
index 7ae6079..c8c8102 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_notification_overlay.9.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_notification_overlay.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_2g.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_2g.png
new file mode 100644
index 0000000..29ff6fe
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_2g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_full_2g.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_full_2g.png
new file mode 100644
index 0000000..5bbfa6f
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_full_2g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_full_hp.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_full_hp.png
new file mode 100644
index 0000000..6e88bf9
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_full_hp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_hp.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_hp.png
new file mode 100644
index 0000000..59c0e9f
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_hp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_add.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_add.png
new file mode 100644
index 0000000..cf9fda6
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_add.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_add_land.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_add_land.png
new file mode 100644
index 0000000..ec8dfa4
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_add_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_add_side.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_add_side.png
new file mode 100644
index 0000000..6231b21
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_add_side.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_side.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_side.png
new file mode 100644
index 0000000..5854b38
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_side.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_ime_left.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_ime_left.png
new file mode 100755
index 0000000..1f08402
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_ime_left.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_ime_right.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_ime_right.png
new file mode 100755
index 0000000..7626499
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_ime_right.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_menu_big.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_menu_big.png
new file mode 100644
index 0000000..c2dd22b
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_menu_big.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_menu_big_land.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_menu_big_land.png
new file mode 100644
index 0000000..4345844
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_menu_big_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_recent_side.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_recent_side.png
new file mode 100644
index 0000000..286bd00
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_recent_side.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_search.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_search.png
new file mode 100644
index 0000000..885c130
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_search.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_search_land.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_search_land.png
new file mode 100644
index 0000000..2487dfb
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_search_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_search_side.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_search_side.png
new file mode 100644
index 0000000..0ff41f5
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_search_side.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_notify_image.png b/packages/SystemUI/res/drawable-mdpi/stat_notify_image.png
deleted file mode 100644
index a02e21c..0000000
--- a/packages/SystemUI/res/drawable-mdpi/stat_notify_image.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_notify_image_error.png b/packages/SystemUI/res/drawable-mdpi/stat_notify_image_error.png
deleted file mode 100644
index 4af2617..0000000
--- a/packages/SystemUI/res/drawable-mdpi/stat_notify_image_error.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_no_sim_1.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_no_sim_1.png
new file mode 100644
index 0000000..5dc627c
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_no_sim_1.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_0_fully_sim1_4g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_0_fully_sim1_4g.png
new file mode 100644
index 0000000..68bfaa9
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_0_fully_sim1_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_0_fully_sim1_hp.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_0_fully_sim1_hp.png
new file mode 100644
index 0000000..f1163cb
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_0_fully_sim1_hp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_0_fully_sim2_4g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_0_fully_sim2_4g.png
new file mode 100644
index 0000000..42b9889
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_0_fully_sim2_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_0_fully_sim2_hp.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_0_fully_sim2_hp.png
new file mode 100644
index 0000000..669a65d
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_0_fully_sim2_hp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_0_sim1_4g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_0_sim1_4g.png
new file mode 100644
index 0000000..4dac80f
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_0_sim1_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_0_sim1_hp.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_0_sim1_hp.png
new file mode 100644
index 0000000..dc9deb1
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_0_sim1_hp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_0_sim2_4g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_0_sim2_4g.png
new file mode 100644
index 0000000..d598aea
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_0_sim2_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_0_sim2_hp.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_0_sim2_hp.png
new file mode 100644
index 0000000..3a449e5
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_0_sim2_hp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_1_fully_sim1_4g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_1_fully_sim1_4g.png
new file mode 100644
index 0000000..61bc6cd
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_1_fully_sim1_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_1_fully_sim1_hp.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_1_fully_sim1_hp.png
new file mode 100644
index 0000000..b82719c
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_1_fully_sim1_hp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_1_fully_sim2_4g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_1_fully_sim2_4g.png
new file mode 100644
index 0000000..36f76c4
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_1_fully_sim2_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_1_fully_sim2_hp.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_1_fully_sim2_hp.png
new file mode 100644
index 0000000..8128273
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_1_fully_sim2_hp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_1_sim1_4g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_1_sim1_4g.png
new file mode 100644
index 0000000..b34834c
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_1_sim1_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_1_sim1_hp.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_1_sim1_hp.png
new file mode 100644
index 0000000..b951e16
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_1_sim1_hp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_1_sim2_4g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_1_sim2_4g.png
new file mode 100644
index 0000000..601cdb1
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_1_sim2_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_1_sim2_hp.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_1_sim2_hp.png
new file mode 100644
index 0000000..ab7b1a1
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_1_sim2_hp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_2_fully_sim1_4g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_2_fully_sim1_4g.png
new file mode 100644
index 0000000..1a6ee0e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_2_fully_sim1_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_2_fully_sim1_hp.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_2_fully_sim1_hp.png
new file mode 100644
index 0000000..cac2e1b
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_2_fully_sim1_hp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_2_fully_sim2_4g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_2_fully_sim2_4g.png
new file mode 100644
index 0000000..67b074f
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_2_fully_sim2_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_2_fully_sim2_hp.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_2_fully_sim2_hp.png
new file mode 100644
index 0000000..647006e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_2_fully_sim2_hp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_2_sim1_4g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_2_sim1_4g.png
new file mode 100644
index 0000000..7a9dba2
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_2_sim1_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_2_sim1_hp.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_2_sim1_hp.png
new file mode 100644
index 0000000..8347aa0
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_2_sim1_hp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_2_sim2_4g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_2_sim2_4g.png
new file mode 100644
index 0000000..097cfc4
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_2_sim2_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_2_sim2_hp.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_2_sim2_hp.png
new file mode 100644
index 0000000..b7aca12
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_2_sim2_hp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_3_fully_sim1_4g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_3_fully_sim1_4g.png
new file mode 100644
index 0000000..5370205
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_3_fully_sim1_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_3_fully_sim1_hp.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_3_fully_sim1_hp.png
new file mode 100644
index 0000000..9fb2ffb
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_3_fully_sim1_hp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_3_fully_sim2_4g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_3_fully_sim2_4g.png
new file mode 100644
index 0000000..221fae0
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_3_fully_sim2_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_3_fully_sim2_hp.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_3_fully_sim2_hp.png
new file mode 100644
index 0000000..b61f127
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_3_fully_sim2_hp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_3_sim1_4g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_3_sim1_4g.png
new file mode 100644
index 0000000..f24da09
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_3_sim1_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_3_sim1_hp.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_3_sim1_hp.png
new file mode 100644
index 0000000..b1f29bb
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_3_sim1_hp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_3_sim2_4g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_3_sim2_4g.png
new file mode 100644
index 0000000..aadbdb3
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_3_sim2_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_3_sim2_hp.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_3_sim2_hp.png
new file mode 100644
index 0000000..48a57c8
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_3_sim2_hp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_4_fully_sim1_4g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_4_fully_sim1_4g.png
new file mode 100644
index 0000000..671914f
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_4_fully_sim1_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_4_fully_sim1_hp.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_4_fully_sim1_hp.png
new file mode 100644
index 0000000..0b18b6d
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_4_fully_sim1_hp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_4_fully_sim2_4g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_4_fully_sim2_4g.png
new file mode 100644
index 0000000..3fa66a2
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_4_fully_sim2_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_4_fully_sim2_hp.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_4_fully_sim2_hp.png
new file mode 100644
index 0000000..ffe7e3a
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_4_fully_sim2_hp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_4_sim1_4g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_4_sim1_4g.png
new file mode 100644
index 0000000..d61ff7e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_4_sim1_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_4_sim1_hp.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_4_sim1_hp.png
new file mode 100644
index 0000000..07bd8b1
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_4_sim1_hp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_4_sim2_4g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_4_sim2_4g.png
new file mode 100644
index 0000000..39309df
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_4_sim2_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_4_sim2_hp.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_4_sim2_hp.png
new file mode 100644
index 0000000..95a3964
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_4_sim2_hp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_3g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_3g.png
new file mode 100755
index 0000000..f11b84e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_3g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_3g_default.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_3g_default.png
new file mode 100755
index 0000000..005b3a4
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_3g_default.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_3g_default_fully.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_3g_default_fully.png
new file mode 100755
index 0000000..6be2156
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_3g_default_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_3g_default_fully_roam.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_3g_default_fully_roam.png
new file mode 100755
index 0000000..738ddec
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_3g_default_fully_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_3g_default_roam.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_3g_default_roam.png
new file mode 100755
index 0000000..6045011
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_3g_default_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_3g_fully.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_3g_fully.png
new file mode 100755
index 0000000..24cbdae
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_3g_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_4g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_4g.png
new file mode 100755
index 0000000..0a71f59
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_4g_default.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_4g_default.png
new file mode 100755
index 0000000..3a4bd3c
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_4g_default.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_4g_default_fully.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_4g_default_fully.png
new file mode 100755
index 0000000..2608bc1
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_4g_default_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_4g_default_fully_roam.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_4g_default_fully_roam.png
new file mode 100755
index 0000000..ae85f93
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_4g_default_fully_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_4g_default_roam.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_4g_default_roam.png
new file mode 100755
index 0000000..ea320f9
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_4g_default_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_4g_fully.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_4g_fully.png
new file mode 100755
index 0000000..7dbba7d
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_4g_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_e.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_e.png
new file mode 100755
index 0000000..55521f5
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_e.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_e_fully.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_e_fully.png
new file mode 100755
index 0000000..b88661d
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_e_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_e_fully_roam.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_e_fully_roam.png
new file mode 100755
index 0000000..ad8a117
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_e_fully_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_e_roam.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_e_roam.png
new file mode 100755
index 0000000..7358b66
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_e_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_fully_sim1_4g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_fully_sim1_4g.png
new file mode 100644
index 0000000..b0b9581
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_fully_sim1_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_fully_sim1_hp.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_fully_sim1_hp.png
new file mode 100644
index 0000000..4b61681
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_fully_sim1_hp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_fully_sim2_4g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_fully_sim2_4g.png
new file mode 100644
index 0000000..08f7b49
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_fully_sim2_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_fully_sim2_hp.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_fully_sim2_hp.png
new file mode 100644
index 0000000..e29348a
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_fully_sim2_hp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_g.png
new file mode 100755
index 0000000..4fca6a3
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_g_fully.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_g_fully.png
new file mode 100755
index 0000000..e77a91a
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_g_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_g_fully_roam.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_g_fully_roam.png
new file mode 100755
index 0000000..7d0d206
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_g_fully_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_g_roam.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_g_roam.png
new file mode 100755
index 0000000..e77a626
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_g_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_gsm.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_gsm.png
new file mode 100755
index 0000000..b581f5d
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_gsm.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_gsm_fully.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_gsm_fully.png
new file mode 100755
index 0000000..370fa88
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_gsm_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_sim1_4g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_sim1_4g.png
new file mode 100644
index 0000000..85c241e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_sim1_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_sim1_hp.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_sim1_hp.png
new file mode 100644
index 0000000..6158001
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_sim1_hp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_sim2_4g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_sim2_4g.png
new file mode 100644
index 0000000..e3446dd
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_sim2_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_sim2_hp.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_sim2_hp.png
new file mode 100644
index 0000000..67ae589
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_sim2_hp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_3g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_3g.png
new file mode 100755
index 0000000..c5dd2c5
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_3g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_3g_default.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_3g_default.png
new file mode 100755
index 0000000..39218a0
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_3g_default.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_3g_default_fully.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_3g_default_fully.png
new file mode 100755
index 0000000..eebe87d
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_3g_default_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_3g_default_fully_roam.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_3g_default_fully_roam.png
new file mode 100755
index 0000000..946e832
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_3g_default_fully_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_3g_default_roam.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_3g_default_roam.png
new file mode 100755
index 0000000..9c8d910
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_3g_default_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_3g_fully.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_3g_fully.png
new file mode 100755
index 0000000..25d9d06
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_3g_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_4g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_4g.png
new file mode 100755
index 0000000..7dbe663
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_4g_default.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_4g_default.png
new file mode 100755
index 0000000..16d093d
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_4g_default.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_4g_default_fully.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_4g_default_fully.png
new file mode 100755
index 0000000..187e0af
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_4g_default_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_4g_default_fully_roam.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_4g_default_fully_roam.png
new file mode 100755
index 0000000..652cdb0
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_4g_default_fully_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_4g_default_roam.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_4g_default_roam.png
new file mode 100755
index 0000000..eaf6a27
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_4g_default_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_4g_fully.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_4g_fully.png
new file mode 100755
index 0000000..c591c85
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_4g_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_e.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_e.png
new file mode 100755
index 0000000..d79900c
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_e.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_e_fully.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_e_fully.png
new file mode 100755
index 0000000..7360d59
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_e_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_e_fully_roam.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_e_fully_roam.png
new file mode 100755
index 0000000..05af68e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_e_fully_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_e_roam.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_e_roam.png
new file mode 100755
index 0000000..f085372
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_e_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_fully_sim1_4g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_fully_sim1_4g.png
new file mode 100644
index 0000000..2131949
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_fully_sim1_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_fully_sim1_hp.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_fully_sim1_hp.png
new file mode 100644
index 0000000..41eaea0
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_fully_sim1_hp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_fully_sim2_4g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_fully_sim2_4g.png
new file mode 100644
index 0000000..ffa6b71
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_fully_sim2_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_fully_sim2_hp.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_fully_sim2_hp.png
new file mode 100644
index 0000000..0d34340
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_fully_sim2_hp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_g.png
new file mode 100755
index 0000000..7c6ef45
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_g_fully.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_g_fully.png
new file mode 100755
index 0000000..795f722
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_g_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_g_fully_roam.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_g_fully_roam.png
new file mode 100755
index 0000000..b09dd9a
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_g_fully_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_g_roam.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_g_roam.png
new file mode 100755
index 0000000..2bd02be
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_g_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_gsm.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_gsm.png
new file mode 100755
index 0000000..9b068c1
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_gsm.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_gsm_fully.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_gsm_fully.png
new file mode 100755
index 0000000..3a0f4f4
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_gsm_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_sim1_4g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_sim1_4g.png
new file mode 100644
index 0000000..eadf888
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_sim1_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_sim1_hp.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_sim1_hp.png
new file mode 100644
index 0000000..487cd1f
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_sim1_hp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_sim2_4g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_sim2_4g.png
new file mode 100644
index 0000000..c955503
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_sim2_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_sim2_hp.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_sim2_hp.png
new file mode 100644
index 0000000..254211d
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_sim2_hp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_3g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_3g.png
new file mode 100755
index 0000000..c715e53
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_3g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_3g_default.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_3g_default.png
new file mode 100755
index 0000000..6a6a34dd
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_3g_default.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_3g_default_fully.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_3g_default_fully.png
new file mode 100755
index 0000000..2c2ee21
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_3g_default_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_3g_default_fully_roam.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_3g_default_fully_roam.png
new file mode 100755
index 0000000..e2cd61e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_3g_default_fully_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_3g_default_roam.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_3g_default_roam.png
new file mode 100755
index 0000000..331e52f
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_3g_default_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_3g_fully.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_3g_fully.png
new file mode 100755
index 0000000..01b7358
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_3g_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_4g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_4g.png
new file mode 100755
index 0000000..a79913f
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_4g_default.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_4g_default.png
new file mode 100755
index 0000000..89a8720
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_4g_default.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_4g_default_fully.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_4g_default_fully.png
new file mode 100755
index 0000000..de92e6d
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_4g_default_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_4g_default_fully_roam.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_4g_default_fully_roam.png
new file mode 100755
index 0000000..b95eb22
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_4g_default_fully_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_4g_default_roam.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_4g_default_roam.png
new file mode 100755
index 0000000..9ddf429
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_4g_default_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_4g_fully.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_4g_fully.png
new file mode 100755
index 0000000..06f5ec9
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_4g_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_e.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_e.png
new file mode 100755
index 0000000..06638f3
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_e.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_e_fully.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_e_fully.png
new file mode 100755
index 0000000..6076075
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_e_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_e_fully_roam.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_e_fully_roam.png
new file mode 100755
index 0000000..d040a2b
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_e_fully_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_e_roam.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_e_roam.png
new file mode 100755
index 0000000..fe9f905
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_e_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_fully_sim1_4g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_fully_sim1_4g.png
new file mode 100644
index 0000000..946ae17
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_fully_sim1_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_fully_sim1_hp.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_fully_sim1_hp.png
new file mode 100644
index 0000000..b9304e7
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_fully_sim1_hp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_fully_sim2_4g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_fully_sim2_4g.png
new file mode 100644
index 0000000..180eec9
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_fully_sim2_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_fully_sim2_hp.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_fully_sim2_hp.png
new file mode 100644
index 0000000..1f6145e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_fully_sim2_hp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_g.png
new file mode 100755
index 0000000..ba1ff45
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_g_fully.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_g_fully.png
new file mode 100755
index 0000000..f7fa38c
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_g_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_g_fully_roam.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_g_fully_roam.png
new file mode 100755
index 0000000..8355a4a
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_g_fully_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_g_roam.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_g_roam.png
new file mode 100755
index 0000000..91769b9
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_g_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_gsm.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_gsm.png
new file mode 100755
index 0000000..2e6bc18
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_gsm.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_gsm_fully.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_gsm_fully.png
new file mode 100755
index 0000000..68c68fc
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_gsm_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_sim1_4g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_sim1_4g.png
new file mode 100644
index 0000000..88645bc
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_sim1_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_sim1_hp.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_sim1_hp.png
new file mode 100644
index 0000000..fec6ead
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_sim1_hp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_sim2_4g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_sim2_4g.png
new file mode 100644
index 0000000..5d6645b
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_sim2_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_sim2_hp.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_sim2_hp.png
new file mode 100644
index 0000000..003737d
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_sim2_hp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_3g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_3g.png
new file mode 100755
index 0000000..6875565
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_3g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_3g_default.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_3g_default.png
new file mode 100755
index 0000000..56f83dd
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_3g_default.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_3g_default_fully.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_3g_default_fully.png
new file mode 100755
index 0000000..42935b6
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_3g_default_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_3g_default_fully_roam.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_3g_default_fully_roam.png
new file mode 100755
index 0000000..b8742a0
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_3g_default_fully_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_3g_default_roam.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_3g_default_roam.png
new file mode 100755
index 0000000..cf04633
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_3g_default_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_3g_fully.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_3g_fully.png
new file mode 100755
index 0000000..b0073c2
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_3g_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_4g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_4g.png
new file mode 100755
index 0000000..0d93580
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_4g_default.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_4g_default.png
new file mode 100755
index 0000000..bdbce47
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_4g_default.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_4g_default_fully.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_4g_default_fully.png
new file mode 100755
index 0000000..347ea6b
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_4g_default_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_4g_default_fully_roam.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_4g_default_fully_roam.png
new file mode 100755
index 0000000..0ade758
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_4g_default_fully_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_4g_default_roam.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_4g_default_roam.png
new file mode 100755
index 0000000..69d763d
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_4g_default_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_4g_fully.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_4g_fully.png
new file mode 100755
index 0000000..841da56
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_4g_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_e.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_e.png
new file mode 100755
index 0000000..c684a5a
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_e.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_e_fully.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_e_fully.png
new file mode 100755
index 0000000..d71f85f
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_e_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_e_fully_roam.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_e_fully_roam.png
new file mode 100755
index 0000000..0e3d718
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_e_fully_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_e_roam.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_e_roam.png
new file mode 100755
index 0000000..39fb603
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_e_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_fully_sim1_4g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_fully_sim1_4g.png
new file mode 100644
index 0000000..14926a3
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_fully_sim1_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_fully_sim1_hp.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_fully_sim1_hp.png
new file mode 100644
index 0000000..47ff33d
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_fully_sim1_hp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_fully_sim2_4g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_fully_sim2_4g.png
new file mode 100644
index 0000000..d6078c6
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_fully_sim2_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_fully_sim2_hp.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_fully_sim2_hp.png
new file mode 100644
index 0000000..7272c32
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_fully_sim2_hp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_g.png
new file mode 100755
index 0000000..d6e3cac
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_g_fully.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_g_fully.png
new file mode 100755
index 0000000..949d58a
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_g_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_g_fully_roam.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_g_fully_roam.png
new file mode 100755
index 0000000..407e5c1
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_g_fully_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_g_roam.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_g_roam.png
new file mode 100755
index 0000000..5f05448
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_g_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_gsm.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_gsm.png
new file mode 100755
index 0000000..9284534
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_gsm.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_gsm_fully.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_gsm_fully.png
new file mode 100755
index 0000000..f7e1a13
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_gsm_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_sim1_4g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_sim1_4g.png
new file mode 100644
index 0000000..51a0f3c
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_sim1_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_sim1_hp.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_sim1_hp.png
new file mode 100644
index 0000000..49c02b3
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_sim1_hp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_sim2_4g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_sim2_4g.png
new file mode 100644
index 0000000..a9ba830
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_sim2_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_sim2_hp.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_sim2_hp.png
new file mode 100644
index 0000000..8ad18f0
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_sim2_hp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_3g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_3g.png
new file mode 100755
index 0000000..86fc340
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_3g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_3g_default.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_3g_default.png
new file mode 100755
index 0000000..84c4699
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_3g_default.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_3g_default_fully.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_3g_default_fully.png
new file mode 100755
index 0000000..8e7ac74
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_3g_default_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_3g_default_fully_roam.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_3g_default_fully_roam.png
new file mode 100755
index 0000000..fe492fd
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_3g_default_fully_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_3g_default_roam.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_3g_default_roam.png
new file mode 100755
index 0000000..3ec684e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_3g_default_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_3g_fully.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_3g_fully.png
new file mode 100755
index 0000000..96bbc46
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_3g_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_4g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_4g.png
new file mode 100755
index 0000000..5c4a61e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_4g_default.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_4g_default.png
new file mode 100755
index 0000000..86b9a88
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_4g_default.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_4g_default_fully.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_4g_default_fully.png
new file mode 100755
index 0000000..adcd352
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_4g_default_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_4g_default_fully_roam.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_4g_default_fully_roam.png
new file mode 100755
index 0000000..f545efe
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_4g_default_fully_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_4g_default_roam.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_4g_default_roam.png
new file mode 100755
index 0000000..c2d055a
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_4g_default_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_4g_fully.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_4g_fully.png
new file mode 100755
index 0000000..716581f
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_4g_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_e.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_e.png
new file mode 100755
index 0000000..de3917d
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_e.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_e_fully.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_e_fully.png
new file mode 100755
index 0000000..f5e5958
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_e_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_e_fully_roam.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_e_fully_roam.png
new file mode 100755
index 0000000..de44dea
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_e_fully_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_e_roam.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_e_roam.png
new file mode 100755
index 0000000..cb068da
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_e_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_fully_sim1_4g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_fully_sim1_4g.png
new file mode 100644
index 0000000..72eadc0
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_fully_sim1_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_fully_sim1_hp.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_fully_sim1_hp.png
new file mode 100644
index 0000000..b47d04f
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_fully_sim1_hp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_fully_sim2_4g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_fully_sim2_4g.png
new file mode 100644
index 0000000..63ca13c
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_fully_sim2_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_fully_sim2_hp.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_fully_sim2_hp.png
new file mode 100644
index 0000000..3bbc885
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_fully_sim2_hp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_g.png
new file mode 100755
index 0000000..f54d21f
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_g_fully.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_g_fully.png
new file mode 100755
index 0000000..474f075
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_g_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_g_fully_roam.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_g_fully_roam.png
new file mode 100755
index 0000000..5c7eaae
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_g_fully_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_g_roam.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_g_roam.png
new file mode 100755
index 0000000..c65123d
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_g_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_gsm.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_gsm.png
new file mode 100755
index 0000000..2a86141
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_gsm.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_gsm_fully.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_gsm_fully.png
new file mode 100755
index 0000000..02f3b83
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_gsm_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_sim1_4g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_sim1_4g.png
new file mode 100644
index 0000000..b3eb6d9
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_sim1_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_sim1_hp.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_sim1_hp.png
new file mode 100644
index 0000000..ef872fd
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_sim1_hp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_sim2_4g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_sim2_4g.png
new file mode 100644
index 0000000..02d8244
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_sim2_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_sim2_hp.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_sim2_hp.png
new file mode 100644
index 0000000..6c34eab
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_sim2_hp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_in.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_in.png
new file mode 100644
index 0000000..31c0936
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_in.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_inout.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_inout.png
new file mode 100644
index 0000000..7e9b752
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_inout.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_null_1.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_null_1.png
new file mode 100644
index 0000000..ade1828
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_null_1.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_out.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_out.png
new file mode 100644
index 0000000..3209234
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_out.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_in.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_in.png
new file mode 100644
index 0000000..95c56ed
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_in.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_inout.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_inout.png
new file mode 100644
index 0000000..11b9a93
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_inout.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_out.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_out.png
new file mode 100644
index 0000000..0f85ca0
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_out.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_mini_settings.png b/packages/SystemUI/res/drawable-xhdpi/ic_mini_settings.png
new file mode 100755
index 0000000..84807e8
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_mini_settings.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_notification_overlay.9.png b/packages/SystemUI/res/drawable-xhdpi/ic_notification_overlay.9.png
index aae807b..77eeda1 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_notification_overlay.9.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_notification_overlay.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_add.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_add.png
new file mode 100644
index 0000000..75ba404
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_add.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_add_land.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_add_land.png
new file mode 100644
index 0000000..30f4415
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_add_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_add_side.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_add_side.png
new file mode 100644
index 0000000..916fe9a
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_add_side.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_side.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_side.png
new file mode 100644
index 0000000..7504d32
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_side.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_ime_left.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_ime_left.png
new file mode 100755
index 0000000..4183e20
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_ime_left.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_ime_right.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_ime_right.png
new file mode 100755
index 0000000..ab1c7b4
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_ime_right.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_menu_big.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_menu_big.png
new file mode 100644
index 0000000..83f8d78
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_menu_big.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_menu_big_land.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_menu_big_land.png
new file mode 100644
index 0000000..fe74ae9
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_menu_big_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_recent_side.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_recent_side.png
new file mode 100644
index 0000000..db596cc
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_recent_side.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_search.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_search.png
new file mode 100644
index 0000000..007faa3
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_search.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_search_land.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_search_land.png
new file mode 100644
index 0000000..e997c37
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_search_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_search_side.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_search_side.png
new file mode 100644
index 0000000..69f1a0b
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_search_side.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_notify_image.png b/packages/SystemUI/res/drawable-xhdpi/stat_notify_image.png
deleted file mode 100644
index 24bdbb6..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/stat_notify_image.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_notify_image_error.png b/packages/SystemUI/res/drawable-xhdpi/stat_notify_image_error.png
deleted file mode 100644
index 6ecd2d3..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/stat_notify_image_error.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_r_signal_0_fully_sim1_4g.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_r_signal_0_fully_sim1_4g.png
new file mode 100644
index 0000000..52569ed
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_r_signal_0_fully_sim1_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_r_signal_0_fully_sim2_4g.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_r_signal_0_fully_sim2_4g.png
new file mode 100644
index 0000000..034a682
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_r_signal_0_fully_sim2_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_r_signal_0_sim1_4g.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_r_signal_0_sim1_4g.png
new file mode 100644
index 0000000..1ed366e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_r_signal_0_sim1_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_r_signal_0_sim2_4g.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_r_signal_0_sim2_4g.png
new file mode 100644
index 0000000..18fe2a2
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_r_signal_0_sim2_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_r_signal_1_fully_sim1_4g.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_r_signal_1_fully_sim1_4g.png
new file mode 100644
index 0000000..175020c
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_r_signal_1_fully_sim1_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_r_signal_1_fully_sim2_4g.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_r_signal_1_fully_sim2_4g.png
new file mode 100644
index 0000000..10e733a
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_r_signal_1_fully_sim2_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_r_signal_1_sim1_4g.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_r_signal_1_sim1_4g.png
new file mode 100644
index 0000000..295e678
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_r_signal_1_sim1_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_r_signal_1_sim2_4g.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_r_signal_1_sim2_4g.png
new file mode 100644
index 0000000..d36720a
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_r_signal_1_sim2_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_r_signal_2_fully_sim1_4g.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_r_signal_2_fully_sim1_4g.png
new file mode 100644
index 0000000..8044a22
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_r_signal_2_fully_sim1_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_r_signal_2_fully_sim2_4g.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_r_signal_2_fully_sim2_4g.png
new file mode 100644
index 0000000..256c8d3
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_r_signal_2_fully_sim2_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_r_signal_2_sim1_4g.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_r_signal_2_sim1_4g.png
new file mode 100644
index 0000000..0b4d9cf
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_r_signal_2_sim1_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_r_signal_2_sim2_4g.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_r_signal_2_sim2_4g.png
new file mode 100644
index 0000000..d347e53
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_r_signal_2_sim2_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_r_signal_3_fully_sim1_4g.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_r_signal_3_fully_sim1_4g.png
new file mode 100644
index 0000000..1b4e28e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_r_signal_3_fully_sim1_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_r_signal_3_fully_sim2_4g.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_r_signal_3_fully_sim2_4g.png
new file mode 100644
index 0000000..c046535
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_r_signal_3_fully_sim2_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_r_signal_3_sim1_4g.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_r_signal_3_sim1_4g.png
new file mode 100644
index 0000000..976d87e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_r_signal_3_sim1_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_r_signal_3_sim2_4g.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_r_signal_3_sim2_4g.png
new file mode 100644
index 0000000..ae2c1b0
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_r_signal_3_sim2_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_r_signal_4_fully_sim1_4g.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_r_signal_4_fully_sim1_4g.png
new file mode 100644
index 0000000..a7b3408
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_r_signal_4_fully_sim1_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_r_signal_4_fully_sim2_4g.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_r_signal_4_fully_sim2_4g.png
new file mode 100644
index 0000000..8cf9fcf
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_r_signal_4_fully_sim2_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_r_signal_4_sim1_4g.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_r_signal_4_sim1_4g.png
new file mode 100644
index 0000000..92d6840
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_r_signal_4_sim1_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_r_signal_4_sim2_4g.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_r_signal_4_sim2_4g.png
new file mode 100644
index 0000000..bca3ef6
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_r_signal_4_sim2_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_3g.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_3g.png
new file mode 100755
index 0000000..ec1d104
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_3g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_3g_default.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_3g_default.png
new file mode 100755
index 0000000..9f1de41
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_3g_default.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_3g_default_fully.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_3g_default_fully.png
new file mode 100755
index 0000000..b5222fc
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_3g_default_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_3g_default_fully_roam.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_3g_default_fully_roam.png
new file mode 100755
index 0000000..b12b0ed
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_3g_default_fully_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_3g_default_roam.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_3g_default_roam.png
new file mode 100755
index 0000000..f333138
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_3g_default_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_3g_fully.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_3g_fully.png
new file mode 100755
index 0000000..12f8875
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_3g_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_4g.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_4g.png
new file mode 100755
index 0000000..9b03d18
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_4g_default.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_4g_default.png
new file mode 100755
index 0000000..ffdc80f
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_4g_default.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_4g_default_fully.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_4g_default_fully.png
new file mode 100755
index 0000000..ae3d75a
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_4g_default_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_4g_default_fully_roam.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_4g_default_fully_roam.png
new file mode 100755
index 0000000..c67bfe7
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_4g_default_fully_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_4g_default_roam.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_4g_default_roam.png
new file mode 100755
index 0000000..66019f8
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_4g_default_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_4g_fully.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_4g_fully.png
new file mode 100755
index 0000000..d14e689
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_4g_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_e.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_e.png
new file mode 100755
index 0000000..281afe0
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_e.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_e_fully.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_e_fully.png
new file mode 100755
index 0000000..083889e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_e_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_e_fully_roam.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_e_fully_roam.png
new file mode 100755
index 0000000..c3efed1
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_e_fully_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_e_roam.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_e_roam.png
new file mode 100755
index 0000000..3fab702
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_e_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_fully_sim1_4g.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_fully_sim1_4g.png
new file mode 100644
index 0000000..1fc6d0e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_fully_sim1_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_fully_sim2_4g.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_fully_sim2_4g.png
new file mode 100644
index 0000000..e28b6f0
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_fully_sim2_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_g.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_g.png
new file mode 100755
index 0000000..651ea7b
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_g_fully.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_g_fully.png
new file mode 100755
index 0000000..5942471
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_g_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_g_fully_roam.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_g_fully_roam.png
new file mode 100755
index 0000000..9699a3a
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_g_fully_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_g_roam.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_g_roam.png
new file mode 100755
index 0000000..d976f3d
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_g_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_gsm.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_gsm.png
new file mode 100755
index 0000000..1422d93
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_gsm.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_gsm_fully.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_gsm_fully.png
new file mode 100755
index 0000000..0ef879b
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_gsm_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_sim1_4g.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_sim1_4g.png
new file mode 100644
index 0000000..dfc663d
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_sim1_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_sim2_4g.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_sim2_4g.png
new file mode 100644
index 0000000..27be3f8
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_sim2_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_3g.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_3g.png
new file mode 100755
index 0000000..8ff5ac8
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_3g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_3g_default.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_3g_default.png
new file mode 100755
index 0000000..655edc3
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_3g_default.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_3g_default_fully.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_3g_default_fully.png
new file mode 100755
index 0000000..e151a7e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_3g_default_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_3g_default_fully_roam.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_3g_default_fully_roam.png
new file mode 100755
index 0000000..9dc081b
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_3g_default_fully_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_3g_default_roam.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_3g_default_roam.png
new file mode 100755
index 0000000..5176104
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_3g_default_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_3g_fully.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_3g_fully.png
new file mode 100755
index 0000000..1c92928
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_3g_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_4g.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_4g.png
new file mode 100755
index 0000000..7ebf56c
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_4g_default.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_4g_default.png
new file mode 100755
index 0000000..d781934
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_4g_default.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_4g_default_fully.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_4g_default_fully.png
new file mode 100755
index 0000000..71aa042
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_4g_default_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_4g_default_fully_roam.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_4g_default_fully_roam.png
new file mode 100755
index 0000000..3091f56
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_4g_default_fully_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_4g_default_roam.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_4g_default_roam.png
new file mode 100755
index 0000000..60344dd
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_4g_default_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_4g_fully.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_4g_fully.png
new file mode 100755
index 0000000..b6689b5
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_4g_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_e.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_e.png
new file mode 100755
index 0000000..79ca14f
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_e.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_e_fully.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_e_fully.png
new file mode 100755
index 0000000..e049773
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_e_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_e_fully_roam.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_e_fully_roam.png
new file mode 100755
index 0000000..3d5e598
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_e_fully_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_e_roam.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_e_roam.png
new file mode 100755
index 0000000..5bec840
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_e_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_fully_sim1_4g.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_fully_sim1_4g.png
new file mode 100644
index 0000000..3c33f6d
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_fully_sim1_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_fully_sim2_4g.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_fully_sim2_4g.png
new file mode 100644
index 0000000..7fc774b
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_fully_sim2_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_g.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_g.png
new file mode 100755
index 0000000..51187f9
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_g_fully.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_g_fully.png
new file mode 100755
index 0000000..ea5baa1
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_g_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_g_fully_roam.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_g_fully_roam.png
new file mode 100755
index 0000000..b3a322c
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_g_fully_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_g_roam.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_g_roam.png
new file mode 100755
index 0000000..5ac30c8
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_g_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_gsm.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_gsm.png
new file mode 100755
index 0000000..b5b3611
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_gsm.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_gsm_fully.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_gsm_fully.png
new file mode 100755
index 0000000..7f3f307
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_gsm_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_sim1_4g.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_sim1_4g.png
new file mode 100644
index 0000000..40096e8
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_sim1_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_sim2_4g.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_sim2_4g.png
new file mode 100644
index 0000000..5a04863
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_sim2_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_3g.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_3g.png
new file mode 100755
index 0000000..12a75c69
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_3g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_3g_default.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_3g_default.png
new file mode 100755
index 0000000..078f837
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_3g_default.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_3g_default_fully.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_3g_default_fully.png
new file mode 100755
index 0000000..f4a0cc2
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_3g_default_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_3g_default_fully_roam.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_3g_default_fully_roam.png
new file mode 100755
index 0000000..20581f7
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_3g_default_fully_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_3g_default_roam.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_3g_default_roam.png
new file mode 100755
index 0000000..b03871f
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_3g_default_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_3g_fully.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_3g_fully.png
new file mode 100755
index 0000000..9583d93
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_3g_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_4g.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_4g.png
new file mode 100755
index 0000000..e9313ec
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_4g_default.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_4g_default.png
new file mode 100755
index 0000000..5a2000b
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_4g_default.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_4g_default_fully.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_4g_default_fully.png
new file mode 100755
index 0000000..91460b2
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_4g_default_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_4g_default_fully_roam.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_4g_default_fully_roam.png
new file mode 100755
index 0000000..b9d5228
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_4g_default_fully_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_4g_default_roam.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_4g_default_roam.png
new file mode 100755
index 0000000..6f6e6f8
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_4g_default_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_4g_fully.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_4g_fully.png
new file mode 100755
index 0000000..50cd5b4
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_4g_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_e.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_e.png
new file mode 100755
index 0000000..8439cef
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_e.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_e_fully.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_e_fully.png
new file mode 100755
index 0000000..77931bc
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_e_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_e_fully_roam.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_e_fully_roam.png
new file mode 100755
index 0000000..2e662e6
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_e_fully_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_e_roam.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_e_roam.png
new file mode 100755
index 0000000..31f52ac
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_e_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_fully_sim1_4g.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_fully_sim1_4g.png
new file mode 100644
index 0000000..a9b3b19
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_fully_sim1_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_fully_sim2_4g.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_fully_sim2_4g.png
new file mode 100644
index 0000000..736c191
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_fully_sim2_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_g.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_g.png
new file mode 100755
index 0000000..f3ffb3b
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_g_fully.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_g_fully.png
new file mode 100755
index 0000000..6360202
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_g_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_g_fully_roam.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_g_fully_roam.png
new file mode 100755
index 0000000..6097971
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_g_fully_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_g_roam.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_g_roam.png
new file mode 100755
index 0000000..64cdc95
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_g_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_gsm.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_gsm.png
new file mode 100755
index 0000000..6486bbf
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_gsm.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_gsm_fully.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_gsm_fully.png
new file mode 100755
index 0000000..95eb1f2
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_gsm_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_sim1_4g.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_sim1_4g.png
new file mode 100644
index 0000000..ed09e62
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_sim1_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_sim2_4g.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_sim2_4g.png
new file mode 100644
index 0000000..ca24721
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_sim2_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_3g.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_3g.png
new file mode 100755
index 0000000..61d2d85
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_3g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_3g_default.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_3g_default.png
new file mode 100755
index 0000000..69fdc62
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_3g_default.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_3g_default_fully.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_3g_default_fully.png
new file mode 100755
index 0000000..13e6090
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_3g_default_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_3g_default_fully_roam.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_3g_default_fully_roam.png
new file mode 100755
index 0000000..a3310a0
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_3g_default_fully_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_3g_default_roam.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_3g_default_roam.png
new file mode 100755
index 0000000..a26b083
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_3g_default_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_3g_fully.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_3g_fully.png
new file mode 100755
index 0000000..fd3dd30
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_3g_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_4g.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_4g.png
new file mode 100755
index 0000000..eb38bbc
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_4g_default.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_4g_default.png
new file mode 100755
index 0000000..cb8fc4f
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_4g_default.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_4g_default_fully.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_4g_default_fully.png
new file mode 100755
index 0000000..fe055c7
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_4g_default_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_4g_default_fully_roam.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_4g_default_fully_roam.png
new file mode 100755
index 0000000..dcfa904
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_4g_default_fully_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_4g_default_roam.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_4g_default_roam.png
new file mode 100755
index 0000000..e7ef1df
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_4g_default_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_4g_fully.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_4g_fully.png
new file mode 100755
index 0000000..e16de169
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_4g_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_e.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_e.png
new file mode 100755
index 0000000..87e96cc
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_e.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_e_fully.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_e_fully.png
new file mode 100755
index 0000000..a2d0faa
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_e_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_e_fully_roam.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_e_fully_roam.png
new file mode 100755
index 0000000..6b52c5f
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_e_fully_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_e_roam.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_e_roam.png
new file mode 100755
index 0000000..477a5fe
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_e_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_fully_sim1_4g.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_fully_sim1_4g.png
new file mode 100644
index 0000000..52726fe
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_fully_sim1_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_fully_sim2_4g.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_fully_sim2_4g.png
new file mode 100644
index 0000000..47422b3
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_fully_sim2_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_g.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_g.png
new file mode 100755
index 0000000..b29d75e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_g_fully.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_g_fully.png
new file mode 100755
index 0000000..8920122
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_g_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_g_fully_roam.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_g_fully_roam.png
new file mode 100755
index 0000000..5769b58
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_g_fully_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_g_roam.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_g_roam.png
new file mode 100755
index 0000000..1487ca7
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_g_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_gsm.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_gsm.png
new file mode 100755
index 0000000..e0f48e1
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_gsm.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_gsm_fully.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_gsm_fully.png
new file mode 100755
index 0000000..11b6c41
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_gsm_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_sim1_4g.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_sim1_4g.png
new file mode 100644
index 0000000..542884b
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_sim1_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_sim2_4g.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_sim2_4g.png
new file mode 100644
index 0000000..8e5f608
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_sim2_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_3g.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_3g.png
new file mode 100755
index 0000000..76893c3
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_3g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_3g_default.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_3g_default.png
new file mode 100755
index 0000000..fe5ea01
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_3g_default.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_3g_default_fully.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_3g_default_fully.png
new file mode 100755
index 0000000..7576cdd
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_3g_default_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_3g_default_fully_roam.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_3g_default_fully_roam.png
new file mode 100755
index 0000000..7cdb571
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_3g_default_fully_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_3g_default_roam.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_3g_default_roam.png
new file mode 100755
index 0000000..0799418
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_3g_default_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_3g_fully.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_3g_fully.png
new file mode 100755
index 0000000..82577be
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_3g_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_4g.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_4g.png
new file mode 100755
index 0000000..4f3494c
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_4g_default.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_4g_default.png
new file mode 100755
index 0000000..39d3bee
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_4g_default.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_4g_default_fully.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_4g_default_fully.png
new file mode 100755
index 0000000..38c1a01
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_4g_default_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_4g_default_fully_roam.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_4g_default_fully_roam.png
new file mode 100755
index 0000000..c2452a9
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_4g_default_fully_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_4g_default_roam.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_4g_default_roam.png
new file mode 100755
index 0000000..77770e4
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_4g_default_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_4g_fully.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_4g_fully.png
new file mode 100755
index 0000000..24c5910
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_4g_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_e.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_e.png
new file mode 100755
index 0000000..cd10b05
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_e.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_e_fully.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_e_fully.png
new file mode 100755
index 0000000..d24e199
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_e_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_e_fully_roam.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_e_fully_roam.png
new file mode 100755
index 0000000..59da70a
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_e_fully_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_e_roam.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_e_roam.png
new file mode 100755
index 0000000..ac30d5e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_e_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_fully_sim1_4g.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_fully_sim1_4g.png
new file mode 100644
index 0000000..0338d28
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_fully_sim1_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_fully_sim2_4g.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_fully_sim2_4g.png
new file mode 100644
index 0000000..231d3c5
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_fully_sim2_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_g.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_g.png
new file mode 100755
index 0000000..5b03544
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_g_fully.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_g_fully.png
new file mode 100755
index 0000000..3ad515c
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_g_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_g_fully_roam.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_g_fully_roam.png
new file mode 100755
index 0000000..21d7c38
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_g_fully_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_g_roam.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_g_roam.png
new file mode 100755
index 0000000..5f1dd07
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_g_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_gsm.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_gsm.png
new file mode 100755
index 0000000..2e929d8
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_gsm.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_gsm_fully.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_gsm_fully.png
new file mode 100755
index 0000000..c8aad28
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_gsm_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_sim1_4g.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_sim1_4g.png
new file mode 100644
index 0000000..185e477
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_sim1_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_sim2_4g.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_sim2_4g.png
new file mode 100644
index 0000000..6fac79f
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_sim2_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_in.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_in.png
new file mode 100644
index 0000000..cc9c49f
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_in.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_inout.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_inout.png
new file mode 100644
index 0000000..5a313c5
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_inout.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_out.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_out.png
new file mode 100644
index 0000000..373a4a4
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_out.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_wifi_in.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_wifi_in.png
new file mode 100644
index 0000000..d299daf
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_wifi_in.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_wifi_inout.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_wifi_inout.png
new file mode 100644
index 0000000..dcfdb7b
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_wifi_inout.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_wifi_out.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_wifi_out.png
new file mode 100644
index 0000000..fb8125a
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_wifi_out.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_mini_settings.png b/packages/SystemUI/res/drawable-xxhdpi/ic_mini_settings.png
new file mode 100755
index 0000000..78bbc25
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_mini_settings.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_notification_overlay.9.png b/packages/SystemUI/res/drawable-xxhdpi/ic_notification_overlay.9.png
index fa7de0e..ea09774 100644
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_notification_overlay.9.png
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_notification_overlay.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_add.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_add.png
new file mode 100644
index 0000000..af182a6
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_add.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_add_land.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_add_land.png
new file mode 100644
index 0000000..cb601f3
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_add_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_ime_left.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_ime_left.png
new file mode 100644
index 0000000..08cbeef
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_ime_left.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_ime_right.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_ime_right.png
new file mode 100644
index 0000000..db4e888
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_ime_right.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_menu_big.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_menu_big.png
new file mode 100644
index 0000000..9664962
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_menu_big.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_menu_big_land.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_menu_big_land.png
new file mode 100644
index 0000000..bb677dc
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_menu_big_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_search.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_search.png
new file mode 100644
index 0000000..9fcc72d
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_search.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_search_land.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_search_land.png
new file mode 100644
index 0000000..b2ae541
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_search_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_notify_image.png b/packages/SystemUI/res/drawable-xxhdpi/stat_notify_image.png
deleted file mode 100644
index 5e733ef..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/stat_notify_image.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_notify_image_error.png b/packages/SystemUI/res/drawable-xxhdpi/stat_notify_image_error.png
deleted file mode 100644
index ecc2c83..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/stat_notify_image_error.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxxhdpi/ic_mini_settings.png b/packages/SystemUI/res/drawable-xxxhdpi/ic_mini_settings.png
new file mode 100755
index 0000000..6a6536e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxxhdpi/ic_mini_settings.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable/cid.xml b/packages/SystemUI/res/drawable/cid.xml
new file mode 100644
index 0000000..614a050
--- /dev/null
+++ b/packages/SystemUI/res/drawable/cid.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2014 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="48dp"
+ android:height="48dp"
+ android:viewportWidth="48"
+ android:viewportHeight="48">
+
+ <group>
+ <path
+ android:name="torso"
+ android:pathData="M35.616,28.128l-4.185-11.17c-0.37-0.966-1.233-1.561-2.11-1.862c-0.638-0.219-1.94-0.47-4.366-0.59h-1.91 c-2.427,0.12-3.729,0.371-4.367,0.59c-0.877,0.301-1.74,0.896-2.11,1.862l-4.185,11.17c-0.496,1.122,0.396,1.59,1.148,1.385 c0.809-0.221,1.518-0.506,2.084-1.866c0.309-0.742,2.818-7.124,2.818-7.124l-1.542,27.45c0,0,0.603,0,2.095,0 c0.967,0,2.209-1.01,2.419-3.358l0.931-12.818h0.709h0.104h0.562h0.241h0.005h0.085h0.005h0.241h0.562h0.104h0.709l0.931,12.818 c0.21,2.348,1.452,3.358,2.419,3.358c1.492,0,2.095,0,2.095,0l-1.542-27.45c0,0,2.509,6.382,2.818,7.124 c0.566,1.36,1.275,1.645,2.084,1.866C35.221,29.718,36.112,29.25,35.616,28.128Z M24,25.331c-1.817,0-3.295-1.478-3.295-3.295 c0-1.817,1.478-3.295,3.295-3.295c1.817,0,3.295,1.478,3.295,3.295C27.295,23.853,25.817,25.331,24,25.331z M26.616,22.036 c0,1.443-1.174,2.616-2.616,2.616c-1.443,0-2.616-1.174-2.616-2.616c0-1.442,1.174-2.616,2.616-2.616 C25.442,19.42,26.616,20.593,26.616,22.036z"
+ android:fillColor="#FFFFFF" />
+ <path
+ android:name="head"
+ android:pathData="M29.081,3.012l0.962-2.35c0.096-0.235-0.016-0.503-0.251-0.599c-0.235-0.096-0.503,0.016-0.599,0.251l-0.997,2.435 c-1.1-0.252-2.503-0.348-4.18-0.348v0.006h0V2.4c-0.219,0-0.432,0.002-0.642,0.006h-0.001c-1.396,0.023-2.581,0.124-3.537,0.343 l-0.997-2.435c-0.096-0.235-0.364-0.347-0.599-0.251c-0.235,0.096-0.347,0.364-0.251,0.599l0.962,2.35 c-1.277,0.483-1.955,1.3-1.955,2.612v2.752V9.09v0.784c0,2.411,2.284,3.151,6.377,3.218v0.004h0.254 c0.128,0.001,0.258,0.002,0.389,0.002v-0.002h0v0.002c0.131,0,0.261-0.001,0.389-0.002h0.018c4.242-0.042,6.613-0.764,6.613-3.221 V9.09V8.376V5.624C31.037,4.311,30.358,3.495,29.081,3.012Z M20.407,9.78c-1.16,0-2.1-0.94-2.1-2.1c0-1.16,0.94-2.1,2.1-2.1 c1.16,0,2.1,0.94,2.1,2.1C22.507,8.84,21.567,9.78,20.407,9.78z M24.237,11.303h-0.443c-0.326,0-0.591-0.264-0.591-0.591 c0-0.012,0.003-0.024,0.004-0.036h1.617c0.001,0.012,0.004,0.023,0.004,0.036C24.828,11.039,24.563,11.303,24.237,11.303z M27.625,9.78c-1.16,0-2.1-0.94-2.1-2.1c0-1.16,0.94-2.1,2.1-2.1c1.16,0,2.1,0.94,2.1,2.1C29.724,8.84,28.784,9.78,27.625,9.78z"
+ android:fillColor="#FFFFFF" />
+ </group>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_lockscreen_shortcuts_blank.xml b/packages/SystemUI/res/drawable/ic_lockscreen_shortcuts_blank.xml
new file mode 100644
index 0000000..1debdda
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_lockscreen_shortcuts_blank.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (c) 2015 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="@dimen/keyguard_affordance_icon_width"
+ android:height="@dimen/keyguard_affordance_icon_height"
+ android:viewportWidth="48"
+ android:viewportHeight="48">
+
+ <path
+ android:fillColor="#666666"
+ android:pathData="M14 10h4V6h-4v4zm0 16h4v-4h-4v4zm0 16h4v-4h-4v4zm8-8h4v-4h-4v4zm0 8h4v-4h-4v4zM6
+42h4v-4H6v4zm0-8h4v-4H6v4zm0-8h4v-4H6v4zm0-8h4v-4H6v4zm0-8h4V6H6v4zm16
+16h4v-4h-4v4zm16 8h4v-4h-4v4zm0-8h4v-4h-4v4zm0 16h4v-4h-4v4zm0-24h4v-4h-4v4zm-16
+0h4v-4h-4v4zM38 6v4h4V6h-4zm-16 4h4V6h-4v4zm8
+32h4v-4h-4v4zm0-16h4v-4h-4v4zm0-16h4V6h-4v4z" />
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_edit_tiles.xml b/packages/SystemUI/res/drawable/ic_qs_edit_tiles.xml
new file mode 100644
index 0000000..218228d
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_edit_tiles.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (c) 2015 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="48dp"
+ android:height="48dp"
+ android:viewportWidth="48"
+ android:viewportHeight="48">
+
+ <path
+ android:fillColor="#FFFFFF"
+ android:pathData="M4,32h4v4H4V32z M4,20h4v-4C5.8,16,4,17.8,4,20z M8,44v-4H4 C4,42.2,5.8,44,8,44z
+M4,28h4v-4H4V28z M12,44h4v-4h-4V44z
+M44,8v20c0,2.2-1.8,4-4,4h-8v4h-4v-4h-8c-2.2,0-4-1.8-4-4v-8h-4v-4h4V8
+c0-2.2,1.8-4,4-4h20C42.2,4,44,5.8,44,8z M40,8H20v20h20V8z
+M28,44c2.2,0,4-1.8,4-4h-4V44z M20,44h4v-4h-4V44z" />
+</vector> \ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_qs_signal_4g_plus.xml b/packages/SystemUI/res/drawable/ic_qs_signal_4g_plus.xml
new file mode 100644
index 0000000..cefb714
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_signal_4g_plus.xml
@@ -0,0 +1,50 @@
+<!--
+Copyright (c) 2015, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="18.0dp"
+ android:height="24dp"
+ android:viewportWidth="36.0"
+ android:viewportHeight="36.0">
+
+ <path
+ android:fillColor="#FFFFFF"
+ android:pathData="M6.797,13.334h1.231v1.522H6.797v2.509h-1.62v-2.509H1.101l-0.039-1.157l4.069-7.643h1.666V13.334z
+M2.648,13.334h2.53V8.721L5.137,8.713L4.984,9.148L2.648,13.334z" />
+ <path
+ android:fillColor="#FFFFFF"
+ android:pathData="M16.155,15.836c-0.269,0.439-0.695,0.832-1.282,1.177c-0.587,0.344-1.344,0.517-2.271,0.517
+c-1.151,0-2.098-0.432-2.841-1.294c-0.744-0.862-1.115-1.978-1.115-3.345v-2.36c0-1.367,0.359-2.481,1.077-3.343
+c0.719-0.863,1.643-1.293,2.772-1.293c1.132,0,2.017,0.331,2.649,0.994c0.633,0.663,0.941,1.528,0.924,2.594l-0.021,0.047h-1.545
+c0-0.638-0.171-1.15-0.513-1.538c-0.341-0.389-0.831-0.583-1.469-0.583c-0.674,0-1.217,0.292-1.63,0.877
+c-0.413,0.585-0.619,1.328-0.619,2.229v2.375c0,0.912,0.215,1.662,0.645,2.25c0.431,0.587,0.992,0.881,1.684,0.881
+c0.522,0,0.935-0.068,1.238-0.205c0.304-0.138,0.533-0.305,0.688-0.502v-2.338h-2.041v-1.413h3.668V15.836z" />
+ <path
+ android:fillColor="#FFFFFF"
+ android:pathData="M19.366,14.701v-2.232h-2.25v-1.541h2.25V8.695h1.5v2.232h2.256v1.541h-2.256v2.232H19.366z" />
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_settings.xml b/packages/SystemUI/res/drawable/ic_settings.xml
index 9c78742..545bc2d 100644
--- a/packages/SystemUI/res/drawable/ic_settings.xml
+++ b/packages/SystemUI/res/drawable/ic_settings.xml
@@ -1,26 +1,25 @@
-<!-- Copyright (C) 2014 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"+
+<!--
+ Copyright (C) 2015 The Android Open Source Project
-http://www.apache.org/licenses/LICENSE-2.0
+ 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.
+ 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.
-->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-android:width="24dp"
-android:height="24dp" android:viewportWidth="24.0"
- android:viewportHeight="24.0">
-
-
-<path
- android:pathData="M19.4,13.0c0.0,-0.3 0.1,-0.6 0.1,-1.0s0.0,-0.7 -0.1,-1.0l2.1,-1.7c0.2,-0.2 0.2,-0.4 0.1,-0.6l-2.0,-3.5C19.5,5.1 19.3,5.0 19.0,5.1l-2.5,1.0c-0.5,-0.4 -1.1,-0.7 -1.7,-1.0l-0.4,-2.6C14.5,2.2 14.2,2.0 14.0,2.0l-4.0,0.0C9.8,2.0 9.5,2.2 9.5,2.4L9.1,5.1C8.5,5.3 8.0,5.7 7.4,6.1L5.0,5.1C4.7,5.0 4.5,5.1 4.3,5.3l-2.0,3.5C2.2,8.9 2.3,9.2 2.5,9.4L4.6,11.0c0.0,0.3 -0.1,0.6 -0.1,1.0s0.0,0.7 0.1,1.0l-2.1,1.7c-0.2,0.2 -0.2,0.4 -0.1,0.6l2.0,3.5C4.5,18.9 4.7,19.0 5.0,18.9l2.5,-1.0c0.5,0.4 1.1,0.7 1.7,1.0l0.4,2.6c0.0,0.2 0.2,0.4 0.5,0.4l4.0,0.0c0.2,0.0 0.5,-0.2 0.5,-0.4l0.4,-2.6c0.6,-0.3 1.2,-0.6 1.7,-1.0l2.5,1.0c0.2,0.1 0.5,0.0 0.6,-0.2l2.0,-3.5c0.1,-0.2 0.1,-0.5 -0.1,-0.6L19.4,13.0zM12.0,15.5c-1.9,0.0 -3.5,-1.6 -3.5,-3.5s1.6,-3.5 3.5,-3.5s3.5,1.6 3.5,3.5S13.9,15.5 12.0,15.5z"
- android:fillColor="#ffffffff"
- />
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:pathData="M19.4,13.0c0.0,-0.3 0.1,-0.6 0.1,-1.0s0.0,-0.7 -0.1,-1.0l2.1,-1.7c0.2,-0.2 0.2,-0.4 0.1,-0.6l-2.0,-3.5C19.5,5.1 19.3,5.0 19.0,5.1l-2.5,1.0c-0.5,-0.4 -1.1,-0.7 -1.7,-1.0l-0.4,-2.6C14.5,2.2 14.2,2.0 14.0,2.0l-4.0,0.0C9.8,2.0 9.5,2.2 9.5,2.4L9.1,5.1C8.5,5.3 8.0,5.7 7.4,6.1L5.0,5.1C4.7,5.0 4.5,5.1 4.3,5.3l-2.0,3.5C2.2,8.9 2.3,9.2 2.5,9.4L4.6,11.0c0.0,0.3 -0.1,0.6 -0.1,1.0s0.0,0.7 0.1,1.0l-2.1,1.7c-0.2,0.2 -0.2,0.4 -0.1,0.6l2.0,3.5C4.5,18.9 4.7,19.0 5.0,18.9l2.5,-1.0c0.5,0.4 1.1,0.7 1.7,1.0l0.4,2.6c0.0,0.2 0.2,0.4 0.5,0.4l4.0,0.0c0.2,0.0 0.5,-0.2 0.5,-0.4l0.4,-2.6c0.6,-0.3 1.2,-0.6 1.7,-1.0l2.5,1.0c0.2,0.1 0.5,0.0 0.6,-0.2l2.0,-3.5c0.1,-0.2 0.1,-0.5 -0.1,-0.6L19.4,13.0zM12.0,15.5c-1.9,0.0 -3.5,-1.6 -3.5,-3.5s1.6,-3.5 3.5,-3.5s3.5,1.6 3.5,3.5S13.9,15.5 12.0,15.5z"
+ android:fillColor="#ffffffff" />
</vector>
diff --git a/packages/SystemUI/res/drawable/lockscreen_shortcuts_phone_background.xml b/packages/SystemUI/res/drawable/lockscreen_shortcuts_phone_background.xml
new file mode 100644
index 0000000..e3cae61
--- /dev/null
+++ b/packages/SystemUI/res/drawable/lockscreen_shortcuts_phone_background.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<layer-list
+ xmlns:android="http://schemas.android.com/apk/res/android" >
+ <item>
+ <shape
+ android:shape="rectangle">
+ <solid
+ android:color="#333333" />
+ <size android:height="@dimen/phone_height" android:width="@dimen/phone_width" />
+ <corners android:bottomLeftRadius="15dp" android:bottomRightRadius="15dp" />
+ </shape>
+ </item>
+ <item android:bottom="@dimen/phone_bottom_padding" android:right="@dimen/phone_side_padding" android:left="@dimen/phone_side_padding">
+ <shape
+ android:shape="rectangle">
+ <solid
+ android:color="@android:color/black" />
+ </shape>
+ </item>
+</layer-list>
+
diff --git a/packages/SystemUI/res/drawable/lockscreen_target_background.xml b/packages/SystemUI/res/drawable/lockscreen_target_background.xml
new file mode 100644
index 0000000..d26da7e
--- /dev/null
+++ b/packages/SystemUI/res/drawable/lockscreen_target_background.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+ <!--
+ Copyright (C) 2014 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.
+-->
+
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+ android:color="#DDDDDD">
+</ripple>
diff --git a/packages/SystemUI/res/drawable/notification_guts_ic_ringer_mute.xml b/packages/SystemUI/res/drawable/notification_guts_ic_ringer_mute.xml
new file mode 100644
index 0000000..63c8315
--- /dev/null
+++ b/packages/SystemUI/res/drawable/notification_guts_ic_ringer_mute.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2015 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.
+-->
+<layer-list
+ xmlns:android="http://schemas.android.com/apk/res/android" >
+ <item android:drawable="@drawable/ic_volume_ringer_mute" />
+</layer-list>
diff --git a/packages/SystemUI/res/drawable/notification_guts_ic_settings.xml b/packages/SystemUI/res/drawable/notification_guts_ic_settings.xml
new file mode 100644
index 0000000..312a55f
--- /dev/null
+++ b/packages/SystemUI/res/drawable/notification_guts_ic_settings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2015 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.
+-->
+<layer-list
+ xmlns:android="http://schemas.android.com/apk/res/android" >
+ <item android:drawable="@drawable/ic_settings" />
+</layer-list>
diff --git a/packages/SystemUI/res/drawable/qs_tile_background_drag.xml b/packages/SystemUI/res/drawable/qs_tile_background_drag.xml
new file mode 100644
index 0000000..0a3ba2d
--- /dev/null
+++ b/packages/SystemUI/res/drawable/qs_tile_background_drag.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2015, 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.
+*/
+-->
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="oval">
+ <solid android:color="#FF37474f" />
+</shape>
diff --git a/packages/SystemUI/res/drawable/stat_notify_image.xml b/packages/SystemUI/res/drawable/stat_notify_image.xml
new file mode 100644
index 0000000..17c1bda
--- /dev/null
+++ b/packages/SystemUI/res/drawable/stat_notify_image.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (c) 2015 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+
+ <path
+ android:fillColor="#FFFFFF"
+ android:pathData="M21,19V5c0-1.1-0.9-2-2-2H5C3.9,3,3,3.9,3,5v14c0,1.1,0.9,2,2,2h14C20.1,21,21,20.1,21,19z
+M8.5,13.5l2.5,3l3.5-4.5l4.5,6H5 L8.5,13.5z" />
+</vector> \ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/stat_notify_image_error.xml b/packages/SystemUI/res/drawable/stat_notify_image_error.xml
new file mode 100644
index 0000000..3c2ca40
--- /dev/null
+++ b/packages/SystemUI/res/drawable/stat_notify_image_error.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (c) 2015 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+
+ <path
+ android:fillColor="#FFFFFF"
+ android:pathData="M19,3H5C3.9,3,3,3.9,3,5v14c0,1.1,0.9,2,2,2h14c1.1,0,2-0.9,2-2V5C21,3.9,20.1,3,19,3z
+M14,12v6h-2h-1H5 l3.5-4.5L10,15l3-4L14,12z M18,18h-2v-2h2V18z M18,14h-2V7h2V14z" />
+</vector> \ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_4g_plus.xml b/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_4g_plus.xml
new file mode 100644
index 0000000..59e880b
--- /dev/null
+++ b/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_4g_plus.xml
@@ -0,0 +1,50 @@
+<!--
+Copyright (c) 2015, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="15dp"
+ android:height="20dp"
+ android:viewportWidth="36"
+ android:viewportHeight="36">
+
+ <path
+ android:fillColor="#FFFFFF"
+ android:pathData="M6.797,13.334h1.231v1.522H6.797v2.509h-1.62v-2.509H1.101l-0.039-1.157l4.069-7.643h1.666V13.334z
+M2.648,13.334h2.53V8.721L5.137,8.713L4.984,9.148L2.648,13.334z" />
+ <path
+ android:fillColor="#FFFFFF"
+ android:pathData="M16.155,15.836c-0.269,0.439-0.695,0.832-1.282,1.177c-0.587,0.344-1.344,0.517-2.271,0.517
+c-1.151,0-2.098-0.432-2.841-1.294c-0.744-0.862-1.115-1.978-1.115-3.345v-2.36c0-1.367,0.359-2.481,1.077-3.343
+c0.719-0.863,1.643-1.293,2.772-1.293c1.132,0,2.017,0.331,2.649,0.994c0.633,0.663,0.941,1.528,0.924,2.594l-0.021,0.047h-1.545
+c0-0.638-0.171-1.15-0.513-1.538c-0.341-0.389-0.831-0.583-1.469-0.583c-0.674,0-1.217,0.292-1.63,0.877
+c-0.413,0.585-0.619,1.328-0.619,2.229v2.375c0,0.912,0.215,1.662,0.645,2.25c0.431,0.587,0.992,0.881,1.684,0.881
+c0.522,0,0.935-0.068,1.238-0.205c0.304-0.138,0.533-0.305,0.688-0.502v-2.338h-2.041v-1.413h3.668V15.836z" />
+ <path
+ android:fillColor="#FFFFFF"
+ android:pathData="M19.366,14.701v-2.232h-2.25v-1.541h2.25V8.695h1.5v2.232h2.256v1.541h-2.256v2.232H19.366z" />
+</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_signal_in_auto_mirrored.xml b/packages/SystemUI/res/drawable/stat_sys_signal_in_auto_mirrored.xml
new file mode 100644
index 0000000..aad8e31
--- /dev/null
+++ b/packages/SystemUI/res/drawable/stat_sys_signal_in_auto_mirrored.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (c) 2015, The Linux Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+-->
+<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
+ android:src="@drawable/stat_sys_signal_in"
+ android:autoMirrored="true">
+</bitmap>
diff --git a/packages/SystemUI/res/drawable/stat_sys_signal_inout_auto_mirrored.xml b/packages/SystemUI/res/drawable/stat_sys_signal_inout_auto_mirrored.xml
new file mode 100644
index 0000000..012afd3
--- /dev/null
+++ b/packages/SystemUI/res/drawable/stat_sys_signal_inout_auto_mirrored.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (c) 2015, The Linux Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+-->
+<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
+ android:src="@drawable/stat_sys_signal_inout"
+ android:autoMirrored="true">
+</bitmap>
diff --git a/packages/SystemUI/res/drawable/stat_sys_signal_out_auto_mirrored.xml b/packages/SystemUI/res/drawable/stat_sys_signal_out_auto_mirrored.xml
new file mode 100644
index 0000000..27d37ae
--- /dev/null
+++ b/packages/SystemUI/res/drawable/stat_sys_signal_out_auto_mirrored.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (c) 2015, The Linux Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+-->
+<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
+ android:src="@drawable/stat_sys_signal_out"
+ android:autoMirrored="true">
+</bitmap>
diff --git a/packages/SystemUI/res/drawable/stat_sys_su.xml b/packages/SystemUI/res/drawable/stat_sys_su.xml
new file mode 100644
index 0000000..e013c13
--- /dev/null
+++ b/packages/SystemUI/res/drawable/stat_sys_su.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<inset xmlns:android="http://schemas.android.com/apk/res/android"
+ android:insetLeft="2.5dp"
+ android:insetRight="2.5dp">
+ <vector
+ android:width="23dp"
+ android:height="18dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M12.49,15.934h-2.373L9.24,21H6.966l0.89-5.066H5.051v-2.089h3.163l0.63-3.584H5.977V8.148h3.238 l0.902-5.141h2.261l-0.902,5.141h2.373l0.914-5.141h2.261l-0.902,5.141h2.719v2.113h-3.089l-0.63,3.584h2.78v2.089h-3.139L13.874,21 H11.6L12.49,15.934Z M10.488,13.845h2.36l0.63-3.584h-2.373L10.488,13.845z" />
+ </vector>
+</inset>
diff --git a/packages/SystemUI/res/drawable/volume_dialog_background.xml b/packages/SystemUI/res/drawable/volume_dialog_background.xml
index f09c01b..8ac471f 100644
--- a/packages/SystemUI/res/drawable/volume_dialog_background.xml
+++ b/packages/SystemUI/res/drawable/volume_dialog_background.xml
@@ -19,4 +19,4 @@
<corners android:radius="@dimen/notification_material_rounded_rect_radius" />
-</shape> \ No newline at end of file
+</shape>
diff --git a/packages/SystemUI/res/drawable/zen_mode_panel_background.xml b/packages/SystemUI/res/drawable/zen_mode_panel_background.xml
new file mode 100644
index 0000000..a91520a
--- /dev/null
+++ b/packages/SystemUI/res/drawable/zen_mode_panel_background.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2015 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.
+ -->
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+ <solid android:color="@color/system_secondary_color" />
+ <corners
+ android:topLeftRadius="0dp"
+ android:topRightRadius="0dp"
+ android:bottomLeftRadius="@dimen/zen_mode_panel_radius"
+ android:bottomRightRadius="@dimen/zen_mode_panel_radius"/>
+</shape>
diff --git a/packages/SystemUI/res/layout-sw600dp/mid_navigation_bar_land.xml b/packages/SystemUI/res/layout-sw600dp/mid_navigation_bar_land.xml
new file mode 100644
index 0000000..43426d1
--- /dev/null
+++ b/packages/SystemUI/res/layout-sw600dp/mid_navigation_bar_land.xml
@@ -0,0 +1,115 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2015, 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.
+-->
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:systemui="http://schemas.android.com/apk/res-auto"
+ android:layout_height="match_parent"
+ android:layout_width="match_parent"
+ android:orientation="horizontal"
+ android:clipChildren="false"
+ android:clipToPadding="false"
+ android:id="@+id/nav_buttons">
+ <com.android.systemui.statusbar.policy.KeyButtonView
+ android:id="@+id/dpad_left"
+ android:visibility="gone"
+ android:layout_width="48dp"
+ android:layout_height="match_parent"
+ android:layout_weight="0"
+ android:scaleType="centerInside"
+ systemui:keyRepeat="true" />
+ <com.android.systemui.statusbar.policy.KeyButtonView
+ android:id="@+id/one"
+ android:layout_width="48dp"
+ android:layout_height="match_parent"
+ android:layout_weight="0"
+ android:scaleType="centerInside" />
+ <View
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_weight="1" />
+ <LinearLayout
+ android:layout_height="match_parent"
+ android:layout_width="wrap_content"
+ android:layout_weight="1"
+ android:clipChildren="false"
+ android:clipToPadding="false"
+ android:id="@+id/mid_nav_buttons"
+ android:gravity="center_horizontal"
+ android:layout_gravity="center_horizontal"
+ android:animateLayoutChanges="true">
+ <com.android.systemui.statusbar.policy.KeyButtonView
+ android:id="@+id/two"
+ android:scaleType="centerInside"
+ android:layout_width="162dp" android:paddingLeft="42dp" android:paddingRight="42dp"
+ android:layout_height="match_parent"
+ systemui:keyRepeat="true"
+ android:layout_weight="0" />
+ <com.android.systemui.statusbar.policy.KeyButtonView
+ android:id="@+id/three"
+ android:scaleType="centerInside"
+ android:layout_width="162dp" android:paddingLeft="42dp" android:paddingRight="42dp"
+ android:layout_height="match_parent"
+ systemui:keyRepeat="true"
+ android:layout_weight="0" />
+ <com.android.systemui.statusbar.policy.KeyButtonView
+ android:id="@+id/four"
+ android:scaleType="centerInside"
+ android:layout_width="162dp" android:paddingLeft="42dp" android:paddingRight="42dp"
+ android:layout_height="match_parent"
+ android:layout_weight="0"
+ systemui:keyRepeat="true" />
+ <com.android.systemui.statusbar.policy.KeyButtonView
+ android:id="@+id/five"
+ android:scaleType="centerInside"
+ android:layout_width="162dp" android:paddingLeft="42dp" android:paddingRight="42dp"
+ android:layout_height="match_parent"
+ android:layout_weight="0"
+ systemui:keyRepeat="true" />
+ </LinearLayout>
+ <View
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_weight="1" />
+ <FrameLayout
+ android:layout_width="@dimen/navigation_extra_key_width"
+ android:layout_height="match_parent"
+ android:layout_weight="0"
+ android:layout_marginEnd="2dp" >
+ <com.android.systemui.statusbar.policy.KeyButtonView
+ android:id="@+id/ime_switcher"
+ android:layout_width="@dimen/navigation_extra_key_width"
+ android:layout_height="match_parent"
+ android:layout_marginEnd="2dp"
+ android:scaleType="centerInside"
+ android:src="@drawable/ic_ime_switcher_default"
+ android:visibility="invisible"
+ android:contentDescription="@string/accessibility_ime_switch_button" />
+ <com.android.systemui.statusbar.policy.KeyButtonView
+ android:id="@+id/six"
+ android:scaleType="centerInside"
+ android:layout_width="@dimen/navigation_extra_key_width"
+ android:layout_height="match_parent" />
+ <com.android.systemui.statusbar.policy.KeyButtonView
+ android:id="@+id/dpad_right"
+ android:visibility="gone"
+ android:layout_width="48dp"
+ android:layout_height="match_parent"
+ android:layout_weight="0"
+ android:scaleType="centerInside"
+ systemui:keyRepeat="true"/>
+ </FrameLayout>
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout-sw600dp/mid_navigation_bar_port.xml b/packages/SystemUI/res/layout-sw600dp/mid_navigation_bar_port.xml
new file mode 100644
index 0000000..a7dedbd
--- /dev/null
+++ b/packages/SystemUI/res/layout-sw600dp/mid_navigation_bar_port.xml
@@ -0,0 +1,132 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2015 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.
+*/
+-->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:systemui="http://schemas.android.com/apk/res-auto"
+ android:layout_height="match_parent"
+ android:layout_width="match_parent"
+ android:orientation="horizontal"
+ android:clipChildren="false"
+ android:clipToPadding="false"
+ android:id="@+id/nav_buttons">
+ <FrameLayout
+ android:layout_width="@dimen/navigation_extra_key_width"
+ android:layout_height="match_parent"
+ android:layout_weight="0">
+ <com.android.systemui.statusbar.policy.KeyButtonView
+ android:id="@+id/dpad_left"
+ android:visibility="gone"
+ android:layout_width="48dp"
+ android:layout_height="match_parent"
+ android:layout_weight="0"
+ android:scaleType="fitCenter"
+ systemui:keyRepeat="true" />
+ <com.android.systemui.statusbar.policy.KeyButtonView
+ android:id="@+id/dpad_left"
+ android:visibility="gone"
+ android:layout_width="48dp"
+ android:layout_height="match_parent"
+ android:layout_weight="0"
+ android:scaleType="fitCenter"
+ systemui:keyRepeat="true" />
+ <com.android.systemui.statusbar.policy.KeyButtonView
+ android:id="@+id/one"
+ android:layout_width="@dimen/navigation_extra_key_width"
+ android:layout_height="match_parent"
+ android:layout_weight="0"
+ android:scaleType="fitCenter" />
+ </FrameLayout>
+ <View
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_weight="1" />
+ <LinearLayout
+ android:layout_height="match_parent"
+ android:layout_width="wrap_content"
+ android:layout_weight="1"
+ android:clipChildren="false"
+ android:clipToPadding="false"
+ android:id="@+id/mid_nav_buttons"
+ android:gravity="center_horizontal"
+ android:layout_gravity="center_horizontal"
+ android:animateLayoutChanges="true">
+ <com.android.systemui.statusbar.policy.KeyButtonView
+ android:id="@+id/two"
+ android:scaleType="centerInside"
+ android:layout_width="128dp" android:paddingLeft="25dp" android:paddingRight="25dp"
+ android:layout_height="match_parent"
+ systemui:keyRepeat="true"
+ android:layout_weight="0" />
+ <com.android.systemui.statusbar.policy.KeyButtonView
+ android:id="@+id/three"
+ android:scaleType="centerInside"
+ android:layout_width="128dp" android:paddingLeft="25dp" android:paddingRight="25dp"
+ android:layout_height="match_parent"
+ systemui:keyRepeat="true"
+ android:layout_weight="0" />
+ <com.android.systemui.statusbar.policy.KeyButtonView
+ android:id="@+id/four"
+ android:scaleType="centerInside"
+ android:layout_width="128dp" android:paddingLeft="25dp" android:paddingRight="25dp"
+ android:layout_height="match_parent"
+ android:layout_weight="0"
+ systemui:keyRepeat="true" />
+ <com.android.systemui.statusbar.policy.KeyButtonView
+ android:id="@+id/five"
+ android:scaleType="centerInside"
+ android:layout_width="128dp" android:paddingLeft="25dp" android:paddingRight="25dp"
+ android:layout_height="match_parent"
+ android:layout_weight="0"
+ systemui:keyRepeat="true" />
+ </LinearLayout>
+ <View
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_weight="1" />
+ <FrameLayout
+ android:layout_width="@dimen/navigation_extra_key_width"
+ android:layout_height="match_parent"
+ android:layout_weight="0"
+ android:layout_marginEnd="2dp" >
+ <com.android.systemui.statusbar.policy.KeyButtonView
+ android:id="@+id/ime_switcher"
+ android:layout_width="@dimen/navigation_extra_key_width"
+ android:layout_height="match_parent"
+ android:scaleType="centerInside"
+ android:src="@drawable/ic_ime_switcher_default"
+ android:visibility="invisible"
+ android:contentDescription="@string/accessibility_ime_switch_button" />
+ <com.android.systemui.statusbar.policy.KeyButtonView
+ android:id="@+id/six"
+ android:layout_width="@dimen/navigation_extra_key_width"
+ android:layout_height="match_parent"
+ android:layout_weight="0"
+ android:scaleType="centerInside" />
+ <com.android.systemui.statusbar.policy.KeyButtonView
+ android:id="@+id/dpad_right"
+ android:visibility="gone"
+ android:layout_width="48dp"
+ android:layout_height="match_parent"
+ android:layout_weight="0"
+ android:scaleType="centerInside"
+ systemui:keyRepeat="true" />
+ </FrameLayout>
+
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout-sw600dp/navigation_bar.xml b/packages/SystemUI/res/layout-sw600dp/navigation_bar.xml
index 9912343..68883ce 100644
--- a/packages/SystemUI/res/layout-sw600dp/navigation_bar.xml
+++ b/packages/SystemUI/res/layout-sw600dp/navigation_bar.xml
@@ -3,16 +3,16 @@
**
** Copyright 2012, The Android Open Source Project
**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
**
-** http://www.apache.org/licenses/LICENSE-2.0
+** http://www.apache.org/licenses/LICENSE-2.0
**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
** limitations under the License.
-->
@@ -36,126 +36,65 @@
android:orientation="horizontal"
android:clipChildren="false"
android:clipToPadding="false"
- android:id="@+id/nav_buttons"
- android:animateLayoutChanges="true"
+ android:id="@+id/container"
>
- <!-- navigation controls -->
- <View
- android:layout_width="@dimen/navigation_extra_key_width"
- android:layout_height="match_parent"
- android:layout_weight="0"
- android:layout_marginStart="2dp"
- android:visibility="invisible"
- />
- <Space
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_weight="1"
- />
- <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/back"
- android:layout_width="128dp" android:paddingStart="25dp" android:paddingEnd="25dp"
- android:layout_height="match_parent"
- android:src="@drawable/ic_sysbar_back"
- android:scaleType="centerInside"
- systemui:keyCode="4"
- android:layout_weight="0"
- android:contentDescription="@string/accessibility_back"
- />
- <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/home"
- android:layout_width="128dp" android:paddingStart="25dp" android:paddingEnd="25dp"
- android:layout_height="match_parent"
- android:src="@drawable/ic_sysbar_home"
- android:scaleType="centerInside"
- systemui:keyCode="3"
- systemui:keyRepeat="true"
- android:layout_weight="0"
- android:contentDescription="@string/accessibility_home"
- />
- <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/recent_apps"
- android:layout_width="128dp" android:paddingStart="25dp" android:paddingEnd="25dp"
- android:layout_height="match_parent"
- android:src="@drawable/ic_sysbar_recent"
- android:scaleType="centerInside"
- android:layout_weight="0"
- android:contentDescription="@string/accessibility_recent"
- />
- <Space
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_weight="1"
- />
- <FrameLayout
- android:layout_width="@dimen/navigation_extra_key_width"
- android:layout_height="match_parent"
- android:layout_weight="0"
- android:layout_marginEnd="2dp" >
- <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/menu"
- android:layout_width="@dimen/navigation_extra_key_width"
- android:layout_height="match_parent"
- android:src="@drawable/ic_sysbar_menu"
- android:scaleType="centerInside"
- android:layout_marginEnd="2dp"
- systemui:keyCode="82"
- android:visibility="invisible"
- android:contentDescription="@string/accessibility_menu"
- />
- <com.android.systemui.statusbar.policy.KeyButtonView
- android:id="@+id/ime_switcher"
- android:layout_width="@dimen/navigation_extra_key_width"
- android:layout_height="match_parent"
- android:layout_marginEnd="2dp"
- android:scaleType="centerInside"
- android:src="@drawable/ic_ime_switcher_default"
- android:visibility="invisible"
- android:contentDescription="@string/accessibility_ime_switch_button" />
- </FrameLayout>
+ <include layout="@layout/mid_navigation_bar_port"/>
+
</LinearLayout>
- <!-- lights out layout to match exactly -->
- <LinearLayout
+ <LinearLayout
android:layout_height="match_parent"
android:layout_width="match_parent"
android:orientation="horizontal"
- android:id="@+id/lights_out"
- android:visibility="gone"
+ android:gravity="center_horizontal"
+ android:layout_gravity="center_horizontal"
>
- <Space
- android:layout_width="match_parent"
+ <View
+ android:layout_width="0dp"
android:layout_height="match_parent"
- android:layout_weight="1"
- />
- <ImageView
- android:layout_width="128dp" android:paddingStart="25dp" android:paddingEnd="25dp"
+ android:layout_weight="1" />
+ <!-- lights out layout to match exactly -->
+ <LinearLayout
android:layout_height="match_parent"
+ android:layout_width="wrap_content"
+ android:layout_weight="1"
+ android:orientation="horizontal"
+ android:gravity="center_horizontal"
android:layout_marginStart="40dp"
- android:src="@drawable/ic_sysbar_lights_out_dot_small"
- android:scaleType="center"
- android:layout_weight="0"
- android:contentDescription="@string/accessibility_back"
- />
- <ImageView
- android:layout_width="128dp" android:paddingStart="25dp" android:paddingEnd="25dp"
- android:layout_height="match_parent"
- android:src="@drawable/ic_sysbar_lights_out_dot_large"
- android:scaleType="center"
- android:layout_weight="0"
- android:contentDescription="@string/accessibility_home"
- />
- <ImageView
- android:layout_width="128dp" android:paddingStart="25dp" android:paddingEnd="25dp"
android:layout_marginEnd="40dp"
+ android:layout_gravity="center_horizontal"
+ android:id="@+id/lights_out"
+ android:visibility="gone">
+ <ImageView
+ android:layout_width="128dp" android:paddingStart="25dp" android:paddingEnd="25dp"
+ android:layout_height="match_parent"
+ android:src="@drawable/ic_sysbar_lights_out_dot_large"
+ android:scaleType="center"
+ />
+ <ImageView
+ android:layout_width="128dp" android:paddingStart="25dp" android:paddingEnd="25dp"
+ android:layout_height="match_parent"
+ android:src="@drawable/ic_sysbar_lights_out_dot_large"
+ android:scaleType="center"
+ />
+ <ImageView
+ android:layout_width="128dp" android:paddingStart="25dp" android:paddingEnd="25dp"
+ android:layout_height="match_parent"
+ android:src="@drawable/ic_sysbar_lights_out_dot_large"
+ android:scaleType="center"
+ />
+ <ImageView
+ android:layout_width="128dp" android:paddingStart="25dp" android:paddingEnd="25dp"
+ android:layout_height="match_parent"
+ android:src="@drawable/ic_sysbar_lights_out_dot_large"
+ android:scaleType="center"
+ />
+ </LinearLayout>
+ <View
+ android:layout_width="0dp"
android:layout_height="match_parent"
- android:src="@drawable/ic_sysbar_lights_out_dot_small"
- android:scaleType="center"
- android:layout_weight="0"
- android:contentDescription="@string/accessibility_recent"
- />
- <Space
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_weight="1"
- />
+ android:layout_weight="1" />
</LinearLayout>
<com.android.systemui.statusbar.policy.DeadZone
@@ -182,127 +121,72 @@
android:layout_height="match_parent"
android:layout_width="match_parent"
android:orientation="horizontal"
+ android:gravity="center_horizontal"
+ android:layout_gravity="center_horizontal"
android:clipChildren="false"
android:clipToPadding="false"
- android:id="@+id/nav_buttons"
- android:animateLayoutChanges="true"
+ android:id="@+id/container"
>
- <!-- navigation controls -->
- <View
- android:layout_width="@dimen/navigation_extra_key_width"
- android:layout_height="match_parent"
- android:layout_weight="0"
- android:layout_marginStart="2dp"
- android:visibility="invisible"
- />
- <Space
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_weight="1"
- />
- <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/back"
- android:layout_width="162dp" android:paddingStart="42dp" android:paddingEnd="42dp"
- android:layout_height="match_parent"
- android:src="@drawable/ic_sysbar_back"
- android:scaleType="centerInside"
- systemui:keyCode="4"
- android:layout_weight="0"
- android:contentDescription="@string/accessibility_back"
- />
- <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/home"
- android:layout_width="162dp" android:paddingStart="42dp" android:paddingEnd="42dp"
- android:layout_height="match_parent"
- android:src="@drawable/ic_sysbar_home"
- android:scaleType="centerInside"
- systemui:keyCode="3"
- systemui:keyRepeat="true"
- android:layout_weight="0"
- android:contentDescription="@string/accessibility_home"
- />
- <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/recent_apps"
- android:layout_width="162dp" android:paddingStart="42dp" android:paddingEnd="42dp"
- android:layout_height="match_parent"
- android:src="@drawable/ic_sysbar_recent"
- android:scaleType="centerInside"
- android:layout_weight="0"
- android:contentDescription="@string/accessibility_recent"
- />
- <Space
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_weight="1"
- />
- <FrameLayout
- android:layout_width="@dimen/navigation_extra_key_width"
- android:layout_height="match_parent"
- android:layout_marginEnd="2dp"
- android:layout_weight="0" >
- <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/menu"
- android:layout_width="@dimen/navigation_extra_key_width"
- android:layout_height="match_parent"
- android:layout_marginEnd="2dp"
- android:src="@drawable/ic_sysbar_menu"
- android:scaleType="centerInside"
- systemui:keyCode="82"
- android:visibility="invisible"
- android:contentDescription="@string/accessibility_menu" />
- <com.android.systemui.statusbar.policy.KeyButtonView
- android:id="@+id/ime_switcher"
- android:layout_width="@dimen/navigation_extra_key_width"
- android:layout_height="match_parent"
- android:layout_marginEnd="2dp"
- android:src="@drawable/ic_ime_switcher_default"
- android:visibility="invisible"
- android:contentDescription="@string/accessibility_ime_switch_button"
- android:scaleType="centerInside" />
- </FrameLayout>
+ <include layout="@layout/mid_navigation_bar_land"/>
+
</LinearLayout>
- <!-- lights out layout to match exactly -->
+ <!-- lights out layout to match exactly -->
<LinearLayout
android:layout_height="match_parent"
android:layout_width="match_parent"
android:orientation="horizontal"
- android:id="@+id/lights_out"
- android:visibility="gone"
+ android:gravity="center_horizontal"
+ android:layout_gravity="center_horizontal"
+ android:visibility="visible"
>
- <Space
- android:layout_width="match_parent"
+ <View
+ android:layout_width="0dp"
android:layout_height="match_parent"
- android:layout_weight="1"
- />
- <ImageView
- android:layout_width="162dp" android:paddingStart="42dp" android:paddingEnd="42dp"
+ android:layout_weight="1" />
+ <!-- lights out layout to match exactly -->
+ <LinearLayout
android:layout_height="match_parent"
+ android:layout_width="wrap_content"
+ android:layout_weight="1"
+ android:orientation="horizontal"
+ android:gravity="center_horizontal"
+ android:layout_gravity="center_horizontal"
android:layout_marginStart="40dp"
- android:src="@drawable/ic_sysbar_lights_out_dot_small"
- android:scaleType="center"
- android:layout_weight="0"
- android:contentDescription="@string/accessibility_back"
- />
- <ImageView
- android:layout_width="162dp" android:paddingStart="42dp" android:paddingEnd="42dp"
- android:layout_height="match_parent"
- android:src="@drawable/ic_sysbar_lights_out_dot_large"
- android:scaleType="center"
- android:layout_weight="0"
- android:contentDescription="@string/accessibility_home"
- />
- <ImageView
- android:layout_width="162dp" android:paddingStart="42dp" android:paddingEnd="42dp"
android:layout_marginEnd="40dp"
+ android:id="@+id/lights_out"
+ android:visibility="gone"
+ >
+ <ImageView
+ android:layout_width="162dp" android:paddingStart="42dp" android:paddingEnd="42dp"
+ android:layout_height="match_parent"
+ android:src="@drawable/ic_sysbar_lights_out_dot_large"
+ android:scaleType="center"
+ />
+ <ImageView
+ android:layout_width="162dp" android:paddingStart="42dp" android:paddingEnd="42dp"
+ android:layout_height="match_parent"
+ android:src="@drawable/ic_sysbar_lights_out_dot_large"
+ android:scaleType="center"
+ />
+ <ImageView
+ android:layout_width="162dp" android:paddingStart="42dp" android:paddingEnd="42dp"
+ android:layout_height="match_parent"
+ android:src="@drawable/ic_sysbar_lights_out_dot_large"
+ android:scaleType="center"
+ />
+ <ImageView
+ android:layout_width="162dp" android:paddingStart="42dp" android:paddingEnd="42dp"
+ android:layout_height="match_parent"
+ android:src="@drawable/ic_sysbar_lights_out_dot_large"
+ android:scaleType="center"
+ />
+ </LinearLayout>
+ <View
+ android:layout_width="0dp"
android:layout_height="match_parent"
- android:src="@drawable/ic_sysbar_lights_out_dot_small"
- android:scaleType="center"
- android:layout_weight="0"
- android:contentDescription="@string/accessibility_recent"
- />
- <Space
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_weight="1"
- />
+ android:layout_weight="1" />
</LinearLayout>
<com.android.systemui.statusbar.policy.DeadZone
diff --git a/packages/SystemUI/res/layout/cmland.xml b/packages/SystemUI/res/layout/cmland.xml
new file mode 100644
index 0000000..3c4e561
--- /dev/null
+++ b/packages/SystemUI/res/layout/cmland.xml
@@ -0,0 +1,104 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2015 The Android Open Source Project
+ Copyright (C) 2014-2015 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.
+-->
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ >
+ <com.android.systemui.egg.CMLand
+ android:id="@+id/world"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+ </com.android.systemui.egg.CMLand>
+ <FrameLayout
+ android:id="@+id/welcome"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:visibility="gone"
+ android:background="#a0000000"
+ android:clickable="true"
+ >
+ <FrameLayout
+ android:id="@+id/play_button"
+ android:layout_width="72dp"
+ android:layout_height="72dp"
+ android:layout_gravity="center"
+ android:clickable="true"
+ android:background="@drawable/ripplebg"
+ android:focusable="true"
+ android:onClick="startButtonPressed"
+ >
+ <ImageView
+ android:id="@+id/play_button_image"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:scaleType="fitCenter"
+ android:layout_gravity="center"
+ android:tint="#000000"
+ android:src="@drawable/play"
+ />
+ <TextView
+ android:id="@+id/play_button_text"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:alpha="0"
+ android:textSize="40dp"
+ android:textColor="#000000"
+ />
+ </FrameLayout>
+ </FrameLayout>
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="top|center_horizontal"
+ android:orientation="horizontal"
+ android:gravity="center_vertical"
+ android:id="@+id/player_setup"
+ >
+ <ImageButton
+ style="@android:style/Widget.Material.Button.Borderless"
+ android:id="@+id/player_minus_button"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:padding="10dp"
+ android:scaleType="centerInside"
+ android:onClick="playerMinus"
+ android:src="@drawable/minus"
+ />
+ <LinearLayout
+ android:id="@+id/scores"
+ android:layout_width="wrap_content"
+ android:layout_height="64dp"
+ android:padding="12dp"
+ android:orientation="horizontal"
+ android:clipToPadding="false"
+ >
+ </LinearLayout>
+ <ImageButton
+ style="@android:style/Widget.Material.Button.Borderless"
+ android:id="@+id/player_plus_button"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:padding="10dp"
+ android:scaleType="centerInside"
+ android:onClick="playerPlus"
+ android:src="@drawable/plus"
+ />
+ </LinearLayout>
+</FrameLayout>
diff --git a/packages/SystemUI/res/layout/keyguard_bottom_area.xml b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
index 444f0f0..6c85a8f 100644
--- a/packages/SystemUI/res/layout/keyguard_bottom_area.xml
+++ b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
@@ -47,7 +47,6 @@
android:layout_height="@dimen/keyguard_affordance_height"
android:layout_width="@dimen/keyguard_affordance_width"
android:layout_gravity="bottom|end"
- android:tint="#ffffffff"
android:src="@drawable/ic_camera_alt_24dp"
android:scaleType="center"
android:contentDescription="@string/accessibility_camera_button" />
@@ -57,7 +56,6 @@
android:layout_height="@dimen/keyguard_affordance_height"
android:layout_width="@dimen/keyguard_affordance_width"
android:layout_gravity="bottom|start"
- android:tint="#ffffffff"
android:src="@drawable/ic_phone_24dp"
android:scaleType="center"
android:contentDescription="@string/accessibility_phone_button" />
diff --git a/packages/SystemUI/res/layout/keyguard_status_bar.xml b/packages/SystemUI/res/layout/keyguard_status_bar.xml
index b5f917a..8d33742 100644
--- a/packages/SystemUI/res/layout/keyguard_status_bar.xml
+++ b/packages/SystemUI/res/layout/keyguard_status_bar.xml
@@ -52,7 +52,7 @@
>
<include layout="@layout/system_icons" />
</FrameLayout>
- <TextView android:id="@+id/battery_level"
+ <com.android.systemui.BatteryLevelTextView android:id="@+id/battery_level_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
diff --git a/packages/SystemUI/res/layout/lockscreen_shortcuts.xml b/packages/SystemUI/res/layout/lockscreen_shortcuts.xml
new file mode 100644
index 0000000..1c99d96
--- /dev/null
+++ b/packages/SystemUI/res/layout/lockscreen_shortcuts.xml
@@ -0,0 +1,65 @@
+<RelativeLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_height="match_parent"
+ android:layout_width="match_parent">
+
+ <ImageView
+ android:id="@+id/phone_button"
+ android:gravity="center_horizontal"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:layout_centerHorizontal="true"
+ android:src="@drawable/lockscreen_shortcuts_phone_background" />
+
+ <TextView
+ android:textSize="15sp"
+ android:textColor="#424242"
+ android:gravity="center"
+ android:layout_below="@id/phone_button"
+ android:layout_alignStart="@id/phone_button"
+ android:layout_alignEnd="@id/phone_button"
+ android:text="@string/lockscreen_message"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent" />
+
+ <RelativeLayout
+ android:layout_alignEnd="@id/phone_button"
+ android:layout_alignStart="@id/phone_button"
+ android:layout_alignBottom="@id/phone_button"
+ android:layout_marginStart="@dimen/phone_side_padding"
+ android:layout_marginEnd="@dimen/phone_side_padding"
+ android:paddingBottom="@dimen/phone_bottom_padding"
+ android:clipChildren="false"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/phone_height">
+ <ImageView
+ android:layout_marginStart="@dimen/lockscreen_icon_side_padding"
+ android:layout_alignParentBottom="true"
+ android:layout_alignParentStart="true"
+ android:clickable="true"
+ android:scaleType="center"
+ android:id="@+id/left_button"
+ android:layout_width="@dimen/keyguard_affordance_width"
+ android:layout_height="@dimen/keyguard_affordance_height" />
+ <ImageView
+ android:id="@+id/middle_button"
+ android:tint="#666666"
+ android:layout_centerHorizontal="true"
+ android:layout_alignParentBottom="true"
+ android:scaleType="center"
+ android:src="@drawable/ic_lock_24dp"
+ android:layout_width="@dimen/keyguard_affordance_width"
+ android:layout_height="@dimen/keyguard_affordance_height" />
+ <ImageView
+ android:layout_marginEnd="@dimen/lockscreen_icon_side_padding"
+ android:id="@+id/right_button"
+ android:clickable="true"
+ android:scaleType="center"
+ android:layout_alignParentBottom="true"
+ android:layout_alignParentEnd="true"
+ android:layout_width="@dimen/keyguard_affordance_width"
+ android:layout_height="@dimen/keyguard_affordance_height" />
+ </RelativeLayout>
+</RelativeLayout>
diff --git a/packages/SystemUI/res/layout/mid_navigation_bar_land.xml b/packages/SystemUI/res/layout/mid_navigation_bar_land.xml
new file mode 100644
index 0000000..6a1f7aa
--- /dev/null
+++ b/packages/SystemUI/res/layout/mid_navigation_bar_land.xml
@@ -0,0 +1,130 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2015 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.
+*/
+-->
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:systemui="http://schemas.android.com/apk/res-auto"
+ android:layout_height="match_parent"
+ android:layout_width="match_parent"
+ android:orientation="vertical"
+ android:clipChildren="false"
+ android:clipToPadding="false"
+ android:id="@+id/nav_buttons">
+ <FrameLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" >
+ <com.android.systemui.statusbar.policy.KeyButtonView
+ android:id="@+id/ime_switcher"
+ android:layout_width="match_parent"
+ android:layout_height="40dp"
+ android:contentDescription="@string/accessibility_ime_switch_button"
+ android:scaleType="centerInside"
+ android:src="@drawable/ic_ime_switcher_default"
+ android:visibility="invisible" />
+
+ <com.android.systemui.statusbar.policy.KeyButtonView
+ android:id="@+id/one"
+ android:scaleType="centerInside"
+ android:layout_height="40dp"
+ android:layout_width="match_parent"
+ android:layout_weight="0" />
+ <com.android.systemui.statusbar.policy.KeyButtonView
+ android:id="@+id/dpad_left"
+ android:visibility="gone"
+ android:layout_width="match_parent"
+ android:layout_height="40dp"
+ android:layout_weight="0"
+ android:scaleType="centerInside"
+ systemui:keyRepeat="true"/>
+ </FrameLayout>
+ <LinearLayout
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:layout_weight="1"
+ android:orientation="vertical"
+ android:clipChildren="false"
+ android:gravity="center_vertical"
+ android:id="@+id/mid_nav_buttons"
+ android:layout_gravity="center_vertical"
+ android:clipToPadding="false"
+ android:animateLayoutChanges="true">
+ <com.android.systemui.statusbar.policy.KeyButtonView
+ android:id="@+id/two"
+ android:scaleType="centerInside"
+ android:layout_height="80dp"
+ android:layout_width="match_parent"
+ android:layout_weight="0"
+ systemui:keyRepeat="true" />
+ <View
+ android:layout_height="0dp"
+ android:layout_width="match_parent"
+ android:layout_weight="1"
+ android:visibility="invisible" />
+ <com.android.systemui.statusbar.policy.KeyButtonView
+ android:id="@+id/three"
+ android:scaleType="centerInside"
+ android:layout_height="80dp"
+ android:layout_width="match_parent"
+ systemui:keyRepeat="true"
+ android:layout_weight="0" />
+ <View
+ android:layout_height="0dp"
+ android:layout_width="match_parent"
+ android:layout_weight="1"
+ android:visibility="invisible" />
+ <com.android.systemui.statusbar.policy.KeyButtonView
+ android:id="@+id/four"
+ android:scaleType="centerInside"
+ android:layout_height="80dp"
+ android:layout_width="match_parent"
+ android:layout_weight="0"
+ systemui:keyRepeat="true" />
+ <View
+ android:layout_height="0dp"
+ android:layout_width="match_parent"
+ android:layout_weight="1"
+ android:visibility="invisible" />
+ <com.android.systemui.statusbar.policy.KeyButtonView
+ android:id="@+id/five"
+ android:scaleType="centerInside"
+ android:layout_height="80dp"
+ android:layout_width="match_parent"
+ android:layout_weight="0"
+ systemui:keyRepeat="true" />
+ </LinearLayout>
+ <FrameLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" >
+ <com.android.systemui.statusbar.policy.KeyButtonView
+ android:id="@+id/dpad_right"
+ android:visibility="gone"
+ android:layout_width="match_parent"
+ android:layout_height="40dp"
+ android:layout_weight="0"
+ android:scaleType="centerInside"
+ systemui:keyRepeat="true" />
+ <com.android.systemui.statusbar.policy.KeyButtonView
+ android:id="@+id/six"
+ android:scaleType="centerInside"
+ android:layout_height="40dp"
+ android:layout_width="match_parent"
+ android:layout_weight="0"
+ systemui:keyRepeat="true" />
+ </FrameLayout>
+
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/mid_navigation_bar_port.xml b/packages/SystemUI/res/layout/mid_navigation_bar_port.xml
new file mode 100644
index 0000000..6dfdc16
--- /dev/null
+++ b/packages/SystemUI/res/layout/mid_navigation_bar_port.xml
@@ -0,0 +1,126 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2015 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.
+*/
+-->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:systemui="http://schemas.android.com/apk/res-auto"
+ android:layout_height="match_parent"
+ android:layout_width="match_parent"
+ android:orientation="horizontal"
+ android:clipChildren="false"
+ android:clipToPadding="false"
+ android:id="@+id/nav_buttons">
+ <FrameLayout
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent" >
+ <com.android.systemui.statusbar.policy.KeyButtonView
+ android:id="@+id/dpad_left"
+ android:visibility="gone"
+ android:layout_width="40dp"
+ android:layout_height="match_parent"
+ android:layout_weight="0"
+ android:scaleType="centerInside"
+ systemui:keyRepeat="true" />
+ <com.android.systemui.statusbar.policy.KeyButtonView
+ android:id="@+id/one"
+ android:layout_width="@dimen/navigation_extra_key_width"
+ android:layout_height="match_parent"
+ android:layout_weight="0"
+ android:scaleType="centerInside" />
+ </FrameLayout>
+ <LinearLayout
+ android:layout_height="match_parent"
+ android:layout_width="0dp"
+ android:layout_weight="1"
+ android:clipChildren="false"
+ android:clipToPadding="false"
+ android:id="@+id/mid_nav_buttons"
+ android:gravity="center_horizontal"
+ android:layout_gravity="center_horizontal"
+ android:animateLayoutChanges="true">
+ <com.android.systemui.statusbar.policy.KeyButtonView
+ android:id="@+id/two"
+ android:scaleType="centerInside"
+ android:layout_width="@dimen/navigation_key_width"
+ android:layout_height="match_parent"
+ systemui:keyRepeat="true"
+ android:layout_weight="0" />
+ <View
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_weight="1" />
+ <com.android.systemui.statusbar.policy.KeyButtonView
+ android:id="@+id/three"
+ android:scaleType="centerInside"
+ android:layout_width="@dimen/navigation_key_width"
+ android:layout_height="match_parent"
+ systemui:keyRepeat="true"
+ android:layout_weight="0" />
+ <View
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_weight="1" />
+ <com.android.systemui.statusbar.policy.KeyButtonView
+ android:id="@+id/four"
+ android:scaleType="centerInside"
+ android:layout_width="@dimen/navigation_key_width"
+ android:layout_height="match_parent"
+ android:layout_weight="0"
+ systemui:keyRepeat="true" />
+ <View
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_weight="1" />
+ <com.android.systemui.statusbar.policy.KeyButtonView
+ android:id="@+id/five"
+ android:scaleType="centerInside"
+ android:layout_width="@dimen/navigation_key_width"
+ android:layout_height="match_parent"
+ android:layout_weight="0"
+ systemui:keyRepeat="true" />
+ </LinearLayout>
+ <FrameLayout
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent" >
+ <com.android.systemui.statusbar.policy.KeyButtonView
+ android:background="#FFAA0000"
+ android:id="@+id/ime_switcher"
+ android:layout_width="@dimen/navigation_extra_key_width"
+ android:layout_weight="0"
+ android:layout_height="match_parent"
+ android:contentDescription="@string/accessibility_ime_switch_button"
+ android:scaleType="centerInside"
+ android:src="@drawable/ic_ime_switcher_default"
+ android:visibility="invisible" />
+ <com.android.systemui.statusbar.policy.KeyButtonView
+ android:id="@+id/six"
+ android:layout_width="@dimen/navigation_extra_key_width"
+ android:layout_height="match_parent"
+ android:layout_weight="0"
+ android:scaleType="centerInside" />
+ <com.android.systemui.statusbar.policy.KeyButtonView
+ android:id="@+id/dpad_right"
+ android:visibility="gone"
+ android:layout_width="40dp"
+ android:layout_height="match_parent"
+ android:layout_weight="0"
+ android:scaleType="centerInside"
+ systemui:keyRepeat="true"/>
+ </FrameLayout>
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/mobile_signal_group.xml b/packages/SystemUI/res/layout/mobile_signal_group.xml
index 6ae5cf3..3d25f9f 100644
--- a/packages/SystemUI/res/layout/mobile_signal_group.xml
+++ b/packages/SystemUI/res/layout/mobile_signal_group.xml
@@ -1,5 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
+/*
+ * Copyright (c) 2015 The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+*/
/* apps/common/assets/default/default/skins/StatusBar.xml
**
** Copyright 2011, The Android Open Source Project
@@ -17,31 +21,73 @@
** limitations under the License.
*/
-->
-<FrameLayout
+<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:systemui="http://schemas.android.com/apk/res-auto"
android:id="@+id/mobile_combo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
>
- <com.android.systemui.statusbar.AnimatedImageView
- android:theme="@style/DualToneLightTheme"
- android:id="@+id/mobile_signal"
- android:layout_height="wrap_content"
+ <ImageView
android:layout_width="wrap_content"
- systemui:hasOverlappingRendering="false"
- />
- <com.android.systemui.statusbar.AnimatedImageView
- android:theme="@style/DualToneDarkTheme"
- android:id="@+id/mobile_signal_dark"
android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- android:alpha="0.0"
- systemui:hasOverlappingRendering="false"
+ android:layout_marginStart="2dp"
+ android:id="@+id/data_inout"
+ android:visibility="gone"
/>
- <ImageView
- android:id="@+id/mobile_type"
- android:layout_height="wrap_content"
+ <FrameLayout
android:layout_width="wrap_content"
- />
-</FrameLayout>
+ android:layout_height="wrap_content"
+ >
+ <FrameLayout
+ android:id="@+id/mobile_signal_single"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ >
+ <com.android.systemui.statusbar.AnimatedImageView
+ android:theme="@style/DualToneLightTheme"
+ android:id="@+id/mobile_signal"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ systemui:hasOverlappingRendering="false"
+ />
+ <com.android.systemui.statusbar.AnimatedImageView
+ android:theme="@style/DualToneDarkTheme"
+ android:id="@+id/mobile_signal_dark"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:alpha="0.0"
+ systemui:hasOverlappingRendering="false"
+ />
+ <ImageView
+ android:id="@+id/mobile_type"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ />
+ <ImageView
+ android:id="@+id/mobile_inout"
+ android:layout_height="17dp"
+ android:layout_width="17dp"
+ android:layout_gravity="end|bottom"
+ />
+ </FrameLayout>
+ <LinearLayout
+ android:id="@+id/mobile_signal_stacked"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:visibility="gone"
+ >
+ <ImageView
+ android:id="@+id/mobile_signal_data"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ />
+ <ImageView
+ android:id="@+id/mobile_signal_voice"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ />
+ </LinearLayout>
+ </FrameLayout>
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/navigation_bar.xml b/packages/SystemUI/res/layout/navigation_bar.xml
index d58664f..6a28ef6 100644
--- a/packages/SystemUI/res/layout/navigation_bar.xml
+++ b/packages/SystemUI/res/layout/navigation_bar.xml
@@ -4,7 +4,7 @@
**
** Copyright 2011, The Android Open Source Project
**
-** Licensed under the Apache License, Version 2.0 (the "License");
+** 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
**
@@ -37,81 +37,10 @@
android:orientation="horizontal"
android:clipChildren="false"
android:clipToPadding="false"
- android:id="@+id/nav_buttons"
- android:animateLayoutChanges="true"
+ android:id="@+id/container"
>
- <!-- navigation controls -->
- <View
- android:layout_width="@dimen/navigation_side_padding"
- android:layout_height="match_parent"
- android:layout_weight="0"
- android:visibility="invisible"
- />
- <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/back"
- android:layout_width="@dimen/navigation_key_width"
- android:layout_height="match_parent"
- android:src="@drawable/ic_sysbar_back"
- systemui:keyCode="4"
- android:layout_weight="0"
- android:scaleType="center"
- android:contentDescription="@string/accessibility_back"
- />
- <View
- android:layout_width="0dp"
- android:layout_height="match_parent"
- android:layout_weight="1"
- android:visibility="invisible"
- />
- <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/home"
- android:layout_width="@dimen/navigation_key_width"
- android:layout_height="match_parent"
- android:src="@drawable/ic_sysbar_home"
- systemui:keyCode="3"
- systemui:keyRepeat="false"
- android:layout_weight="0"
- android:scaleType="center"
- android:contentDescription="@string/accessibility_home"
- />
- <View
- android:layout_width="0dp"
- android:layout_height="match_parent"
- android:layout_weight="1"
- android:visibility="invisible"
- />
- <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/recent_apps"
- android:layout_width="@dimen/navigation_key_width"
- android:layout_height="match_parent"
- android:src="@drawable/ic_sysbar_recent"
- android:layout_weight="0"
- android:scaleType="center"
- android:contentDescription="@string/accessibility_recent"
- />
- <FrameLayout
- android:layout_width="@dimen/navigation_side_padding"
- android:layout_height="match_parent"
- android:layout_weight="0" >
- <com.android.systemui.statusbar.policy.KeyButtonView
- android:id="@+id/menu"
- android:layout_width="@dimen/navigation_extra_key_width"
- android:layout_height="match_parent"
- android:contentDescription="@string/accessibility_menu"
- android:src="@drawable/ic_sysbar_menu"
- android:visibility="invisible"
- android:scaleType="centerInside"
- android:layout_gravity="end"
- systemui:keyCode="82" />
-
- <com.android.systemui.statusbar.policy.KeyButtonView
- android:id="@+id/ime_switcher"
- android:layout_width="@dimen/navigation_extra_key_width"
- android:layout_height="match_parent"
- android:contentDescription="@string/accessibility_ime_switch_button"
- android:scaleType="centerInside"
- android:src="@drawable/ic_ime_switcher_default"
- android:visibility="invisible"
- android:layout_gravity="end" />
- </FrameLayout>
+ <include layout="@layout/mid_navigation_bar_port"/>
</LinearLayout>
@@ -120,6 +49,10 @@
android:layout_height="match_parent"
android:layout_width="match_parent"
android:orientation="horizontal"
+ android:gravity="center_horizontal"
+ android:layout_marginStart="40dp"
+ android:layout_marginEnd="40dp"
+ android:layout_gravity="center_horizontal"
android:id="@+id/lights_out"
android:visibility="gone"
>
@@ -127,13 +60,11 @@
android:layout_width="@dimen/navigation_key_width"
android:layout_height="match_parent"
android:layout_marginStart="@dimen/navigation_side_padding"
- android:src="@drawable/ic_sysbar_lights_out_dot_small"
+ android:src="@drawable/ic_sysbar_lights_out_dot_large"
android:scaleType="center"
- android:layout_weight="0"
- android:contentDescription="@string/accessibility_back"
/>
<View
- android:layout_width="match_parent"
+ android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:visibility="invisible"
@@ -143,11 +74,9 @@
android:layout_height="match_parent"
android:src="@drawable/ic_sysbar_lights_out_dot_large"
android:scaleType="center"
- android:layout_weight="0"
- android:contentDescription="@string/accessibility_home"
/>
<View
- android:layout_width="match_parent"
+ android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:visibility="invisible"
@@ -156,10 +85,20 @@
android:layout_width="@dimen/navigation_key_width"
android:layout_marginEnd="@dimen/navigation_side_padding"
android:layout_height="match_parent"
- android:src="@drawable/ic_sysbar_lights_out_dot_small"
+ android:src="@drawable/ic_sysbar_lights_out_dot_large"
+ android:scaleType="center"
+ />
+ <View
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:visibility="invisible"
+ android:layout_weight="1"
+ />
+ <ImageView
+ android:layout_width="80dp"
+ android:layout_height="match_parent"
+ android:src="@drawable/ic_sysbar_lights_out_dot_large"
android:scaleType="center"
- android:layout_weight="0"
- android:contentDescription="@string/accessibility_recent"
/>
</LinearLayout>
@@ -183,95 +122,30 @@
android:paddingTop="0dp"
>
- <LinearLayout
+ <LinearLayout
android:layout_height="match_parent"
android:layout_width="match_parent"
android:orientation="vertical"
+ android:gravity="center_vertical"
+ android:layout_gravity="center_vertical"
android:clipChildren="false"
android:clipToPadding="false"
- android:id="@+id/nav_buttons"
- android:animateLayoutChanges="true"
+ android:id="@+id/container"
>
- <!-- navigation controls -->
- <FrameLayout
- android:layout_weight="0"
- android:layout_width="match_parent"
- android:layout_height="@dimen/navigation_side_padding" >
- <com.android.systemui.statusbar.policy.KeyButtonView
- android:id="@+id/ime_switcher"
- android:layout_width="match_parent"
- android:layout_height="@dimen/navigation_extra_key_width"
- android:contentDescription="@string/accessibility_ime_switch_button"
- android:scaleType="centerInside"
- android:src="@drawable/ic_ime_switcher_default"
- android:layout_gravity="top"
- android:visibility="invisible" />
-
- <com.android.systemui.statusbar.policy.KeyButtonView
- android:id="@+id/menu"
- android:layout_width="match_parent"
- android:layout_height="40dp"
- android:contentDescription="@string/accessibility_menu"
- android:src="@drawable/ic_sysbar_menu"
- android:scaleType="centerInside"
- android:layout_gravity="top"
- android:visibility="invisible"
- systemui:keyCode="82" />
- </FrameLayout>
+ <include layout="@layout/mid_navigation_bar_land"/>
- <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/recent_apps"
- android:layout_height="@dimen/navigation_key_width"
- android:layout_width="match_parent"
- android:src="@drawable/ic_sysbar_recent"
- android:scaleType="center"
- android:layout_weight="0"
- android:contentDescription="@string/accessibility_recent"
- />
- <View
- android:layout_height="match_parent"
- android:layout_width="match_parent"
- android:layout_weight="1"
- android:visibility="invisible"
- />
- <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/home"
- android:layout_height="@dimen/navigation_key_width"
- android:layout_width="match_parent"
- android:src="@drawable/ic_sysbar_home"
- android:scaleType="center"
- systemui:keyCode="3"
- systemui:keyRepeat="false"
- android:layout_weight="0"
- android:contentDescription="@string/accessibility_home"
- />
- <View
- android:layout_height="match_parent"
- android:layout_width="match_parent"
- android:layout_weight="1"
- android:visibility="invisible"
- />
- <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/back"
- android:layout_height="@dimen/navigation_key_width"
- android:layout_width="match_parent"
- android:src="@drawable/ic_sysbar_back"
- android:scaleType="center"
- systemui:keyCode="4"
- android:layout_weight="0"
- android:contentDescription="@string/accessibility_back"
- />
- <View
- android:layout_height="@dimen/navigation_side_padding"
- android:layout_width="match_parent"
- android:layout_weight="0"
- android:visibility="invisible"
- />
</LinearLayout>
<!-- lights out layout to match exactly -->
- <LinearLayout
+ <LinearLayout
android:layout_height="match_parent"
android:layout_width="match_parent"
android:orientation="vertical"
+ android:gravity="center_vertical"
+ android:layout_gravity="center_vertical"
+ android:layout_marginTop="40dp"
+ android:layout_marginBottom="40dp"
android:id="@+id/lights_out"
android:visibility="gone"
>
@@ -279,13 +153,11 @@
android:layout_height="@dimen/navigation_key_width"
android:layout_marginTop="@dimen/navigation_side_padding"
android:layout_width="match_parent"
- android:src="@drawable/ic_sysbar_lights_out_dot_small"
+ android:src="@drawable/ic_sysbar_lights_out_dot_large"
android:scaleType="center"
- android:layout_weight="0"
- android:contentDescription="@string/accessibility_recent"
/>
<View
- android:layout_height="match_parent"
+ android:layout_height="0dp"
android:layout_width="match_parent"
android:layout_weight="1"
android:visibility="invisible"
@@ -295,11 +167,9 @@
android:layout_width="match_parent"
android:src="@drawable/ic_sysbar_lights_out_dot_large"
android:scaleType="center"
- android:layout_weight="0"
- android:contentDescription="@string/accessibility_home"
/>
<View
- android:layout_height="match_parent"
+ android:layout_height="0dp"
android:layout_width="match_parent"
android:layout_weight="1"
android:visibility="invisible"
@@ -308,10 +178,20 @@
android:layout_height="@dimen/navigation_key_width"
android:layout_marginBottom="@dimen/navigation_side_padding"
android:layout_width="match_parent"
- android:src="@drawable/ic_sysbar_lights_out_dot_small"
+ android:src="@drawable/ic_sysbar_lights_out_dot_large"
+ android:scaleType="center"
+ />
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:visibility="invisible"
+ android:layout_weight="1"
+ />
+ <ImageView
+ android:layout_height="80dp"
+ android:layout_width="match_parent"
+ android:src="@drawable/ic_sysbar_lights_out_dot_large"
android:scaleType="center"
- android:layout_weight="0"
- android:contentDescription="@string/accessibility_back"
/>
</LinearLayout>
diff --git a/packages/SystemUI/res/layout/navigation_bar_edit_menu_item.xml b/packages/SystemUI/res/layout/navigation_bar_edit_menu_item.xml
new file mode 100644
index 0000000..d951f5b
--- /dev/null
+++ b/packages/SystemUI/res/layout/navigation_bar_edit_menu_item.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2015 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.
+*/
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal">
+
+ <ImageView
+ android:id="@+id/key_icon"
+ android:layout_width="80dip"
+ android:layout_height="match_parent"
+ android:padding="4dip"
+ android:scaleType="centerInside"/>
+
+ <TextView
+ android:id="@+id/key_text"
+ android:layout_width="0dip"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:minHeight="?android:attr/listPreferredItemHeightSmall"
+ android:textAppearance="?android:attr/textAppearanceListItemSmall"
+ android:textColor="?android:attr/textColorAlertDialogListItem"
+ android:gravity="center_vertical"
+ android:paddingEnd="16dip"
+ android:ellipsize="marquee"/>
+
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/notification_guts.xml b/packages/SystemUI/res/layout/notification_guts.xml
index d52c274..effa302 100644
--- a/packages/SystemUI/res/layout/notification_guts.xml
+++ b/packages/SystemUI/res/layout/notification_guts.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- Copyright 2014, The Android Open Source Project
+ Copyright (C) 2015 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.
@@ -82,11 +82,21 @@
android:layout_height="match_parent"
android:layout_weight="0"
android:gravity="center"
- android:src="@drawable/ic_settings"
+ android:src="@drawable/notification_guts_ic_settings"
android:visibility="gone"
/>
<ImageButton style="@android:style/Widget.Material.Light.Button.Borderless.Small"
+ android:id="@+id/notification_inspect_filter_notification"
+ android:layout_width="52dp"
+ android:layout_height="match_parent"
+ android:layout_weight="0"
+ android:gravity="center"
+ android:src="@drawable/notification_guts_ic_ringer_mute"
+ android:visibility="gone"
+ />
+
+ <ImageButton style="@android:style/Widget.Material.Light.Button.Borderless.Small"
android:id="@+id/notification_inspect_item"
android:layout_width="52dp"
android:layout_height="match_parent"
diff --git a/packages/SystemUI/res/layout/qs_custom_detail.xml b/packages/SystemUI/res/layout/qs_custom_detail.xml
new file mode 100644
index 0000000..6aa1fc0
--- /dev/null
+++ b/packages/SystemUI/res/layout/qs_custom_detail.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2015 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.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ android:paddingTop="@dimen/detail_exterior_padding"
+ android:paddingStart="@dimen/detail_exterior_padding"
+ android:paddingEnd="@dimen/detail_exterior_padding">
+
+ <LinearLayout android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:orientation="horizontal">
+
+ <ImageView android:id="@+id/custom_qs_tile_icon"
+ android:layout_width="36dp"
+ android:layout_height="36dp"
+ android:layout_marginEnd="12dp" />
+
+ <LinearLayout android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:orientation="vertical">
+
+ <TextView android:id="@+id/custom_qs_tile_title"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:textAppearance="@style/TextAppearance.QS.DetailItemPrimary"/>
+
+ <TextView android:id="@+id/custom_qs_tile_package "
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:layout_marginTop="2dp"
+ android:textAppearance="@style/TextAppearance.QS.DetailItemSub"/>
+
+ <TextView android:id="@+id/custom_qs_tile_content_description"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:layout_marginTop="2dp"
+ android:textAppearance="@style/TextAppearance.QS.DetailItemSub" />
+
+ </LinearLayout>
+
+ </LinearLayout>
+
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/qs_custom_detail_remote.xml b/packages/SystemUI/res/layout/qs_custom_detail_remote.xml
new file mode 100644
index 0000000..bdbe6bb
--- /dev/null
+++ b/packages/SystemUI/res/layout/qs_custom_detail_remote.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2015 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.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ android:paddingTop="@dimen/detail_exterior_padding"
+ android:paddingStart="@dimen/detail_exterior_padding"
+ android:paddingEnd="@dimen/detail_exterior_padding">
+
+</LinearLayout> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout/qs_detail.xml b/packages/SystemUI/res/layout/qs_detail.xml
index ddff0f0..38daf0f 100644
--- a/packages/SystemUI/res/layout/qs_detail.xml
+++ b/packages/SystemUI/res/layout/qs_detail.xml
@@ -18,7 +18,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/qs_detail_background"
- android:paddingBottom="8dp"
+ android:paddingBottom="@dimen/detail_exterior_padding"
android:orientation="vertical">
<FrameLayout
@@ -44,6 +44,16 @@
android:focusable="true" />
<TextView
+ android:id="@android:id/button3"
+ style="@style/QSBorderlessButton"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginEnd="8dp"
+ android:minWidth="88dp"
+ android:textAppearance="@style/TextAppearance.QS.DetailButton"
+ android:focusable="true" />
+
+ <TextView
android:id="@android:id/button1"
style="@style/QSBorderlessButton"
android:layout_width="wrap_content"
diff --git a/packages/SystemUI/res/layout/qs_detail_header.xml b/packages/SystemUI/res/layout/qs_detail_header.xml
index 5a96dc3..6f07543 100644
--- a/packages/SystemUI/res/layout/qs_detail_header.xml
+++ b/packages/SystemUI/res/layout/qs_detail_header.xml
@@ -37,4 +37,15 @@
android:clickable="false"
android:textAppearance="@style/TextAppearance.QS.DetailHeader" />
-</com.android.keyguard.AlphaOptimizedLinearLayout> \ No newline at end of file
+ <TextView
+ android:id="@+id/done"
+ android:text="@string/quick_settings_done"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:gravity="center"
+ android:minWidth="88dp"
+ android:paddingRight="12dp"
+ android:textAppearance="@style/TextAppearance.QS.DetailButton"
+ android:clickable="false"
+ android:focusable="false" />
+</com.android.keyguard.AlphaOptimizedLinearLayout>
diff --git a/packages/SystemUI/res/layout/qs_detail_items.xml b/packages/SystemUI/res/layout/qs_detail_items.xml
index c22e42c..4ad82cb 100644
--- a/packages/SystemUI/res/layout/qs_detail_items.xml
+++ b/packages/SystemUI/res/layout/qs_detail_items.xml
@@ -18,9 +18,9 @@
<com.android.systemui.qs.QSDetailItems xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:paddingTop="16dp"
- android:paddingStart="16dp"
- android:paddingEnd="16dp">
+ android:paddingTop="@dimen/detail_exterior_padding"
+ android:paddingStart="@dimen/detail_exterior_padding"
+ android:paddingEnd="@dimen/detail_exterior_padding">
<LinearLayout
android:id="@android:id/list"
diff --git a/packages/SystemUI/res/layout/qs_detail_items_grid.xml b/packages/SystemUI/res/layout/qs_detail_items_grid.xml
new file mode 100644
index 0000000..617acfb
--- /dev/null
+++ b/packages/SystemUI/res/layout/qs_detail_items_grid.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ ~ Copyright (C) 2015 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
+ -->
+
+<!-- GridView -->
+<com.android.systemui.qs.QSDetailItemsGrid
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:sysui="http://schemas.android.com/apk/res-auto"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:numColumns="3"
+ sysui:verticalSpacing="4dp"
+ sysui:horizontalSpacing="4dp" /> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout/qs_detail_items_list.xml b/packages/SystemUI/res/layout/qs_detail_items_list.xml
new file mode 100644
index 0000000..535f28d
--- /dev/null
+++ b/packages/SystemUI/res/layout/qs_detail_items_list.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2015 The CyanogenMod 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.
+-->
+<!-- extends LinearLayout -->
+<com.android.systemui.qs.QSDetailItemsList xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:minHeight="200dp"
+ android:paddingTop="16dp"
+ android:paddingStart="16dp"
+ android:paddingEnd="16dp">
+
+ <ListView
+ android:id="@android:id/list"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical" />
+
+ <LinearLayout
+ android:id="@android:id/empty"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:gravity="center_horizontal"
+ android:orientation="vertical" >
+
+ <ImageView
+ android:id="@android:id/icon"
+ android:layout_width="56dp"
+ android:layout_height="56dp" />
+
+ <TextView
+ android:id="@android:id/title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="20dp"
+ android:textAppearance="@style/TextAppearance.QS.DetailEmpty" />
+ </LinearLayout>
+
+</com.android.systemui.qs.QSDetailItemsList>
diff --git a/packages/SystemUI/res/layout/qs_panel.xml b/packages/SystemUI/res/layout/qs_panel.xml
index 1873168..9df4425 100644
--- a/packages/SystemUI/res/layout/qs_panel.xml
+++ b/packages/SystemUI/res/layout/qs_panel.xml
@@ -19,11 +19,10 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/qs_background_primary"
- android:paddingTop="8dp"
- android:paddingBottom="8dp"
+ android:paddingBottom="12dp"
android:elevation="2dp">
- <com.android.systemui.qs.QSPanel
+ <com.android.systemui.qs.QSDragPanel
android:id="@+id/quick_settings_panel"
android:background="#0000"
android:layout_width="match_parent"
diff --git a/packages/SystemUI/res/layout/qs_settings.xml b/packages/SystemUI/res/layout/qs_settings.xml
new file mode 100644
index 0000000..af2cc0c
--- /dev/null
+++ b/packages/SystemUI/res/layout/qs_settings.xml
@@ -0,0 +1,75 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 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.
+-->
+<com.android.systemui.qs.QSSettings
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:systemui="http://schemas.android.com/apk/res-auto"
+ android:id="@+id/quick_settings_settings_recursion_container"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingTop="16dp"
+ android:orientation="vertical">
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="48dp"
+ android:paddingLeft="16dp"
+ android:paddingRight="16dp"
+ android:gravity="center_vertical"
+ android:textColor="#80cbc4"
+ android:text="@string/quick_settings_title_header"/>
+
+ <!-- show weather -->
+ <com.android.systemui.qs.QSBooleanSettingRow
+ style="@style/SettingRow"
+ android:key="status_bar_show_weather"
+ android:title="@string/quick_settings_title_show_weather"
+ systemui:table="cm_system"
+ />
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="48dp"
+ android:paddingLeft="16dp"
+ android:paddingRight="16dp"
+ android:gravity="center_vertical"
+ android:textColor="#80cbc4"
+ android:text="@string/quick_settings_title_tiles"/>
+
+ <!-- first row large -->
+ <com.android.systemui.qs.QSBooleanSettingRow
+ style="@style/SettingRow"
+ android:title="@string/quick_settings_title_enlarge_first_row"
+ android:key="sysui_qs_main_tiles"
+ systemui:table="cm_secure" />
+
+ <LinearLayout
+ android:id="@+id/reset_tiles"
+ style="@style/SettingRow">
+ <TextView
+ android:layout_width="0dp"
+ android:layout_height="24dp"
+ android:gravity="center_vertical"
+ android:layout_gravity="center_vertical"
+ android:layout_weight="1"
+ android:id="@+id/title"
+ android:textColor="@android:color/white"
+ android:text="@string/quick_settings_tile_reset_to_default"
+ android:contentDescription="@null"/>
+
+ </LinearLayout>
+
+</com.android.systemui.qs.QSSettings>
+
diff --git a/packages/SystemUI/res/layout/qs_settings_row.xml b/packages/SystemUI/res/layout/qs_settings_row.xml
new file mode 100644
index 0000000..98ac6fc
--- /dev/null
+++ b/packages/SystemUI/res/layout/qs_settings_row.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 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.
+-->
+<merge xmlns:android="http://schemas.android.com/apk/res/android">
+ <TextView
+ android:layout_width="0dp"
+ android:layout_height="24dp"
+ android:gravity="center_vertical"
+ android:layout_gravity="center_vertical"
+ android:layout_weight="1"
+ android:id="@+id/title"
+ android:textColor="@android:color/white"
+ android:contentDescription="@null"/>
+
+ <Switch
+ android:id="@+id/switcher"
+ android:layout_width="wrap_content"
+ android:layout_height="24dp"
+ android:gravity="center_vertical"
+ android:layout_gravity="center_vertical"
+ />
+</merge>
diff --git a/packages/SystemUI/res/layout/qs_tile_top.xml b/packages/SystemUI/res/layout/qs_tile_top.xml
new file mode 100644
index 0000000..4847c77
--- /dev/null
+++ b/packages/SystemUI/res/layout/qs_tile_top.xml
@@ -0,0 +1,88 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 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.
+-->
+<com.android.systemui.qs.QSPanelTopView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/qs_panel_top"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <!-- brightness -->
+ <include android:id="@+id/brightness_container"
+ android:paddingTop="@dimen/qs_brightness_padding_top"
+ layout="@layout/quick_settings_brightness_dialog"/>
+
+ <!-- delete target -->
+ <LinearLayout
+ android:id="@+id/delete_container"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:paddingTop="@dimen/qs_brightness_padding_top"
+ android:paddingLeft="16dp"
+ android:paddingRight="16dp"
+ android:orientation="horizontal">
+
+ <ImageView
+ android:id="@+id/delete_target"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:gravity="center"
+ android:layout_gravity="center"
+ android:src="@drawable/ic_delete"
+ />
+ </LinearLayout>
+
+ <!-- edit instructions & add target -->
+ <LinearLayout
+ android:id="@+id/edit_container"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:paddingTop="@dimen/qs_brightness_padding_top"
+ android:paddingLeft="16dp"
+ android:paddingRight="16dp"
+ android:orientation="horizontal">
+
+ <TextView
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:gravity="center_vertical"
+ android:layout_weight="1"
+ android:textColor="@android:color/white"
+ android:text="@string/qs_tile_edit_header_instruction"
+ android:contentDescription="@null"/>
+
+ <ImageView
+ android:id="@+id/add_target"
+ android:layout_width="20dp"
+ android:layout_height="match_parent"
+ android:gravity="center_vertical"
+ android:src="@drawable/ic_add_circle_qs"
+ />
+ </LinearLayout>
+
+ <TextView
+ android:id="@+id/qs_toast"
+ android:layout_height="match_parent"
+ android:paddingTop="@dimen/qs_brightness_padding_top"
+ android:paddingLeft="16dp"
+ android:paddingRight="16dp"
+ android:gravity="center_vertical"
+ android:layout_gravity="center_vertical"
+ android:layout_width="match_parent"
+ android:textColor="@color/quick_settings_toast_color"/>
+
+
+</com.android.systemui.qs.QSPanelTopView>
+
diff --git a/packages/SystemUI/res/layout/qs_user_detail_item.xml b/packages/SystemUI/res/layout/qs_user_detail_item.xml
index af22f03..666f878 100644
--- a/packages/SystemUI/res/layout/qs_user_detail_item.xml
+++ b/packages/SystemUI/res/layout/qs_user_detail_item.xml
@@ -24,7 +24,7 @@
android:layout_height="wrap_content"
android:orientation="vertical"
android:gravity="top|center_horizontal"
- android:paddingTop="16dp"
+ android:paddingTop="@dimen/detail_exterior_padding"
android:minHeight="112dp"
android:clipChildren="false"
android:clipToPadding="false"
diff --git a/packages/SystemUI/res/layout/quick_settings_notification_brightness_dialog.xml b/packages/SystemUI/res/layout/quick_settings_notification_brightness_dialog.xml
new file mode 100644
index 0000000..1f51fe3
--- /dev/null
+++ b/packages/SystemUI/res/layout/quick_settings_notification_brightness_dialog.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012-2015 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.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:systemui="http://schemas.android.com/apk/res-auto"
+ android:paddingLeft="16dp"
+ android:paddingRight="16dp"
+ style="@style/BrightnessDialogContainer">
+
+ <com.android.systemui.settings.ToggleSlider
+ android:id="@+id/notification_brightness_slider"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:layout_weight="1"
+ android:contentDescription="@string/accessibility_notification_brightness"
+ android:importantForAccessibility="no" />
+
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/screen_pinning_request.xml b/packages/SystemUI/res/layout/screen_pinning_request.xml
index fea45cc..af203ce 100644
--- a/packages/SystemUI/res/layout/screen_pinning_request.xml
+++ b/packages/SystemUI/res/layout/screen_pinning_request.xml
@@ -28,12 +28,6 @@
android:layout_height="wrap_content"
layout="@layout/screen_pinning_request_text_area" />
- <View
- android:id="@+id/spacer"
- android:layout_width="@dimen/screen_pinning_request_width"
- android:layout_height="18dp"
- android:background="@color/screen_pinning_request_bg" />
-
<include
android:layout_width="@dimen/screen_pinning_request_width"
android:layout_height="wrap_content"
diff --git a/packages/SystemUI/res/layout/screen_pinning_request_text_area.xml b/packages/SystemUI/res/layout/screen_pinning_request_text_area.xml
index df957f4..9900b84 100644
--- a/packages/SystemUI/res/layout/screen_pinning_request_text_area.xml
+++ b/packages/SystemUI/res/layout/screen_pinning_request_text_area.xml
@@ -29,7 +29,7 @@
android:layout_height="wrap_content"
android:paddingEnd="48dp"
android:paddingStart="48dp"
- android:paddingTop="43dp"
+ android:paddingTop="18dp"
android:text="@string/screen_pinning_title"
android:textColor="@color/screen_pinning_primary_text"
android:textSize="24sp" />
@@ -50,7 +50,7 @@
android:id="@+id/screen_pinning_ok_button"
style="@android:style/Widget.Material.Button"
android:layout_width="wrap_content"
- android:layout_height="36dp"
+ android:layout_height="54dp"
android:layout_alignParentEnd="true"
android:layout_below="@+id/screen_pinning_description"
android:layout_marginEnd="40dp"
@@ -66,7 +66,7 @@
android:id="@+id/screen_pinning_cancel_button"
style="@android:style/Widget.Material.Button"
android:layout_width="wrap_content"
- android:layout_height="36dp"
+ android:layout_height="54dp"
android:layout_alignTop="@id/screen_pinning_ok_button"
android:layout_marginEnd="4dp"
android:layout_toStartOf="@id/screen_pinning_ok_button"
diff --git a/packages/SystemUI/res/layout/signal_cluster_view.xml b/packages/SystemUI/res/layout/signal_cluster_view.xml
index f8bd6fd..308c502 100644
--- a/packages/SystemUI/res/layout/signal_cluster_view.xml
+++ b/packages/SystemUI/res/layout/signal_cluster_view.xml
@@ -25,7 +25,6 @@
android:layout_width="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal"
- android:paddingEnd="@dimen/signal_cluster_battery_padding"
>
<ImageView
android:id="@+id/vpn"
@@ -75,6 +74,14 @@
android:alpha="0.0"
systemui:hasOverlappingRendering="false"
/>
+ <com.android.systemui.statusbar.AlphaOptimizedImageView
+ android:theme="@style/DualToneLightTheme"
+ android:id="@+id/wifi_inout"
+ android:layout_height="17dp"
+ android:layout_width="18.41dp"
+ android:layout_gravity="center|bottom"
+ systemui:hasOverlappingRendering="false"
+ />
</FrameLayout>
<View
android:id="@+id/wifi_signal_spacer"
diff --git a/packages/SystemUI/res/layout/status_bar.xml b/packages/SystemUI/res/layout/status_bar.xml
index a5b3a83..291dc65 100644
--- a/packages/SystemUI/res/layout/status_bar.xml
+++ b/packages/SystemUI/res/layout/status_bar.xml
@@ -62,6 +62,16 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
>
+ <com.android.systemui.statusbar.policy.Clock
+ android:id="@+id/left_clock"
+ android:textAppearance="@style/TextAppearance.StatusBar.Clock"
+ android:layout_width="wrap_content"
+ android:layout_height="fill_parent"
+ android:singleLine="true"
+ android:paddingEnd="6dip"
+ android:gravity="center"
+ android:visibility="gone"
+ />
<com.android.systemui.statusbar.StatusBarIconView android:id="@+id/moreIcon"
android:layout_width="@dimen/status_bar_icon_size"
android:layout_height="match_parent"
@@ -85,6 +95,14 @@
<include layout="@layout/system_icons" />
+ <com.android.systemui.BatteryLevelTextView android:id="@+id/battery_level_text"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:layout_marginStart="@dimen/header_battery_margin_keyguard"
+ android:textColor="#ffffff"
+ android:textSize="@dimen/battery_level_text_size" />
+
<com.android.systemui.statusbar.policy.Clock
android:id="@+id/clock"
android:textAppearance="@style/TextAppearance.StatusBar.Clock"
@@ -97,4 +115,22 @@
</com.android.keyguard.AlphaOptimizedLinearLayout>
</LinearLayout>
+ <com.android.keyguard.AlphaOptimizedLinearLayout
+ android:id="@+id/center_clock_layout"
+ android:gravity="center"
+ android:orientation="horizontal"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ >
+
+ <com.android.systemui.statusbar.policy.Clock
+ android:id="@+id/center_clock"
+ android:textAppearance="@style/TextAppearance.StatusBar.Clock"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:singleLine="true"
+ android:gravity="center"
+ android:visibility="gone"
+ />
+ </com.android.keyguard.AlphaOptimizedLinearLayout>
</com.android.systemui.statusbar.phone.PhoneStatusBarView>
diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml
index f7bbce0..c4e3fcd 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded.xml
@@ -20,6 +20,7 @@
<com.android.systemui.statusbar.phone.NotificationPanelView
xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/res-auto"
xmlns:systemui="http://schemas.android.com/apk/res/com.android.systemui"
android:id="@+id/notification_panel"
android:layout_width="match_parent"
@@ -27,6 +28,19 @@
android:background="@android:color/transparent"
>
+ <com.android.keyguard.CarrierText
+ android:id="@+id/carrier_label"
+ android:layout_height="@dimen/carrier_label_height"
+ android:layout_width="match_parent"
+ android:layout_marginBottom="@dimen/close_handle_height"
+ android:layout_gravity="bottom"
+ android:gravity="center"
+ android:ellipsize="marquee"
+ android:singleLine="true"
+ android:visibility="invisible"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textColor="#999999" />
+
<include
layout="@layout/keyguard_status_view"
android:layout_height="wrap_content"
@@ -57,8 +71,8 @@
android:layout_marginTop="@dimen/status_bar_header_height_expanded"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginLeft="@dimen/notification_side_padding"
- android:layout_marginRight="@dimen/notification_side_padding"/>
+ android:layout_marginStart="@dimen/qs_panel_side_padding"
+ android:layout_marginEnd="@dimen/qs_panel_side_padding"/>
<!-- A view to reserve space for the collapsed stack -->
<!-- Layout height: notification_min_height + bottom_stack_peek_amount -->
diff --git a/packages/SystemUI/res/layout/status_bar_expanded_header.xml b/packages/SystemUI/res/layout/status_bar_expanded_header.xml
index 5eca471..577ad55 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded_header.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded_header.xml
@@ -23,10 +23,10 @@
android:layout_width="@dimen/notification_panel_width"
android:layout_height="@dimen/status_bar_header_height"
android:layout_gravity="@integer/notification_panel_layout_gravity"
- android:paddingStart="@dimen/notification_side_padding"
- android:paddingEnd="@dimen/notification_side_padding"
+ android:paddingStart="@dimen/notification_header_side_padding"
+ android:paddingEnd="@dimen/notification_header_side_padding"
android:baselineAligned="false"
- android:elevation="4dp"
+ android:elevation="@dimen/status_bar_expanded_header_elevation"
android:background="@drawable/notification_header_bg"
android:clickable="true"
android:focusable="true"
@@ -63,7 +63,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingStart="36dp"
- android:tint="#4DFFFFFF"
+ android:tint="@color/tuner_icon_tint"
android:tintMode="src_in"
android:visibility="invisible"
android:src="@drawable/tuner" />
@@ -85,13 +85,13 @@
>
<include layout="@layout/system_icons" />
</FrameLayout>
- <TextView android:id="@+id/battery_level"
+ <com.android.systemui.BatteryLevelTextView android:id="@+id/battery_level_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginStart="@dimen/header_battery_margin_expanded"
android:paddingEnd="@dimen/battery_level_padding_end"
- android:textColor="#ffffff"
+ android:textColor="@color/status_bar_battery_level_text_color"
android:textSize="@dimen/battery_level_text_size"
android:importantForAccessibility="noHideDescendants"/>
</LinearLayout>
@@ -115,6 +115,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/clock_collapsed_bottom_margin"
+ android:background="@drawable/ripple_drawable"
android:layout_alignParentBottom="true">
<com.android.systemui.statusbar.policy.DateView android:id="@+id/date_collapsed"
android:layout_width="wrap_content"
@@ -137,13 +138,18 @@
/>
</FrameLayout>
- <include layout="@layout/split_clock_view"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginStart="16dp"
- android:layout_above="@id/date_group"
- android:id="@+id/clock"
- />
+ <FrameLayout
+ android:id="@+id/clock"
+ android:layout_marginStart="16dp"
+ android:layout_above="@id/date_group"
+ android:background="@drawable/ripple_drawable"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content">
+ <include layout="@layout/split_clock_view"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ />
+ </FrameLayout>
<com.android.systemui.statusbar.AlphaOptimizedButton android:id="@+id/alarm_status"
android:layout_width="wrap_content"
@@ -153,16 +159,48 @@
android:layout_marginBottom="4dp"
android:drawablePadding="6dp"
android:drawableStart="@drawable/ic_access_alarms_small"
- android:textColor="#64ffffff"
+ android:textColor="@color/status_bar_alarm_status_text_color"
android:textAppearance="@style/TextAppearance.StatusBar.Expanded.Date"
android:paddingEnd="6dp"
android:paddingStart="6dp"
android:paddingTop="16dp"
android:paddingBottom="16dp"
- android:background="?android:attr/selectableItemBackground"
+ android:background="@drawable/ripple_drawable"
android:visibility="gone"
/>
+ <LinearLayout
+ android:id="@+id/weather_container"
+ android:background="@drawable/ripple_drawable"
+ android:orientation="vertical"
+ android:layout_marginBottom="@dimen/clock_collapsed_bottom_margin"
+ android:layout_alignParentBottom="true"
+ android:layout_alignParentEnd="true"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:layout_width="wrap_content">
+ <TextView
+ android:id="@+id/weather_line_1"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingEnd="@dimen/status_bar_weather_padding_end"
+ android:gravity="right"
+ android:textColor="@color/status_bar_temperature_text_color"
+ android:textSize="@dimen/weather_text_size"
+ android:textAppearance="@style/TextAppearance.StatusBar.Expanded.WeatherTemp"
+ android:importantForAccessibility="noHideDescendants"/>
+ <TextView
+ android:id="@+id/weather_line_2"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingEnd="@dimen/status_bar_weather_padding_end"
+ android:gravity="right"
+ android:textColor="@color/status_bar_temperature_location_text_color"
+ android:textSize="@dimen/weather_text_size"
+ android:textAppearance="@style/TextAppearance.StatusBar.Expanded.WeatherLocation"
+ android:importantForAccessibility="noHideDescendants"/>
+ </LinearLayout>
+
<include
android:id="@+id/qs_detail_header"
layout="@layout/qs_detail_header"
diff --git a/packages/SystemUI/res/layout/super_status_bar.xml b/packages/SystemUI/res/layout/super_status_bar.xml
index e42ce66..7ef4db1 100644
--- a/packages/SystemUI/res/layout/super_status_bar.xml
+++ b/packages/SystemUI/res/layout/super_status_bar.xml
@@ -18,12 +18,14 @@
-->
<!-- This is the combined status bar / notification panel window. -->
-<com.android.systemui.statusbar.phone.StatusBarWindowView
+<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:sysui="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:fitsSystemWindows="true">
+ android:focusable="true"
+ android:fitsSystemWindows="false"
+ android:descendantFocusability="afterDescendants">
<com.android.systemui.statusbar.BackDropView
android:id="@+id/backdrop"
@@ -97,4 +99,4 @@
sysui:ignoreRightInset="true"
/>
-</com.android.systemui.statusbar.phone.StatusBarWindowView>
+</FrameLayout>
diff --git a/packages/SystemUI/res/layout/system_icons.xml b/packages/SystemUI/res/layout/system_icons.xml
index 943e846..8d15898 100644
--- a/packages/SystemUI/res/layout/system_icons.xml
+++ b/packages/SystemUI/res/layout/system_icons.xml
@@ -36,5 +36,6 @@
<com.android.systemui.BatteryMeterView android:id="@+id/battery"
android:layout_height="14.5dp"
android:layout_width="9.5dp"
- android:layout_marginBottom="@dimen/battery_margin_bottom"/>
+ android:layout_marginBottom="@dimen/battery_margin_bottom"
+ android:layout_marginStart="@dimen/signal_cluster_battery_padding"/>
</LinearLayout> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout/volume_dialog.xml b/packages/SystemUI/res/layout/volume_dialog.xml
index 7617ed4..a766261 100644
--- a/packages/SystemUI/res/layout/volume_dialog.xml
+++ b/packages/SystemUI/res/layout/volume_dialog.xml
@@ -22,7 +22,7 @@
android:layout_marginLeft="@dimen/notification_side_padding"
android:layout_marginRight="@dimen/notification_side_padding"
android:background="@drawable/volume_dialog_background"
- android:translationZ="4dp" >
+ android:translationZ="@dimen/volume_panel_z">
<com.android.keyguard.AlphaOptimizedImageButton
android:id="@+id/volume_expand_button"
@@ -48,4 +48,4 @@
<include layout="@layout/volume_zen_footer" />
</LinearLayout>
-</RelativeLayout> \ No newline at end of file
+</RelativeLayout>
diff --git a/packages/SystemUI/res/menu/recent_popup_menu.xml b/packages/SystemUI/res/menu/recent_popup_menu.xml
new file mode 100644
index 0000000..9b605f9
--- /dev/null
+++ b/packages/SystemUI/res/menu/recent_popup_menu.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* apps/common/assets/default/default/skins/StatusBar.xml
+**
+** Copyright 2011, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:id="@+id/recent_remove_item" android:title="@string/status_bar_recent_remove_item_title" />
+ <item android:id="@+id/recent_inspect_item" android:title="@string/status_bar_recent_inspect_item_title" />
+ <item android:id="@+id/recent_force_stop" android:title="@string/advanced_dev_option_force_stop" />
+ <item android:id="@+id/recent_wipe_app" android:title="@string/advanced_dev_option_wipe_app" />
+ <item android:id="@+id/recent_uninstall" android:title="@string/advanced_dev_option_uninstall" />
+</menu>
diff --git a/packages/SystemUI/res/values-hdpi/cm_dimens.xml b/packages/SystemUI/res/values-hdpi/cm_dimens.xml
new file mode 100644
index 0000000..404f22f
--- /dev/null
+++ b/packages/SystemUI/res/values-hdpi/cm_dimens.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2014 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.
+-->
+<resources>
+ <dimen name="weather_text_size">10sp</dimen>
+</resources> \ No newline at end of file
diff --git a/packages/SystemUI/res/values-land/cm_dimens.xml b/packages/SystemUI/res/values-land/cm_dimens.xml
new file mode 100644
index 0000000..e996f02
--- /dev/null
+++ b/packages/SystemUI/res/values-land/cm_dimens.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (c) 2015, 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.
+*/
+-->
+<resources>
+ <dimen name="phone_height">210dp</dimen>
+ <dimen name="phone_width">420dp</dimen>
+</resources>
diff --git a/packages/SystemUI/res/values-mdpi/cm_dimens.xml b/packages/SystemUI/res/values-mdpi/cm_dimens.xml
new file mode 100644
index 0000000..20d836a
--- /dev/null
+++ b/packages/SystemUI/res/values-mdpi/cm_dimens.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2014 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.
+-->
+<resources>
+ <dimen name="weather_text_size">9sp</dimen>
+</resources> \ No newline at end of file
diff --git a/packages/SystemUI/res/values-xhdpi/cm_dimens.xml b/packages/SystemUI/res/values-xhdpi/cm_dimens.xml
new file mode 100644
index 0000000..eacf1d9
--- /dev/null
+++ b/packages/SystemUI/res/values-xhdpi/cm_dimens.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2014 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.
+-->
+<resources>
+ <dimen name="weather_text_size">12sp</dimen>
+</resources> \ No newline at end of file
diff --git a/packages/SystemUI/res/values-xxhdpi/cm_dimens.xml b/packages/SystemUI/res/values-xxhdpi/cm_dimens.xml
new file mode 100644
index 0000000..eacf1d9
--- /dev/null
+++ b/packages/SystemUI/res/values-xxhdpi/cm_dimens.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2014 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.
+-->
+<resources>
+ <dimen name="weather_text_size">12sp</dimen>
+</resources> \ No newline at end of file
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 06acce2..4aa71bb 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -142,7 +142,7 @@
<string name="accessibility_data_connection_4g" msgid="7741000750630089612">"4G"</string>
<string name="accessibility_data_connection_lte" msgid="5413468808637540658">"LTE"</string>
<string name="accessibility_data_connection_cdma" msgid="6132648193978823023">"CDMA"</string>
- <string name="accessibility_data_connection_roaming" msgid="5977362333466556094">"漫游中"</string>
+ <string name="accessibility_data_connection_roaming" msgid="5977362333466556094">"数据漫游"</string>
<string name="accessibility_data_connection_edge" msgid="4477457051631979278">"EDGE"</string>
<string name="accessibility_data_connection_wifi" msgid="2324496756590645221">"WLAN"</string>
<string name="accessibility_no_sim" msgid="8274017118472455155">"无 SIM 卡。"</string>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 4ace18e..7d704d3 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -142,7 +142,7 @@
<string name="accessibility_data_connection_4g" msgid="7741000750630089612">"4G"</string>
<string name="accessibility_data_connection_lte" msgid="5413468808637540658">"LTE"</string>
<string name="accessibility_data_connection_cdma" msgid="6132648193978823023">"CDMA"</string>
- <string name="accessibility_data_connection_roaming" msgid="5977362333466556094">"漫遊中"</string>
+ <string name="accessibility_data_connection_roaming" msgid="5977362333466556094">"數據漫遊"</string>
<string name="accessibility_data_connection_edge" msgid="4477457051631979278">"Edge"</string>
<string name="accessibility_data_connection_wifi" msgid="2324496756590645221">"Wi-Fi"</string>
<string name="accessibility_no_sim" msgid="8274017118472455155">"沒有 SIM 卡。"</string>
diff --git a/packages/SystemUI/res/values/arrays.xml b/packages/SystemUI/res/values/arrays.xml
index 6102aa6..0dd957e 100644
--- a/packages/SystemUI/res/values/arrays.xml
+++ b/packages/SystemUI/res/values/arrays.xml
@@ -1,5 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
+/*
+ * Copyright (c) 2014, 2015 The Linux Foundation. All rights reserved.
+ * Not a Contribution.
/* //device/apps/common/assets/res/any/colors.xml
**
** Copyright 2012, The Android Open Source Project
@@ -26,7 +29,7 @@
</array>
<array name="batterymeter_color_values">
<item>@*android:color/battery_saver_mode_color</item>
- <item>#FFFFFFFF</item>
+ <item>@color/batterymeter_base_color</item>
</array>
<array name="batterymeter_bolt_points">
<item>73</item> <item>0</item>
@@ -37,4 +40,1092 @@
<item>157</item><item>334</item>
<item>0</item> <item>334</item>
</array>
+
+ <!-- added for customized status bar -->
+ <!--data type-->
+ <!--Add three items to support TSTS-->
+ <string-array name="multi_data_type">
+ <item>array/telephony_data_type_sim1</item>
+ <item>array/telephony_data_type_sim1</item>
+ <item>array/telephony_data_type_sim1</item>
+ </string-array>
+
+ <string-array name="telephony_data_type_sim1">
+ <!--NETWORK_TYPE_UNKNOWN-->
+ <item>0</item>
+ <!--NETWORK_TYPE_GPRS-->
+ <item>drawable/stat_sys_data_fully_connected_g</item>
+ <!--NETWORK_TYPE_EDGE-->
+ <item>drawable/stat_sys_data_fully_connected_e</item>
+ <!--NETWORK_TYPE_UMTS-->
+ <item>drawable/stat_sys_data_fully_connected_3g</item>
+ <!--NETWORK_TYPE_CDMA-->
+ <item>drawable/stat_sys_data_fully_connected_1x</item>
+ <!--NETWORK_TYPE_EVDO_0-->
+ <item>drawable/stat_sys_data_fully_connected_3g</item>
+ <!--NETWORK_TYPE_EVDO_A-->
+ <item>drawable/stat_sys_data_fully_connected_3g</item>
+ <!--NETWORK_TYPE_1xRTT-->
+ <item>drawable/stat_sys_data_fully_connected_1x</item>
+ <!--NETWORK_TYPE_HSDPA-->
+ <item>drawable/stat_sys_data_fully_connected_h</item>
+ <!--NETWORK_TYPE_HSUPA-->
+ <item>drawable/stat_sys_data_fully_connected_h</item>
+ <!--NETWORK_TYPE_HSPA-->
+ <item>drawable/stat_sys_data_fully_connected_h</item>
+ <!--NETWORK_TYPE_IDEN-->
+ <item>0</item>
+ <!--NETWORK_TYPE_EVDO_B-->
+ <item>drawable/stat_sys_data_fully_connected_3g</item>
+ <!--NETWORK_TYPE_LTE-->
+ <item>drawable/stat_sys_data_fully_connected_3g</item>
+ <!--NETWORK_TYPE_EHRPD-->
+ <item>drawable/stat_sys_data_fully_connected_3g</item>
+ <!--NETWORK_TYPE_HSPAP-->
+ <item>drawable/stat_sys_data_fully_connected_3g</item>
+ <!--NETWORK_TYPE_GSM-->
+ <item>drawable/stat_sys_data_fully_connected_g</item>
+ <!--NETWORK_TYPE_TD_SCDMA-->
+ <item>drawable/stat_sys_data_fully_connected_3g</item>
+ <!--NETWORK_TYPE_IWLAN-->
+ <item>0</item>
+ </string-array>
+
+ <!--reserved for overlay-->
+ <string-array name="telephony_data_type_sim2">
+ </string-array>
+
+ <!--reserved for overlay-->
+ <string-array name="telephony_data_type_sim3">
+ </string-array>
+
+ <string-array name="telephony_data_type_generation">
+ <!--3G-->
+ <item>drawable/stat_sys_data_fully_connected_3g</item>
+ <!--4G-->
+ <item>drawable/stat_sys_data_fully_connected_4g</item>
+ <!--4G+-->
+ <item>drawable/stat_sys_data_fully_connected_4g_plus</item>
+ </string-array>
+
+ <!--data type description-->
+ <string-array name="telephony_data_type_description">
+ <!--NETWORK_TYPE_UNKNOWN-->
+ <item>0</item>
+ <!--NETWORK_TYPE_GPRS-->
+ <item>string/accessibility_data_connection_gprs</item>
+ <!--NETWORK_TYPE_EDGE-->
+ <item>string/accessibility_data_connection_edge</item>
+ <!--NETWORK_TYPE_UMTS-->
+ <item>string/accessibility_data_connection_3g</item>
+ <!--NETWORK_TYPE_CDMA-->
+ <item>string/accessibility_data_connection_cdma</item>
+ <!--NETWORK_TYPE_EVDO_0-->
+ <item>string/accessibility_data_connection_3g</item>
+ <!--NETWORK_TYPE_EVDO_A-->
+ <item>string/accessibility_data_connection_3g</item>
+ <!--NETWORK_TYPE_1xRTT-->
+ <item>string/accessibility_data_connection_cdma</item>
+ <!--NETWORK_TYPE_HSDPA-->
+ <item>string/accessibility_data_connection_3.5g</item>
+ <!--NETWORK_TYPE_HSUPA-->
+ <item>string/accessibility_data_connection_3.5g</item>
+ <!--NETWORK_TYPE_HSPA-->
+ <item>string/accessibility_data_connection_3.5g</item>
+ <!--NETWORK_TYPE_IDEN-->
+ <item>0</item>
+ <!--NETWORK_TYPE_EVDO_B-->
+ <item>string/accessibility_data_connection_3g</item>
+ <!--NETWORK_TYPE_LTE-->
+ <item>string/accessibility_data_connection_lte</item>
+ <!--NETWORK_TYPE_EHRPD-->
+ <item>string/accessibility_data_connection_3g</item>
+ <!--NETWORK_TYPE_HSPAP-->
+ <item>string/accessibility_data_connection_3.5g</item>
+ <!--NETWORK_TYPE_GSM-->
+ <item>string/accessibility_data_connection_gprs</item>
+ <!--NETWORK_TYPE_TD_SCDMA-->
+ <item>string/accessibility_data_connection_3g</item>
+ <!--NETWORK_TYPE_IWLAN-->
+ <item>0</item>
+ </string-array>
+
+ <string-array name="telephony_data_type_generation_description">
+ <!--3G-->
+ <item>string/accessibility_data_connection_3g</item>
+ <!--4G-->
+ <item>string/accessibility_data_connection_4g</item>
+ </string-array>
+
+ <!--data activity-->
+ <!--Add three items to support TSTS-->
+ <string-array name="multi_data_activity">
+ <item>array/data_activity_sim1</item>
+ <item>array/data_activity_sim1</item>
+ <item>array/data_activity_sim1</item>
+ </string-array>
+
+ <string-array name="data_activity_sim1">
+ <item>array/telephony_data_activity_unknown_sim1</item>
+ <item>array/telephony_data_activity_g_sim1</item>
+ <item>array/telephony_data_activity_e_sim1</item>
+ <item>array/telephony_data_activity_2g_sim1</item>
+ <item>array/telephony_data_activity_3g_sim1</item>
+ <item>array/telephony_data_activity_4g_sim1</item>
+ <item>array/telephony_data_activity_h_sim1</item>
+ <item>array/telephony_data_activity_hp_sim1</item>
+ <item>array/telephony_data_activity_1x_sim1</item>
+ <item>array/telephony_data_activity_lte_sim1</item>
+ </string-array>
+
+ <!--reserved for overlay-->
+ <string-array name="data_activity_sim2">
+ </string-array>
+ <!--reserved for overlay-->
+ <string-array name="data_activity_sim3">
+ </string-array>
+
+ <string-array name="telephony_data_activity_unknown_sim1">
+ <item>0</item><!--none-->
+ <item>0</item><!--in-->
+ <item>0</item><!--out-->
+ <item>0</item><!--inout-->
+ <item>0</item><!--dormant-->
+ </string-array>
+
+ <!--reserved for overlay-->
+ <string-array name="telephony_data_activity_unknown_sim2">
+ </string-array>
+ <!--reserved for overlay-->
+ <string-array name="telephony_data_activity_unknown_sim3">
+ </string-array>
+
+ <string-array name="telephony_data_activity_g_sim1">
+ <item>0</item>
+ <item>drawable/stat_sys_signal_in_auto_mirrored</item>
+ <item>drawable/stat_sys_signal_out_auto_mirrored</item>
+ <item>drawable/stat_sys_signal_inout_auto_mirrored</item>
+ <item>0</item>
+ </string-array>
+
+ <!--reserved for overlay-->
+ <string-array name="telephony_data_activity_g_sim2">
+ </string-array>
+ <!--reserved for overlay-->
+ <string-array name="telephony_data_activity_g_sim3">
+ </string-array>
+
+ <string-array name="telephony_data_activity_e_sim1">
+ <item>0</item>
+ <item>drawable/stat_sys_signal_in_auto_mirrored</item>
+ <item>drawable/stat_sys_signal_out_auto_mirrored</item>
+ <item>drawable/stat_sys_signal_inout_auto_mirrored</item>
+ <item>0</item>
+ </string-array>
+
+ <!--reserved for overlay-->
+ <string-array name="telephony_data_activity_e_sim2">
+ </string-array>
+ <!--reserved for overlay-->
+ <string-array name="telephony_data_activity_e_sim3">
+ </string-array>
+
+ <string-array name="telephony_data_activity_2g_sim1">
+ <item>0</item>
+ <item>drawable/stat_sys_signal_in_auto_mirrored</item>
+ <item>drawable/stat_sys_signal_out_auto_mirrored</item>
+ <item>drawable/stat_sys_signal_inout_auto_mirrored</item>
+ <item>0</item>
+ </string-array>
+
+ <!--reserved for overlay-->
+ <string-array name="telephony_data_activity_2g_sim2">
+ </string-array>
+ <!--reserved for overlay-->
+ <string-array name="telephony_data_activity_2g_sim3">
+ </string-array>
+
+ <string-array name="telephony_data_activity_3g_sim1">
+ <item>0</item>
+ <item>drawable/stat_sys_signal_in_auto_mirrored</item>
+ <item>drawable/stat_sys_signal_out_auto_mirrored</item>
+ <item>drawable/stat_sys_signal_inout_auto_mirrored</item>
+ <item>0</item>
+ </string-array>
+
+ <!--reserved for overlay-->
+ <string-array name="telephony_data_activity_3g_sim2">
+ </string-array>
+ <!--reserved for overlay-->
+ <string-array name="telephony_data_activity_3g_sim3">
+ </string-array>
+
+ <string-array name="telephony_data_activity_4g_sim1">
+ <item>0</item>
+ <item>drawable/stat_sys_signal_in_auto_mirrored</item>
+ <item>drawable/stat_sys_signal_out_auto_mirrored</item>
+ <item>drawable/stat_sys_signal_inout_auto_mirrored</item>
+ <item>0</item>
+ </string-array>
+
+ <!--reserved for overlay-->
+ <string-array name="telephony_data_activity_4g_sim2">
+ </string-array>
+ <!--reserved for overlay-->
+ <string-array name="telephony_data_activity_4g_sim3">
+ </string-array>
+
+ <string-array name="telephony_data_activity_h_sim1">
+ <item>0</item>
+ <item>drawable/stat_sys_signal_in_auto_mirrored</item>
+ <item>drawable/stat_sys_signal_out_auto_mirrored</item>
+ <item>drawable/stat_sys_signal_inout_auto_mirrored</item>
+ <item>0</item>
+ </string-array>
+
+ <!--reserved for overlay-->
+ <string-array name="telephony_data_activity_h_sim2">
+ </string-array>
+ <!--reserved for overlay-->
+ <string-array name="telephony_data_activity_h_sim3">
+ </string-array>
+
+ <string-array name="telephony_data_activity_hp_sim1">
+ <item>0</item>
+ <item>drawable/stat_sys_signal_in_auto_mirrored</item>
+ <item>drawable/stat_sys_signal_out_auto_mirrored</item>
+ <item>drawable/stat_sys_signal_inout_auto_mirrored</item>
+ <item>0</item>
+ </string-array>
+
+ <!--reserved for overlay-->
+ <string-array name="telephony_data_activity_hp_sim2">
+ </string-array>
+ <!--reserved for overlay-->
+ <string-array name="telephony_data_activity_hp_sim3">
+ </string-array>
+
+ <string-array name="telephony_data_activity_1x_sim1">
+ <item>0</item>
+ <item>drawable/stat_sys_signal_in_auto_mirrored</item>
+ <item>drawable/stat_sys_signal_out_auto_mirrored</item>
+ <item>drawable/stat_sys_signal_inout_auto_mirrored</item>
+ <item>0</item>
+ </string-array>
+
+ <!--reserved for overlay-->
+ <string-array name="telephony_data_activity_1x_sim2">
+ </string-array>
+ <!--reserved for overlay-->
+ <string-array name="telephony_data_activity_1x_sim3">
+ </string-array>
+
+ <string-array name="telephony_data_activity_lte_sim1">
+ <item>0</item>
+ <item>drawable/stat_sys_signal_in_auto_mirrored</item>
+ <item>drawable/stat_sys_signal_out_auto_mirrored</item>
+ <item>drawable/stat_sys_signal_inout_auto_mirrored</item>
+ <item>0</item>
+ </string-array>
+
+ <!--reserved for overlay-->
+ <string-array name="telephony_data_activity_lte_sim2">
+ </string-array>
+ <!--reserved for overlay-->
+ <string-array name="telephony_data_activity_lte_sim3">
+ </string-array>
+
+ <!--signal strength-->
+ <!--Add three items to support TSTS-->
+ <string-array name="multi_signal_strength">
+ <item>array/telephony_siganl_strength_sim1</item>
+ <item>array/telephony_siganl_strength_sim1</item>
+ <item>array/telephony_siganl_strength_sim1</item>
+ </string-array>
+
+ <!--Add three items to support TSTS-->
+ <string-array name="multi_signal_strength_roaming">
+ <item>array/telephony_siganl_strength_roaming_sim1</item>
+ <item>array/telephony_siganl_strength_roaming_sim1</item>
+ <item>array/telephony_siganl_strength_roaming_sim1</item>
+ </string-array>
+
+ <string-array name="telephony_siganl_strength_sim1">
+ <item>array/telephony_signal_strength_g_sim1</item>
+ <item>array/telephony_signal_strength_e_sim1</item>
+ <item>array/telephony_signal_strength_3g_sim1</item>
+ <item>array/telephony_signal_strength_4g_sim1</item>
+ <item>array/telephony_signal_strength_h_sim1</item>
+ <item>array/telephony_signal_strength_hp_sim1</item>
+ <item>array/telephony_signal_strength_1x_sim1</item>
+ <item>array/telephony_signal_strength_cdma_sim1</item>
+ <item>array/telephony_signal_strength_umts_sim1</item>
+ </string-array>
+
+ <!--reserved for overlay-->
+ <string-array name="telephony_siganl_strength_sim2">
+ </string-array>
+ <string-array name="telephony_siganl_strength_sim3">
+ </string-array>
+
+ <string-array name="telephony_siganl_strength_roaming_sim1">
+ <item>array/telephony_signal_strength_g_roaming_sim1</item>
+ <item>array/telephony_signal_strength_e_roaming_sim1</item>
+ <item>array/telephony_signal_strength_3g_roaming_sim1</item>
+ <item>array/telephony_signal_strength_4g_roaming_sim1</item>
+ <item>array/telephony_signal_strength_h_roaming_sim1</item>
+ <item>array/telephony_signal_strength_hp_roaming_sim1</item>
+ <item>array/telephony_signal_strength_1x_roaming_sim1</item>
+ <item>array/telephony_signal_strength_cdma_roaming_sim1</item>
+ <item>array/telephony_signal_strength_umts_roaming_sim1</item>
+ </string-array>
+
+ <!--reserved for overlay-->
+ <string-array name="telephony_siganl_strength_roaming_sim2">
+ </string-array>
+ <string-array name="telephony_siganl_strength_roaming_sim3">
+ </string-array>
+
+ <string-array name="telephony_signal_strength_g_sim1">
+ <item>array/signal_strength_g_normal_sim1</item>
+ <item>array/signal_strength_g_fully_sim1</item>
+ </string-array>
+
+ <string-array name="telephony_signal_strength_g_roaming_sim1">
+ <item>array/signal_strength_g_normal_roaming_sim1</item>
+ <item>array/signal_strength_g_fully_roaming_sim1</item>
+ </string-array>
+
+ <string-array name="telephony_signal_strength_e_sim1">
+ <item>array/signal_strength_e_normal_sim1</item>
+ <item>array/signal_strength_e_fully_sim1</item>
+ </string-array>
+
+ <string-array name="telephony_signal_strength_e_roaming_sim1">
+ <item>array/signal_strength_e_normal_roaming_sim1</item>
+ <item>array/signal_strength_e_fully_roaming_sim1</item>
+ </string-array>
+
+ <string-array name="telephony_signal_strength_3g_sim1">
+ <item>array/signal_strength_3g_normal_sim1</item>
+ <item>array/signal_strength_3g_fully_sim1</item>
+ </string-array>
+
+ <string-array name="telephony_signal_strength_3g_roaming_sim1">
+ <item>array/signal_strength_3g_normal_roaming_sim1</item>
+ <item>array/signal_strength_3g_fully_roaming_sim1</item>
+ </string-array>
+
+ <string-array name="telephony_signal_strength_4g_sim1">
+ <item>array/signal_strength_4g_normal_sim1</item>
+ <item>array/signal_strength_4g_fully_sim1</item>
+ </string-array>
+
+ <string-array name="telephony_signal_strength_4g_roaming_sim1">
+ <item>array/signal_strength_4g_normal_roaming_sim1</item>
+ <item>array/signal_strength_4g_fully_roaming_sim1</item>
+ </string-array>
+
+ <string-array name="telephony_signal_strength_h_sim1">
+ <item>array/signal_strength_h_normal_sim1</item>
+ <item>array/signal_strength_h_fully_sim1</item>
+ </string-array>
+
+ <string-array name="telephony_signal_strength_h_roaming_sim1">
+ <item>array/signal_strength_h_normal_roaming_sim1</item>
+ <item>array/signal_strength_h_fully_roaming_sim1</item>
+ </string-array>
+
+ <string-array name="telephony_signal_strength_hp_sim1">
+ <item>array/signal_strength_hp_normal_sim1</item>
+ <item>array/signal_strength_hp_fully_sim1</item>
+ </string-array>
+
+ <string-array name="telephony_signal_strength_hp_roaming_sim1">
+ <item>array/signal_strength_hp_normal_roaming_sim1</item>
+ <item>array/signal_strength_hp_fully_roaming_sim1</item>
+ </string-array>
+
+ <string-array name="telephony_signal_strength_1x_sim1">
+ <item>array/signal_strength_1x_normal_sim1</item>
+ <item>array/signal_strength_1x_fully_sim1</item>
+ </string-array>
+
+ <string-array name="telephony_signal_strength_1x_roaming_sim1">
+ <item>array/signal_strength_1x_normal_roaming_sim1</item>
+ <item>array/signal_strength_1x_fully_roaming_sim1</item>
+ </string-array>
+
+ <string-array name="telephony_signal_strength_cdma_sim1">
+ <item>array/signal_strength_cdma_normal_sim1</item>
+ <item>array/signal_strength_cdma_fully_sim1</item>
+ </string-array>
+
+ <string-array name="telephony_signal_strength_cdma_roaming_sim1">
+ <item>array/signal_strength_cdma_normal_roaming_sim1</item>
+ <item>array/signal_strength_cdma_fully_roaming_sim1</item>
+ </string-array>
+
+ <string-array name="telephony_signal_strength_umts_sim1">
+ <item>array/signal_strength_umts_normal_sim1</item>
+ <item>array/signal_strength_umts_fully_sim1</item>
+ </string-array>
+
+ <string-array name="telephony_signal_strength_umts_roaming_sim1">
+ <item>array/signal_strength_umts_normal_roaming_sim1</item>
+ <item>array/signal_strength_umts_fully_roaming_sim1</item>
+ </string-array>
+
+ <string-array name="signal_strength_g_normal_sim1">
+ <item>drawable/stat_sys_signal_0_fully</item>
+ <item>drawable/stat_sys_signal_1_fully</item>
+ <item>drawable/stat_sys_signal_2_fully</item>
+ <item>drawable/stat_sys_signal_3_fully</item>
+ <item>drawable/stat_sys_signal_4_fully</item>
+ </string-array>
+
+ <string-array name="signal_strength_g_fully_sim1">
+ <item>drawable/stat_sys_signal_0_fully</item>
+ <item>drawable/stat_sys_signal_1_fully</item>
+ <item>drawable/stat_sys_signal_2_fully</item>
+ <item>drawable/stat_sys_signal_3_fully</item>
+ <item>drawable/stat_sys_signal_4_fully</item>
+ </string-array>
+
+ <string-array name="signal_strength_g_normal_roaming_sim1">
+ <item>drawable/stat_sys_signal_0_fully</item>
+ <item>drawable/stat_sys_signal_1_fully</item>
+ <item>drawable/stat_sys_signal_2_fully</item>
+ <item>drawable/stat_sys_signal_3_fully</item>
+ <item>drawable/stat_sys_signal_4_fully</item>
+ </string-array>
+
+ <string-array name="signal_strength_g_fully_roaming_sim1">
+ <item>drawable/stat_sys_signal_0_fully</item>
+ <item>drawable/stat_sys_signal_1_fully</item>
+ <item>drawable/stat_sys_signal_2_fully</item>
+ <item>drawable/stat_sys_signal_3_fully</item>
+ <item>drawable/stat_sys_signal_4_fully</item>
+ </string-array>
+
+ <string-array name="signal_strength_e_normal_sim1">
+ <item>drawable/stat_sys_signal_0_fully</item>
+ <item>drawable/stat_sys_signal_1_fully</item>
+ <item>drawable/stat_sys_signal_2_fully</item>
+ <item>drawable/stat_sys_signal_3_fully</item>
+ <item>drawable/stat_sys_signal_4_fully</item>
+ </string-array>
+
+ <string-array name="signal_strength_e_fully_sim1">
+ <item>drawable/stat_sys_signal_0_fully</item>
+ <item>drawable/stat_sys_signal_1_fully</item>
+ <item>drawable/stat_sys_signal_2_fully</item>
+ <item>drawable/stat_sys_signal_3_fully</item>
+ <item>drawable/stat_sys_signal_4_fully</item>
+ </string-array>
+
+ <string-array name="signal_strength_e_normal_roaming_sim1">
+ <item>drawable/stat_sys_signal_0_fully</item>
+ <item>drawable/stat_sys_signal_1_fully</item>
+ <item>drawable/stat_sys_signal_2_fully</item>
+ <item>drawable/stat_sys_signal_3_fully</item>
+ <item>drawable/stat_sys_signal_4_fully</item>
+ </string-array>
+
+ <string-array name="signal_strength_e_fully_roaming_sim1">
+ <item>drawable/stat_sys_signal_0_fully</item>
+ <item>drawable/stat_sys_signal_1_fully</item>
+ <item>drawable/stat_sys_signal_2_fully</item>
+ <item>drawable/stat_sys_signal_3_fully</item>
+ <item>drawable/stat_sys_signal_4_fully</item>
+ </string-array>
+
+ <string-array name="signal_strength_3g_normal_sim1">
+ <item>drawable/stat_sys_signal_0_fully</item>
+ <item>drawable/stat_sys_signal_1_fully</item>
+ <item>drawable/stat_sys_signal_2_fully</item>
+ <item>drawable/stat_sys_signal_3_fully</item>
+ <item>drawable/stat_sys_signal_4_fully</item>
+ </string-array>
+
+ <string-array name="signal_strength_3g_fully_sim1">
+ <item>drawable/stat_sys_signal_0_fully</item>
+ <item>drawable/stat_sys_signal_1_fully</item>
+ <item>drawable/stat_sys_signal_2_fully</item>
+ <item>drawable/stat_sys_signal_3_fully</item>
+ <item>drawable/stat_sys_signal_4_fully</item>
+ </string-array>
+
+ <string-array name="signal_strength_3g_normal_roaming_sim1">
+ <item>drawable/stat_sys_signal_0_fully</item>
+ <item>drawable/stat_sys_signal_1_fully</item>
+ <item>drawable/stat_sys_signal_2_fully</item>
+ <item>drawable/stat_sys_signal_3_fully</item>
+ <item>drawable/stat_sys_signal_4_fully</item>
+ </string-array>
+
+ <string-array name="signal_strength_3g_fully_roaming_sim1">
+ <item>drawable/stat_sys_signal_0_fully</item>
+ <item>drawable/stat_sys_signal_1_fully</item>
+ <item>drawable/stat_sys_signal_2_fully</item>
+ <item>drawable/stat_sys_signal_3_fully</item>
+ <item>drawable/stat_sys_signal_4_fully</item>
+ </string-array>
+
+ <string-array name="signal_strength_4g_normal_sim1">
+ <item>drawable/stat_sys_signal_0_fully</item>
+ <item>drawable/stat_sys_signal_1_fully</item>
+ <item>drawable/stat_sys_signal_2_fully</item>
+ <item>drawable/stat_sys_signal_3_fully</item>
+ <item>drawable/stat_sys_signal_4_fully</item>
+ </string-array>
+
+ <string-array name="signal_strength_4g_fully_sim1">
+ <item>drawable/stat_sys_signal_0_fully</item>
+ <item>drawable/stat_sys_signal_1_fully</item>
+ <item>drawable/stat_sys_signal_2_fully</item>
+ <item>drawable/stat_sys_signal_3_fully</item>
+ <item>drawable/stat_sys_signal_4_fully</item>
+ </string-array>
+
+ <string-array name="signal_strength_4g_normal_roaming_sim1">
+ <item>drawable/stat_sys_signal_0_fully</item>
+ <item>drawable/stat_sys_signal_1_fully</item>
+ <item>drawable/stat_sys_signal_2_fully</item>
+ <item>drawable/stat_sys_signal_3_fully</item>
+ <item>drawable/stat_sys_signal_4_fully</item>
+ </string-array>
+
+ <string-array name="signal_strength_4g_fully_roaming_sim1">
+ <item>drawable/stat_sys_signal_0_fully</item>
+ <item>drawable/stat_sys_signal_1_fully</item>
+ <item>drawable/stat_sys_signal_2_fully</item>
+ <item>drawable/stat_sys_signal_3_fully</item>
+ <item>drawable/stat_sys_signal_4_fully</item>
+ </string-array>
+
+ <string-array name="signal_strength_h_normal_sim1">
+ <item>drawable/stat_sys_signal_0_fully</item>
+ <item>drawable/stat_sys_signal_1_fully</item>
+ <item>drawable/stat_sys_signal_2_fully</item>
+ <item>drawable/stat_sys_signal_3_fully</item>
+ <item>drawable/stat_sys_signal_4_fully</item>
+ </string-array>
+
+ <string-array name="signal_strength_h_fully_sim1">
+ <item>drawable/stat_sys_signal_0_fully</item>
+ <item>drawable/stat_sys_signal_1_fully</item>
+ <item>drawable/stat_sys_signal_2_fully</item>
+ <item>drawable/stat_sys_signal_3_fully</item>
+ <item>drawable/stat_sys_signal_4_fully</item>
+ </string-array>
+
+ <string-array name="signal_strength_h_normal_roaming_sim1">
+ <item>drawable/stat_sys_signal_0_fully</item>
+ <item>drawable/stat_sys_signal_1_fully</item>
+ <item>drawable/stat_sys_signal_2_fully</item>
+ <item>drawable/stat_sys_signal_3_fully</item>
+ <item>drawable/stat_sys_signal_4_fully</item>
+ </string-array>
+
+ <string-array name="signal_strength_h_fully_roaming_sim1">
+ <item>drawable/stat_sys_signal_0_fully</item>
+ <item>drawable/stat_sys_signal_1_fully</item>
+ <item>drawable/stat_sys_signal_2_fully</item>
+ <item>drawable/stat_sys_signal_3_fully</item>
+ <item>drawable/stat_sys_signal_4_fully</item>
+ </string-array>
+
+ <string-array name="signal_strength_hp_normal_sim1">
+ <item>drawable/stat_sys_signal_0_fully</item>
+ <item>drawable/stat_sys_signal_1_fully</item>
+ <item>drawable/stat_sys_signal_2_fully</item>
+ <item>drawable/stat_sys_signal_3_fully</item>
+ <item>drawable/stat_sys_signal_4_fully</item>
+ </string-array>
+
+ <string-array name="signal_strength_hp_fully_sim1">
+ <item>drawable/stat_sys_signal_0_fully</item>
+ <item>drawable/stat_sys_signal_1_fully</item>
+ <item>drawable/stat_sys_signal_2_fully</item>
+ <item>drawable/stat_sys_signal_3_fully</item>
+ <item>drawable/stat_sys_signal_4_fully</item>
+ </string-array>
+
+ <string-array name="signal_strength_hp_normal_roaming_sim1">
+ <item>drawable/stat_sys_signal_0_fully</item>
+ <item>drawable/stat_sys_signal_1_fully</item>
+ <item>drawable/stat_sys_signal_2_fully</item>
+ <item>drawable/stat_sys_signal_3_fully</item>
+ <item>drawable/stat_sys_signal_4_fully</item>
+ </string-array>
+
+ <string-array name="signal_strength_hp_fully_roaming_sim1">
+ <item>drawable/stat_sys_signal_0_fully</item>
+ <item>drawable/stat_sys_signal_1_fully</item>
+ <item>drawable/stat_sys_signal_2_fully</item>
+ <item>drawable/stat_sys_signal_3_fully</item>
+ <item>drawable/stat_sys_signal_4_fully</item>
+ </string-array>
+
+ <string-array name="signal_strength_1x_normal_sim1">
+ <item>drawable/stat_sys_signal_0_fully</item>
+ <item>drawable/stat_sys_signal_1_fully</item>
+ <item>drawable/stat_sys_signal_2_fully</item>
+ <item>drawable/stat_sys_signal_3_fully</item>
+ <item>drawable/stat_sys_signal_4_fully</item>
+ </string-array>
+
+ <string-array name="signal_strength_1x_fully_sim1">
+ <item>drawable/stat_sys_signal_0_fully</item>
+ <item>drawable/stat_sys_signal_1_fully</item>
+ <item>drawable/stat_sys_signal_2_fully</item>
+ <item>drawable/stat_sys_signal_3_fully</item>
+ <item>drawable/stat_sys_signal_4_fully</item>
+ </string-array>
+
+ <string-array name="signal_strength_1x_normal_roaming_sim1">
+ <item>drawable/stat_sys_signal_0_fully</item>
+ <item>drawable/stat_sys_signal_1_fully</item>
+ <item>drawable/stat_sys_signal_2_fully</item>
+ <item>drawable/stat_sys_signal_3_fully</item>
+ <item>drawable/stat_sys_signal_4_fully</item>
+ </string-array>
+
+ <string-array name="signal_strength_1x_fully_roaming_sim1">
+ <item>drawable/stat_sys_signal_0_fully</item>
+ <item>drawable/stat_sys_signal_1_fully</item>
+ <item>drawable/stat_sys_signal_2_fully</item>
+ <item>drawable/stat_sys_signal_3_fully</item>
+ <item>drawable/stat_sys_signal_4_fully</item>
+ </string-array>
+
+ <string-array name="signal_strength_cdma_normal_sim1">
+ <item>drawable/stat_sys_signal_0_fully</item>
+ <item>drawable/stat_sys_signal_1_fully</item>
+ <item>drawable/stat_sys_signal_2_fully</item>
+ <item>drawable/stat_sys_signal_3_fully</item>
+ <item>drawable/stat_sys_signal_4_fully</item>
+ </string-array>
+
+ <string-array name="signal_strength_cdma_fully_sim1">
+ <item>drawable/stat_sys_signal_0_fully</item>
+ <item>drawable/stat_sys_signal_1_fully</item>
+ <item>drawable/stat_sys_signal_2_fully</item>
+ <item>drawable/stat_sys_signal_3_fully</item>
+ <item>drawable/stat_sys_signal_4_fully</item>
+ </string-array>
+
+ <string-array name="signal_strength_cdma_normal_roaming_sim1">
+ <item>drawable/stat_sys_signal_0_fully</item>
+ <item>drawable/stat_sys_signal_1_fully</item>
+ <item>drawable/stat_sys_signal_2_fully</item>
+ <item>drawable/stat_sys_signal_3_fully</item>
+ <item>drawable/stat_sys_signal_4_fully</item>
+ </string-array>
+
+ <string-array name="signal_strength_cdma_fully_roaming_sim1">
+ <item>drawable/stat_sys_signal_0_fully</item>
+ <item>drawable/stat_sys_signal_1_fully</item>
+ <item>drawable/stat_sys_signal_2_fully</item>
+ <item>drawable/stat_sys_signal_3_fully</item>
+ <item>drawable/stat_sys_signal_4_fully</item>
+ </string-array>
+
+ <string-array name="signal_strength_umts_normal_sim1">
+ <item>drawable/stat_sys_signal_0_fully</item>
+ <item>drawable/stat_sys_signal_1_fully</item>
+ <item>drawable/stat_sys_signal_2_fully</item>
+ <item>drawable/stat_sys_signal_3_fully</item>
+ <item>drawable/stat_sys_signal_4_fully</item>
+ </string-array>
+
+ <string-array name="signal_strength_umts_fully_sim1">
+ <item>drawable/stat_sys_signal_0_fully</item>
+ <item>drawable/stat_sys_signal_1_fully</item>
+ <item>drawable/stat_sys_signal_2_fully</item>
+ <item>drawable/stat_sys_signal_3_fully</item>
+ <item>drawable/stat_sys_signal_4_fully</item>
+ </string-array>
+
+ <string-array name="signal_strength_umts_normal_roaming_sim1">
+ <item>drawable/stat_sys_signal_0_fully</item>
+ <item>drawable/stat_sys_signal_1_fully</item>
+ <item>drawable/stat_sys_signal_2_fully</item>
+ <item>drawable/stat_sys_signal_3_fully</item>
+ <item>drawable/stat_sys_signal_4_fully</item>
+ </string-array>
+
+ <string-array name="signal_strength_umts_fully_roaming_sim1">
+ <item>drawable/stat_sys_signal_0_fully</item>
+ <item>drawable/stat_sys_signal_1_fully</item>
+ <item>drawable/stat_sys_signal_2_fully</item>
+ <item>drawable/stat_sys_signal_3_fully</item>
+ <item>drawable/stat_sys_signal_4_fully</item>
+ </string-array>
+
+ <!--signal strength description-->
+ <string-array name="signal_strength_description">
+ <item>string/accessibility_no_phone</item>
+ <item>string/accessibility_phone_one_bar</item>
+ <item>string/accessibility_phone_two_bars</item>
+ <item>string/accessibility_phone_three_bars</item>
+ <item>string/accessibility_phone_signal_full</item>
+ </string-array>
+
+ <!--null signal-->
+ <!--Add three items to support TSTS-->
+ <string-array name="multi_signal_null">
+ <item>drawable/stat_sys_signal_null</item>
+ <item>drawable/stat_sys_signal_null</item>
+ <item>drawable/stat_sys_signal_null</item>
+ </string-array>
+
+ <!--no sim-->
+ <!--Add three items to support TSTS-->
+ <string-array name="multi_no_sim">
+ <item>drawable/stat_sys_no_sims</item>
+ <item>drawable/stat_sys_no_sims</item>
+ <item>drawable/stat_sys_no_sims</item>
+ </string-array>
+
+ <!--reserved for overlay-->
+ <string-array name="telephony_signal_strength_g_sim2">
+ <item>array/signal_strength_g_normal_sim2</item>
+ <item>array/signal_strength_g_fully_sim2</item>
+ </string-array>
+ <string-array name="telephony_signal_strength_g_roaming_sim2">
+ <item>array/signal_strength_g_normal_roaming_sim2</item>
+ <item>array/signal_strength_g_fully_roaming_sim2</item>
+ </string-array>
+ <string-array name="telephony_signal_strength_e_sim2">
+ <item>array/signal_strength_e_normal_sim2</item>
+ <item>array/signal_strength_e_fully_sim2</item>
+ </string-array>
+ <string-array name="telephony_signal_strength_e_roaming_sim2">
+ <item>array/signal_strength_e_normal_roaming_sim2</item>
+ <item>array/signal_strength_e_fully_roaming_sim2</item>
+ </string-array>
+ <string-array name="telephony_signal_strength_3g_sim2">
+ <item>array/signal_strength_3g_normal_sim2</item>
+ <item>array/signal_strength_3g_fully_sim2</item>
+ </string-array>
+ <string-array name="telephony_signal_strength_3g_roaming_sim2">
+ <item>array/signal_strength_3g_normal_roaming_sim2</item>
+ <item>array/signal_strength_3g_fully_roaming_sim2</item>
+ </string-array>
+ <string-array name="telephony_signal_strength_4g_sim2">
+ <item>array/signal_strength_4g_normal_sim2</item>
+ <item>array/signal_strength_4g_fully_sim2</item>
+ </string-array>
+ <string-array name="telephony_signal_strength_4g_roaming_sim2">
+ <item>array/signal_strength_4g_normal_roaming_sim2</item>
+ <item>array/signal_strength_4g_fully_roaming_sim2</item>
+ </string-array>
+ <string-array name="telephony_signal_strength_h_sim2">
+ <item>array/signal_strength_h_normal_sim2</item>
+ <item>array/signal_strength_h_fully_sim2</item>
+ </string-array>
+ <string-array name="telephony_signal_strength_h_roaming_sim2">
+ <item>array/signal_strength_h_normal_roaming_sim2</item>
+ <item>array/signal_strength_h_fully_roaming_sim2</item>
+ </string-array>
+ <string-array name="telephony_signal_strength_hp_sim2">
+ <item>array/signal_strength_hp_normal_sim2</item>
+ <item>array/signal_strength_hp_fully_sim2</item>
+ </string-array>
+ <string-array name="telephony_signal_strength_hp_roaming_sim2">
+ <item>array/signal_strength_hp_normal_roaming_sim2</item>
+ <item>array/signal_strength_hp_fully_roaming_sim2</item>
+ </string-array>
+ <string-array name="telephony_signal_strength_1x_sim2">
+ <item>array/signal_strength_1x_normal_sim2</item>
+ <item>array/signal_strength_1x_fully_sim2</item>
+ </string-array>
+ <string-array name="telephony_signal_strength_1x_roaming_sim2">
+ <item>array/signal_strength_1x_normal_roaming_sim2</item>
+ <item>array/signal_strength_1x_fully_roaming_sim2</item>
+ </string-array>
+ <string-array name="telephony_signal_strength_cdma_sim2">
+ <item>array/signal_strength_cdma_normal_sim2</item>
+ <item>array/signal_strength_cdma_fully_sim2</item>
+ </string-array>
+ <string-array name="telephony_signal_strength_cdma_roaming_sim2">
+ <item>array/signal_strength_cdma_normal_roaming_sim2</item>
+ <item>array/signal_strength_cdma_fully_roaming_sim2</item>
+ </string-array>
+ <string-array name="telephony_signal_strength_umts_sim2">
+ <item>array/signal_strength_umts_normal_sim2</item>
+ <item>array/signal_strength_umts_fully_sim2</item>
+ </string-array>
+ <string-array name="telephony_signal_strength_umts_roaming_sim2">
+ <item>array/signal_strength_umts_normal_roaming_sim2</item>
+ <item>array/signal_strength_umts_fully_roaming_sim2</item>
+ </string-array>
+ <!--reserved for overlay-->
+ <string-array name="signal_strength_g_normal_sim2">
+ </string-array>
+ <string-array name="signal_strength_g_fully_sim2">
+ </string-array>
+ <string-array name="signal_strength_g_normal_roaming_sim2">
+ </string-array>
+ <string-array name="signal_strength_g_fully_roaming_sim2">
+ </string-array>
+ <string-array name="signal_strength_e_normal_sim2">
+ </string-array>
+ <string-array name="signal_strength_e_fully_sim2">
+ </string-array>
+ <string-array name="signal_strength_e_normal_roaming_sim2">
+ </string-array>
+ <string-array name="signal_strength_e_fully_roaming_sim2">
+ </string-array>
+ <string-array name="signal_strength_3g_normal_sim2">
+ </string-array>
+ <string-array name="signal_strength_3g_fully_sim2">
+ </string-array>
+ <string-array name="signal_strength_3g_normal_roaming_sim2">
+ </string-array>
+ <string-array name="signal_strength_3g_fully_roaming_sim2">
+ </string-array>
+ <string-array name="signal_strength_4g_normal_sim2">
+ </string-array>
+ <string-array name="signal_strength_4g_fully_sim2">
+ </string-array>
+ <string-array name="signal_strength_4g_normal_roaming_sim2">
+ </string-array>
+ <string-array name="signal_strength_4g_fully_roaming_sim2">
+ </string-array>
+ <string-array name="signal_strength_h_normal_sim2">
+ </string-array>
+ <string-array name="signal_strength_h_fully_sim2">
+ </string-array>
+ <string-array name="signal_strength_h_normal_roaming_sim2">
+ </string-array>
+ <string-array name="signal_strength_h_fully_roaming_sim2">
+ </string-array>
+ <string-array name="signal_strength_hp_normal_sim2">
+ </string-array>
+ <string-array name="signal_strength_hp_fully_sim2">
+ </string-array>
+ <string-array name="signal_strength_hp_normal_roaming_sim2">
+ </string-array>
+ <string-array name="signal_strength_hp_fully_roaming_sim2">
+ </string-array>
+ <string-array name="signal_strength_1x_normal_sim2">
+ </string-array>
+ <string-array name="signal_strength_1x_fully_sim2">
+ </string-array>
+ <string-array name="signal_strength_1x_normal_roaming_sim2">
+ </string-array>
+ <string-array name="signal_strength_1x_fully_roaming_sim2">
+ </string-array>
+ <string-array name="signal_strength_cdma_normal_sim2">
+ </string-array>
+ <string-array name="signal_strength_cdma_fully_sim2">
+ </string-array>
+ <string-array name="signal_strength_cdma_normal_roaming_sim2">
+ </string-array>
+ <string-array name="signal_strength_cdma_fully_roaming_sim2">
+ </string-array>
+ <string-array name="signal_strength_umts_normal_sim2">
+ </string-array>
+ <string-array name="signal_strength_umts_fully_sim2">
+ </string-array>
+ <string-array name="signal_strength_umts_normal_roaming_sim2">
+ </string-array>
+ <string-array name="signal_strength_umts_fully_roaming_sim2">
+ </string-array>
+
+ <string-array name="telephony_signal_strength_g_sim3">
+ <item>array/signal_strength_g_normal_sim3</item>
+ <item>array/signal_strength_g_fully_sim3</item>
+ </string-array>
+ <string-array name="telephony_signal_strength_g_roaming_sim3">
+ <item>array/signal_strength_g_normal_roaming_sim3</item>
+ <item>array/signal_strength_g_fully_roaming_sim3</item>
+ </string-array>
+ <string-array name="telephony_signal_strength_e_sim3">
+ <item>array/signal_strength_e_normal_sim3</item>
+ <item>array/signal_strength_e_fully_sim3</item>
+ </string-array>
+ <string-array name="telephony_signal_strength_e_roaming_sim3">
+ <item>array/signal_strength_e_normal_roaming_sim3</item>
+ <item>array/signal_strength_e_fully_roaming_sim3</item>
+ </string-array>
+ <string-array name="telephony_signal_strength_3g_sim3">
+ <item>array/signal_strength_3g_normal_sim3</item>
+ <item>array/signal_strength_3g_fully_sim3</item>
+ </string-array>
+ <string-array name="telephony_signal_strength_3g_roaming_sim3">
+ <item>array/signal_strength_3g_normal_roaming_sim3</item>
+ <item>array/signal_strength_3g_fully_roaming_sim3</item>
+ </string-array>
+ <string-array name="telephony_signal_strength_4g_sim3">
+ <item>array/signal_strength_4g_normal_sim3</item>
+ <item>array/signal_strength_4g_fully_sim3</item>
+ </string-array>
+ <string-array name="telephony_signal_strength_4g_roaming_sim3">
+ <item>array/signal_strength_4g_normal_roaming_sim3</item>
+ <item>array/signal_strength_4g_fully_roaming_sim3</item>
+ </string-array>
+ <string-array name="telephony_signal_strength_h_sim3">
+ <item>array/signal_strength_h_normal_sim3</item>
+ <item>array/signal_strength_h_fully_sim3</item>
+ </string-array>
+ <string-array name="telephony_signal_strength_h_roaming_sim3">
+ <item>array/signal_strength_h_normal_roaming_sim3</item>
+ <item>array/signal_strength_h_fully_roaming_sim3</item>
+ </string-array>
+ <string-array name="telephony_signal_strength_hp_sim3">
+ <item>array/signal_strength_hp_normal_sim3</item>
+ <item>array/signal_strength_hp_fully_sim3</item>
+ </string-array>
+ <string-array name="telephony_signal_strength_hp_roaming_sim3">
+ <item>array/signal_strength_hp_normal_roaming_sim3</item>
+ <item>array/signal_strength_hp_fully_roaming_sim3</item>
+ </string-array>
+ <string-array name="telephony_signal_strength_1x_sim3">
+ <item>array/signal_strength_1x_normal_sim3</item>
+ <item>array/signal_strength_1x_fully_sim3</item>
+ </string-array>
+ <string-array name="telephony_signal_strength_1x_roaming_sim3">
+ <item>array/signal_strength_1x_normal_roaming_sim3</item>
+ <item>array/signal_strength_1x_fully_roaming_sim3</item>
+ </string-array>
+ <string-array name="telephony_signal_strength_cdma_sim3">
+ <item>array/signal_strength_cdma_normal_sim3</item>
+ <item>array/signal_strength_cdma_fully_sim3</item>
+ </string-array>
+ <string-array name="telephony_signal_strength_cdma_roaming_sim3">
+ <item>array/signal_strength_cdma_normal_roaming_sim3</item>
+ <item>array/signal_strength_cdma_fully_roaming_sim3</item>
+ </string-array>
+ <string-array name="telephony_signal_strength_umts_sim3">
+ <item>array/signal_strength_umts_normal_sim3</item>
+ <item>array/signal_strength_umts_fully_sim3</item>
+ </string-array>
+ <string-array name="telephony_signal_strength_umts_roaming_sim3">
+ <item>array/signal_strength_umts_normal_roaming_sim3</item>
+ <item>array/signal_strength_umts_fully_roaming_sim3</item>
+ </string-array>
+ <!--reserved for overlay-->
+ <string-array name="signal_strength_g_normal_sim3">
+ </string-array>
+ <string-array name="signal_strength_g_fully_sim3">
+ </string-array>
+ <string-array name="signal_strength_g_normal_roaming_sim3">
+ </string-array>
+ <string-array name="signal_strength_g_fully_roaming_sim3">
+ </string-array>
+ <string-array name="signal_strength_e_normal_sim3">
+ </string-array>
+ <string-array name="signal_strength_e_fully_sim3">
+ </string-array>
+ <string-array name="signal_strength_e_normal_roaming_sim3">
+ </string-array>
+ <string-array name="signal_strength_e_fully_roaming_sim3">
+ </string-array>
+ <string-array name="signal_strength_3g_normal_sim3">
+ </string-array>
+ <string-array name="signal_strength_3g_fully_sim3">
+ </string-array>
+ <string-array name="signal_strength_3g_normal_roaming_sim3">
+ </string-array>
+ <string-array name="signal_strength_3g_fully_roaming_sim3">
+ </string-array>
+ <string-array name="signal_strength_4g_normal_sim3">
+ </string-array>
+ <string-array name="signal_strength_4g_fully_sim3">
+ </string-array>
+ <string-array name="signal_strength_4g_normal_roaming_sim3">
+ </string-array>
+ <string-array name="signal_strength_4g_fully_roaming_sim3">
+ </string-array>
+ <string-array name="signal_strength_h_normal_sim3">
+ </string-array>
+ <string-array name="signal_strength_h_fully_sim3">
+ </string-array>
+ <string-array name="signal_strength_h_normal_roaming_sim3">
+ </string-array>
+ <string-array name="signal_strength_h_fully_roaming_sim3">
+ </string-array>
+ <string-array name="signal_strength_hp_normal_sim3">
+ </string-array>
+ <string-array name="signal_strength_hp_fully_sim3">
+ </string-array>
+ <string-array name="signal_strength_hp_normal_roaming_sim3">
+ </string-array>
+ <string-array name="signal_strength_hp_fully_roaming_sim3">
+ </string-array>
+ <string-array name="signal_strength_1x_normal_sim3">
+ </string-array>
+ <string-array name="signal_strength_1x_fully_sim3">
+ </string-array>
+ <string-array name="signal_strength_1x_normal_roaming_sim3">
+ </string-array>
+ <string-array name="signal_strength_1x_fully_roaming_sim3">
+ </string-array>
+ <string-array name="signal_strength_cdma_normal_sim3">
+ </string-array>
+ <string-array name="signal_strength_cdma_fully_sim3">
+ </string-array>
+ <string-array name="signal_strength_cdma_normal_roaming_sim3">
+ </string-array>
+ <string-array name="signal_strength_cdma_fully_roaming_sim3">
+ </string-array>
+ <string-array name="signal_strength_umts_normal_sim3">
+ </string-array>
+ <string-array name="signal_strength_umts_fully_sim3">
+ </string-array>
+ <string-array name="signal_strength_umts_normal_roaming_sim3">
+ </string-array>
+ <string-array name="signal_strength_umts_fully_roaming_sim3">
+ </string-array>
+
+ <!--convert stacked icons to single icons-->
+ <array name="stacked_signal_icons">
+ <item>@drawable/stat_sys_signal_0_3g</item>
+ <item>@drawable/stat_sys_signal_0_4g</item>
+ <item>@drawable/stat_sys_signal_1_3g</item>
+ <item>@drawable/stat_sys_signal_1_4g</item>
+ <item>@drawable/stat_sys_signal_2_3g</item>
+ <item>@drawable/stat_sys_signal_2_4g</item>
+ <item>@drawable/stat_sys_signal_3_3g</item>
+ <item>@drawable/stat_sys_signal_3_4g</item>
+ <item>@drawable/stat_sys_signal_4_3g</item>
+ <item>@drawable/stat_sys_signal_4_4g</item>
+ <item>@drawable/stat_sys_signal_0_3g_fully</item>
+ <item>@drawable/stat_sys_signal_0_4g_fully</item>
+ <item>@drawable/stat_sys_signal_1_3g_fully</item>
+ <item>@drawable/stat_sys_signal_1_4g_fully</item>
+ <item>@drawable/stat_sys_signal_2_3g_fully</item>
+ <item>@drawable/stat_sys_signal_2_4g_fully</item>
+ <item>@drawable/stat_sys_signal_3_3g_fully</item>
+ <item>@drawable/stat_sys_signal_3_4g_fully</item>
+ <item>@drawable/stat_sys_signal_4_3g_fully</item>
+ <item>@drawable/stat_sys_signal_4_4g_fully</item>
+ </array>
+
+ <array name="single_signal_icons">
+ <item>@drawable/stat_sys_signal_0_3g_default</item>
+ <item>@drawable/stat_sys_signal_0_4g_default</item>
+ <item>@drawable/stat_sys_signal_1_3g_default</item>
+ <item>@drawable/stat_sys_signal_1_4g_default</item>
+ <item>@drawable/stat_sys_signal_2_3g_default</item>
+ <item>@drawable/stat_sys_signal_2_4g_default</item>
+ <item>@drawable/stat_sys_signal_3_3g_default</item>
+ <item>@drawable/stat_sys_signal_3_4g_default</item>
+ <item>@drawable/stat_sys_signal_4_3g_default</item>
+ <item>@drawable/stat_sys_signal_4_4g_default</item>
+ <item>@drawable/stat_sys_signal_0_3g_default_fully</item>
+ <item>@drawable/stat_sys_signal_0_4g_default_fully</item>
+ <item>@drawable/stat_sys_signal_1_3g_default_fully</item>
+ <item>@drawable/stat_sys_signal_1_4g_default_fully</item>
+ <item>@drawable/stat_sys_signal_2_3g_default_fully</item>
+ <item>@drawable/stat_sys_signal_2_4g_default_fully</item>
+ <item>@drawable/stat_sys_signal_3_3g_default_fully</item>
+ <item>@drawable/stat_sys_signal_3_4g_default_fully</item>
+ <item>@drawable/stat_sys_signal_4_3g_default_fully</item>
+ <item>@drawable/stat_sys_signal_4_4g_default_fully</item>
+ </array>
</resources>
diff --git a/packages/SystemUI/res/values/cm_arrays.xml b/packages/SystemUI/res/values/cm_arrays.xml
new file mode 100644
index 0000000..a9e3654
--- /dev/null
+++ b/packages/SystemUI/res/values/cm_arrays.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2012-2014 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.
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <array name="batterymeter_inverted_bolt_points" translatable="false">
+ <item>743</item><item>73</item>
+ <item>743</item><item>292</item>
+ <item>442</item><item>201</item>
+ <item>442</item><item>400</item>
+ <item>0</item><item>20</item>
+ <item>369</item><item>157</item>
+ <item>369</item><item>0</item>
+ </array>
+</resources>
diff --git a/packages/SystemUI/res/values/cm_attrs.xml b/packages/SystemUI/res/values/cm_attrs.xml
new file mode 100644
index 0000000..8e88e67
--- /dev/null
+++ b/packages/SystemUI/res/values/cm_attrs.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 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.
+-->
+
+<resources>
+ <declare-styleable name="QuickSettingsRow">
+ <attr name="table" format="enum">
+ <enum name="system" value="0"/>
+ <enum name="global" value="1"/>
+ <enum name="secure" value="2"/>
+
+ <enum name="cm_system" value="3"/>
+ <enum name="cm_global" value="4"/>
+ <enum name="cm_secure" value="5"/>
+ </attr>
+
+ <attr name="android:key"/>
+ <attr name="android:title" />
+ </declare-styleable>
+</resources>
+
diff --git a/packages/SystemUI/res/values/cm_colors.xml b/packages/SystemUI/res/values/cm_colors.xml
new file mode 100644
index 0000000..abca9bb
--- /dev/null
+++ b/packages/SystemUI/res/values/cm_colors.xml
@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2014 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.
+-->
+<resources>
+
+ <!-- Color for the "No recent apps" text in the recent apps list. -->
+ <color name="no_recent_apps">#bebebe</color>
+
+ <!-- Colors for the system bars -->
+ <color name="status_bar_background_opaque">@color/system_bar_background_opaque</color>
+ <color name="status_bar_background_semi_transparent">
+ @color/system_bar_background_semi_transparent
+ </color>
+ <color name="status_bar_background_transparent">@color/system_bar_background_transparent</color>
+ <color name="navigation_bar_background_opaque">@color/system_bar_background_opaque</color>
+ <color name="navigation_bar_background_semi_transparent">
+ @color/system_bar_background_semi_transparent
+ </color>
+ <color name="navigation_bar_background_transparent">
+ @color/system_bar_background_transparent
+ </color>
+
+ <!-- Expanded Status Bar Weather Text Colors -->
+ <color name="status_bar_temperature_text_color">#FFFFFFFF</color>
+ <color name="status_bar_temperature_location_text_color">#FFFFFFFF</color>
+
+ <!-- tint of the Visualizer tile -->
+ <color name="visualizer_fill_color">#96FFFFFF</color>
+
+ <!-- Background of the volume panel. See also: volume_dialog_background -->
+ <color name="volume_panel_background_color">@color/system_secondary_color</color>
+
+ <!-- Battery base color -->
+ <color name="batterymeter_base_color">#FFFFFFFF</color>
+
+ <!-- Color for notification icons -->
+ <color name="notification_icon_color">#FFFFFFFF</color>
+
+ <!-- Navigation button ripple color -->
+ <color name="navbutton_ripple_color">#FFFFFFFF</color>
+
+ <!-- Expanded Status Bar Weather Text Colors -->
+ <color name="status_bar_temperature_text_color">#FFFFFFFF</color>
+ <color name="status_bar_temperature_location_text_color">#FFFFFFFF</color>
+
+ <!-- Expanded Status Bar Alarm Status Text Color -->
+ <color name="status_bar_alarm_status_text_color">#64ffffff</color>
+
+ <!-- Expanded Status Bar Battery Level Text Color -->
+ <color name="status_bar_battery_level_text_color">#ffffff</color>
+
+ <!-- QS Toast Text color -->
+ <color name="quick_settings_toast_color">#ffbe1b</color>
+
+ <!-- SystemUI Tuner Icon Tint Color -->
+ <color name="tuner_icon_tint">#4dffffff</color>
+</resources>
diff --git a/packages/SystemUI/res/values/cm_dimens.xml b/packages/SystemUI/res/values/cm_dimens.xml
new file mode 100644
index 0000000..aade9f0
--- /dev/null
+++ b/packages/SystemUI/res/values/cm_dimens.xml
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2014 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.
+-->
+<resources>
+
+ <dimen name="detail_radio_group_padding_left">16dp</dimen>
+ <dimen name="detail_radio_group_padding">8dp</dimen>
+
+ <!-- Themes: radius of the corners of the notification dropshadow
+ See also: notification_material_rounded_rect_radius
+ -->
+ <dimen name="notification_material_shadow_rounded_rect_radius">0dp</dimen>
+
+ <dimen name="zen_mode_panel_radius">@dimen/notification_material_rounded_rect_radius</dimen>
+
+ <dimen name="status_bar_expanded_header_elevation">4dp</dimen>
+
+ <dimen name="volume_panel_z">4dp</dimen>
+
+ <!-- Side padding for the status bar header -->
+ <dimen name="notification_header_side_padding">@dimen/notification_side_padding</dimen>
+
+ <!-- Side padding for the Quick Settings panel -->
+ <dimen name="qs_panel_side_padding">@dimen/notification_side_padding</dimen>
+
+ <!-- Padding end for weather text -->
+ <dimen name="status_bar_weather_padding_end">16dp</dimen>
+
+ <dimen name="lockscreen_icon_side_padding">10dp</dimen>
+ <dimen name="lockscreen_icon_size">35dp</dimen>
+ <dimen name="phone_side_padding">10dp</dimen>
+ <dimen name="phone_bottom_padding">40dp</dimen>
+ <dimen name="phone_width">320dp</dimen>
+ <dimen name="phone_height">420dp</dimen>
+
+ <dimen name="qs_detail_item_height_twoline">72dp</dimen>
+
+ <dimen name="detail_exterior_padding">8dp</dimen>
+</resources>
diff --git a/packages/SystemUI/res/values/cm_strings.xml b/packages/SystemUI/res/values/cm_strings.xml
new file mode 100644
index 0000000..0750700
--- /dev/null
+++ b/packages/SystemUI/res/values/cm_strings.xml
@@ -0,0 +1,91 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ * Copyright (c) 2015, 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.
+ */
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+ <!-- Weather string format in expanded statusbar header -->
+ <string name="status_bar_expanded_header_weather_format"><xliff:g id="temp">%1$s</xliff:g> - <xliff:g id="condition">%2$s</xliff:g></string>
+
+ <!-- Text to use when the number in a notification info is too large
+ (greater than status_bar_notification_info_maxnum, defined in
+ values/config.xml) and must be truncated.
+ [CHAR LIMIT=4] -->
+ <string name="status_bar_notification_info_overflow" translatable="false">\u221E</string>
+
+ <!-- Content description of the superuser tile -->
+ <string name="accessibility_su_active">Superuser session active</string>
+
+ <!-- Strings for lockscreen shortcut hints -->
+ <string name="left_shortcut_hint">Swipe right for %1$s</string>
+ <string name="right_shortcut_hint">Swipe left for %1$s</string>
+
+ <string name="lockscreen_message">Tap an icon on the left or right to reassign a lock screen shortcut.</string>
+ <string name="lockscreen_default_target">Default</string>
+ <string name="select_application">Select application</string>
+ <string name="lockscreen_choose_action_title">Choose action</string>
+ <string name="lockscreen_none_target">None</string>
+
+ <!-- Dialog title for navigation bar button selection -->
+ <string name="navbar_dialog_title">Choose action to assign</string>
+ <string name="navbar_home_button">Home button</string>
+ <string name="navbar_recent_button">Recent button</string>
+ <string name="navbar_search_button">Search button</string>
+ <string name="navbar_back_button">Back button</string>
+ <string name="navbar_empty_button">Empty button</string>
+ <string name="navbar_menu_conditional_button">Menu (autoHide) button</string>
+ <string name="navbar_menu_always_button">Menu (alwaysShow) button</string>
+ <string name="navbar_menu_big_button">Menu button</string>
+ <string name="accessibility_dpad_left">Cursor left</string>
+ <string name="accessibility_dpad_right">Cursor right</string>
+
+ <!-- Development shortcuts -->
+ <!-- Title shown in recents popup for removing an application from the list -->
+ <string name="status_bar_recent_remove_item_title">Remove from list</string>
+ <!-- Title shown in recents popup for inspecting an application's properties -->
+ <string name="status_bar_recent_inspect_item_title">App info</string>
+ <!-- Title shown in recents popup for wiping application's data -->
+ <string name="advanced_dev_option_wipe_app">Wipe app data</string>
+ <!-- Title shown in recents popup for force stopping the application -->
+ <string name="advanced_dev_option_force_stop">Force stop</string>
+ <!-- Title shown in recents popup for uninstalling the application -->
+ <string name="advanced_dev_option_uninstall">Uninstall</string>
+
+ <!-- Content description of the light brightness slider (not shown on the screen). [CHAR LIMIT=NONE] -->
+ <string name="accessibility_notification_brightness">Light brightness</string>
+
+ <!-- Lights settings, LED notification -->
+ <string name="led_notification_title">Light settings</string>
+ <string name="led_notification_text">LED light enabled by settings</string>
+
+ <string name="qs_tile_edit_header_instruction">Press and hold tiles to rearrange</string>
+ <string name="quick_settings_edit_label">Edit tiles</string>
+ <string name="quick_settings_cannot_delete_edit_tile">Cannot delete the Edit tile</string>
+ <string name="qs_tiles_reset_confirmation">Reset quick settings tiles to default configuration?</string>
+ <string name="quick_settings_tile_reset_to_default">Reset to default layout</string>
+ <string name="quick_settings_title_header">Header</string>
+ <string name="quick_settings_title_tiles">Tiles</string>
+ <string name="quick_settings_title_show_weather">Show weather</string>
+ <string name="quick_settings_title_enlarge_first_row">Enlarge first row</string>
+
+ <!-- Screen pinning dialog description (for devices without navbar) -->
+ <string name="screen_pinning_description_no_navbar">This keeps it in view until you unpin. Touch and hold the Back button to unpin.</string>
+
+ <string name="quick_settings_custom_tile_detail_title">Custom Tile</string>
+ <string name="quick_settings_remove">Remove tile</string>
+</resources>
diff --git a/packages/SystemUI/res/values/cm_styles.xml b/packages/SystemUI/res/values/cm_styles.xml
new file mode 100644
index 0000000..8caa89d
--- /dev/null
+++ b/packages/SystemUI/res/values/cm_styles.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2015 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.
+-->
+<resources>
+
+ <style name="SettingRow">
+ <item name="android:layout_width">match_parent</item>
+ <item name="android:layout_height">48dp</item>
+ <item name="android:paddingLeft">16dp</item>
+ <item name="android:paddingRight">16dp</item>
+ <item name="android:background">?android:attr/selectableItemBackground</item>
+ <item name="android:clickable">true</item>
+ </style>
+
+ <style name="TextAppearance.StatusBar.Expanded.WeatherTemp">
+ <item name="android:textSize">12sp</item>
+ <item name="android:textStyle">normal</item>
+ <item name="android:textColor">@color/status_bar_temperature_text_color</item>
+ </style>
+
+ <style name="TextAppearance.StatusBar.Expanded.WeatherLocation">
+ <item name="android:textSize">12sp</item>
+ <item name="android:textStyle">normal</item>
+ <item name="android:textColor">@color/status_bar_temperature_location_text_color</item>
+ </style>
+
+ <style name="TextAppearance.QS.DetailItemSub">
+ <item name="android:textSize">@dimen/qs_detail_item_secondary_text_size</item>
+ </style>
+
+</resources>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 0dcbe88..f116f05 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -17,7 +17,7 @@
*/
-->
<resources>
- <drawable name="notification_number_text_color">#ffffffff</drawable>
+ <drawable name="notification_number_text_color">#ff000000</drawable>
<drawable name="ticker_background_color">#ff1d1d1d</drawable>
<drawable name="system_bar_background">@color/system_bar_background_opaque</drawable>
<color name="system_bar_background_opaque">#ff000000</color>
@@ -35,6 +35,7 @@
<color name="batterymeter_bolt_color">#FFFFFFFF</color>
<color name="qs_batterymeter_frame_color">#FF404040</color>
<color name="system_primary_color">#ff263238</color><!-- blue grey 900 -->
+ <color name="system_primary_color_translucent">#90aaaaaa</color><!-- blue grey 900 -->
<color name="system_secondary_color">#ff384248</color>
<color name="system_accent_color">#ff80CBC4</color><!-- deep teal 200 -->
<color name="system_warning_color">#fff4511e</color><!-- deep orange 600 -->
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 5d06768..5bac1d5 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -119,7 +119,7 @@
<!-- The default tiles to display in QuickSettings -->
<string name="quick_settings_tiles_default" translatable="false">
- wifi,bt,inversion,dnd,cell,airplane,rotation,flashlight,location,cast,hotspot
+ wifi,bt,cell,airplane,rotation,flashlight,location,edit,cast,hotspot,inversion,dnd
</string>
<!-- The tiles to display in QuickSettings -->
@@ -138,6 +138,35 @@
<!-- Should "4G" be shown instead of "LTE" when the network is NETWORK_TYPE_LTE? -->
<bool name="config_show4GForLTE">true</bool>
+ <!-- Whether or not we also show rsrp level for LTE. -->
+ <bool name="config_showRsrpSignalLevelforLTE">false</bool>
+
+ <!-- Whether or not we show carrier label in notification panel. -->
+ <bool name="config_showCarrierLabel">false</bool>
+
+ <!-- Whether or not we also show wifi activity in status bar. -->
+ <bool name="config_showWifiActivity">false</bool>
+
+ <!-- Show indicator for Wifi on but not connected. -->
+ <bool name="config_showWifiIndicatorWhenEnabled">false</bool>
+
+ <!-- style of status bar:
+ 0: Default Android style
+ 1: Show data activity with data type at the left side of
+ signal icon, and signal icon may be two icons
+ stacked, the upper one is to show 3G, and the lower one
+ is to show 2G.
+ 2: Do not show data activity besides signal icon, instead,
+ it shows data activity within signal view.
+ 3: Show data activity with data type at the left side
+ of signal icon, and do not show two stacked icon on
+ one slot.
+ -->
+ <integer name="status_bar_style">0</integer>
+
+ <!-- Control whether status bar should fetch mobile signal icons from xml file dynamically -->
+ <bool name="config_read_icons_from_xml">false</bool>
+
<!-- milliseconds before the heads up notification auto-dismisses. -->
<integer name="heads_up_notification_decay">5000</integer>
@@ -239,6 +268,9 @@
<!-- Doze: check proximity sensor before pulsing? -->
<bool name="doze_proximity_check_before_pulse">true</bool>
+ <!-- Doze: check proximity sensor before pulsing from intent? -->
+ <bool name="doze_proximity_check_before_pulse_intent">false</bool>
+
<!-- Doze: should notifications be used as a pulse signal? -->
<bool name="doze_pulse_on_notifications">true</bool>
@@ -260,6 +292,12 @@
<!-- Doze: pulse parameter - how long does it take to fade in after a pickup? -->
<integer name="doze_pulse_duration_in_pickup">300</integer>
+ <!-- Doze: pulse parameter - how long does it take to fade in after an intent? -->
+ <integer name="doze_pulse_duration_in_intent">300</integer>
+
+ <!-- Doze: pulse parameter - delay to wait for the screen to wake up after an intent -->
+ <integer name="doze_pulse_delay_in_intent">200</integer>
+
<!-- Doze: pulse parameter - once faded in, how long does it stay visible? -->
<integer name="doze_pulse_duration_visible">3000</integer>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index dc9c9fd..5d5522e 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -341,6 +341,9 @@
<!-- Content description of the data connection type 4G for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_data_connection_4g">4G</string>
+ <!-- Content description of the data connection type 4G for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
+ <string name="accessibility_data_connection_4g_plus">4G+</string>
+
<!-- Content description of the data connection type LTE for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_data_connection_lte">LTE</string>
diff --git a/packages/SystemUI/res/values/vpi__attrs.xml b/packages/SystemUI/res/values/vpi__attrs.xml
new file mode 100644
index 0000000..911df54
--- /dev/null
+++ b/packages/SystemUI/res/values/vpi__attrs.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 Jake Wharton
+ Copyright (C) 2011 Patrik Åkerfeldt
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<resources>
+ <attr name="centered" format="boolean" />
+ <attr name="selectedColor" format="color" />
+ <attr name="strokeWidth" format="dimension" />
+ <attr name="unselectedColor" format="color" />
+
+ <declare-styleable name="CirclePageIndicator">
+ <!-- Whether or not the indicators should be centered. -->
+ <attr name="centered" />
+ <!-- Color of the filled circle that represents the current page. -->
+ <attr name="indicatorFillColor" format="color" />
+ <!-- Color of the filled circles that represents pages. -->
+ <attr name="pageColor" format="color" />
+ <!-- Orientation of the indicator. -->
+ <attr name="android:orientation"/>
+ <!-- Radius of the circles. This is also the spacing between circles. -->
+ <attr name="radius" format="dimension" />
+ <!-- Whether or not the selected indicator snaps to the circles. -->
+ <attr name="snap" format="boolean" />
+ <!-- Color of the open circles. -->
+ <attr name="strokeColor" format="color" />
+ <!-- Width of the stroke used to draw the circles. -->
+ <attr name="strokeWidth" />
+ <!-- View background -->
+ <attr name="android:background"/>
+ </declare-styleable>
+</resources>
diff --git a/packages/SystemUI/res/values/vpi__defaults.xml b/packages/SystemUI/res/values/vpi__defaults.xml
new file mode 100644
index 0000000..7aabee4
--- /dev/null
+++ b/packages/SystemUI/res/values/vpi__defaults.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 Jake Wharton
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<resources>
+ <bool name="default_circle_indicator_centered">true</bool>
+ <color name="default_circle_indicator_fill_color">#ffFFFFFF</color>
+ <color name="default_circle_indicator_page_color">#ffcccccc</color>
+ <integer name="default_circle_indicator_orientation">0</integer>
+ <dimen name="default_circle_indicator_radius">3dp</dimen>
+ <bool name="default_circle_indicator_snap">false</bool>
+ <color name="default_circle_indicator_stroke_color">#ffcccccc</color>
+ <dimen name="default_circle_indicator_stroke_width">0dp</dimen>
+</resources>
diff --git a/packages/SystemUI/src/com/android/systemui/BatteryLevelTextView.java b/packages/SystemUI/src/com/android/systemui/BatteryLevelTextView.java
new file mode 100644
index 0000000..4717a0b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/BatteryLevelTextView.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2014 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 com.android.systemui;
+
+import com.android.systemui.statusbar.policy.BatteryController;
+
+import android.content.Context;
+import android.content.res.Configuration;
+import android.util.AttributeSet;
+import android.util.TypedValue;
+import android.widget.TextView;
+
+import java.text.NumberFormat;
+
+public class BatteryLevelTextView extends TextView implements
+ BatteryController.BatteryStateChangeCallback{
+ private BatteryController mBatteryController;
+ private boolean mBatteryCharging;
+ private boolean mForceShow;
+ private boolean mAttached;
+ private int mRequestedVisibility;
+ private int mStyle;
+ private int mPercentMode;
+
+ public BatteryLevelTextView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ mRequestedVisibility = getVisibility();
+ }
+
+ public void setForceShown(boolean forceShow) {
+ mForceShow = forceShow;
+ updateVisibility();
+ }
+
+ public void setBatteryController(BatteryController batteryController) {
+ mBatteryController = batteryController;
+ if (mAttached) {
+ mBatteryController.addStateChangedCallback(this);
+ }
+ }
+
+ @Override
+ public void setVisibility(int visibility) {
+ mRequestedVisibility = visibility;
+ updateVisibility();
+ }
+
+ @Override
+ protected void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+
+ // Respect font size setting.
+ setTextSize(TypedValue.COMPLEX_UNIT_PX,
+ getResources().getDimensionPixelSize(R.dimen.battery_level_text_size));
+ }
+
+ @Override
+ public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) {
+ String percentage = NumberFormat.getPercentInstance().format((double) level / 100.0);
+ setText(percentage);
+ if (mBatteryCharging != charging) {
+ mBatteryCharging = charging;
+ updateVisibility();
+ }
+ }
+
+ @Override
+ public void onPowerSaveChanged() {
+ // Not used
+ }
+
+ @Override
+ public void onBatteryStyleChanged(int style, int percentMode) {
+ mStyle = style;
+ mPercentMode = percentMode;
+ updateVisibility();
+ }
+
+ @Override
+ public void onAttachedToWindow() {
+ super.onAttachedToWindow();
+
+ if (mBatteryController != null) {
+ mBatteryController.addStateChangedCallback(this);
+ }
+
+ mAttached = true;
+ }
+
+ @Override
+ public void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ mAttached = false;
+
+ if (mBatteryController != null) {
+ mBatteryController.removeStateChangedCallback(this);
+ }
+ }
+
+ private void updateVisibility() {
+ boolean showNextPercent = mPercentMode == BatteryController.PERCENTAGE_MODE_OUTSIDE
+ || (mBatteryCharging && mPercentMode == BatteryController.PERCENTAGE_MODE_INSIDE);
+ if (mStyle == BatteryController.STYLE_GONE) {
+ showNextPercent = false;
+ } else if (mStyle == BatteryController.STYLE_TEXT) {
+ showNextPercent = true;
+ }
+
+ if (showNextPercent || mForceShow) {
+ super.setVisibility(mRequestedVisibility);
+ } else {
+ super.setVisibility(GONE);
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
index 95b58e5..41d4aae 100755
--- a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
+++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 The Android Open Source Project
+ * Copyright (C) 2013-14 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.
@@ -16,6 +16,8 @@
package com.android.systemui;
+import com.android.systemui.statusbar.policy.BatteryController;
+
import android.animation.ArgbEvaluator;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -23,30 +25,22 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.Resources;
import android.content.res.TypedArray;
-import android.database.ContentObserver;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
+import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Typeface;
-import android.net.Uri;
import android.os.BatteryManager;
import android.os.Bundle;
-import android.os.Handler;
-import android.provider.Settings;
import android.util.AttributeSet;
import android.view.View;
-import com.android.systemui.statusbar.policy.BatteryController;
-
public class BatteryMeterView extends View implements DemoMode,
BatteryController.BatteryStateChangeCallback {
public static final String TAG = BatteryMeterView.class.getSimpleName();
public static final String ACTION_LEVEL_TEST = "com.android.systemui.BATTERY_LEVEL_TEST";
- public static final String SHOW_PERCENT_SETTING = "status_bar_show_battery_percent";
-
- private static final boolean SINGLE_DIGIT_PERCENT = false;
private static final int FULL = 96;
@@ -54,25 +48,26 @@ public class BatteryMeterView extends View implements DemoMode,
private final int[] mColors;
- private boolean mShowPercent;
+ protected boolean mShowPercent = true;
private float mButtonHeightFraction;
private float mSubpixelSmoothingLeft;
private float mSubpixelSmoothingRight;
- private final Paint mFramePaint, mBatteryPaint, mWarningTextPaint, mTextPaint, mBoltPaint;
- private float mTextHeight, mWarningTextHeight;
- private int mIconTint = Color.WHITE;
+
+ public enum BatteryMeterMode {
+ BATTERY_METER_GONE,
+ BATTERY_METER_ICON_PORTRAIT,
+ BATTERY_METER_ICON_LANDSCAPE,
+ BATTERY_METER_CIRCLE,
+ BATTERY_METER_TEXT
+ }
private int mHeight;
private int mWidth;
private String mWarningString;
private final int mCriticalLevel;
- private int mChargeColor;
- private final float[] mBoltPoints;
- private final Path mBoltPath = new Path();
+ private final int mFrameColor;
- private final RectF mFrame = new RectF();
- private final RectF mButtonFrame = new RectF();
- private final RectF mBoltFrame = new RectF();
+ private boolean mAnimationsEnabled;
private final Path mShapePath = new Path();
private final Path mClipPath = new Path();
@@ -87,8 +82,129 @@ public class BatteryMeterView extends View implements DemoMode,
private int mLightModeBackgroundColor;
private int mLightModeFillColor;
- private BatteryTracker mTracker = new BatteryTracker();
- private final SettingObserver mSettingObserver = new SettingObserver();
+ protected BatteryMeterMode mMeterMode = null;
+
+ protected boolean mAttached;
+
+ private boolean mDemoMode;
+ protected BatteryTracker mDemoTracker = new BatteryTracker();
+ protected BatteryTracker mTracker = new BatteryTracker();
+ private BatteryMeterDrawable mBatteryMeterDrawable;
+ private int mIconTint = Color.WHITE;
+
+ private class BatteryTracker extends BroadcastReceiver {
+ public static final int UNKNOWN_LEVEL = -1;
+
+ // current battery status
+ boolean present = true;
+ int level = UNKNOWN_LEVEL;
+ String percentStr;
+ int plugType;
+ boolean plugged;
+ int health;
+ int status;
+ String technology;
+ int voltage;
+ int temperature;
+ boolean testmode = false;
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ final String action = intent.getAction();
+ if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {
+ if (testmode && ! intent.getBooleanExtra("testmode", false)) return;
+
+ level = (int)(100f
+ * intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0)
+ / intent.getIntExtra(BatteryManager.EXTRA_SCALE, 100));
+
+ present = intent.getBooleanExtra(BatteryManager.EXTRA_PRESENT, true);
+ plugType = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0);
+ plugged = plugType != 0;
+ health = intent.getIntExtra(BatteryManager.EXTRA_HEALTH,
+ BatteryManager.BATTERY_HEALTH_UNKNOWN);
+ status = intent.getIntExtra(BatteryManager.EXTRA_STATUS,
+ BatteryManager.BATTERY_STATUS_UNKNOWN);
+ technology = intent.getStringExtra(BatteryManager.EXTRA_TECHNOLOGY);
+ voltage = intent.getIntExtra(BatteryManager.EXTRA_VOLTAGE, 0);
+ temperature = intent.getIntExtra(BatteryManager.EXTRA_TEMPERATURE, 0);
+
+ setContentDescription(
+ context.getString(R.string.accessibility_battery_level, level));
+ if (mBatteryMeterDrawable != null) {
+ setVisibility(View.VISIBLE);
+ invalidate();
+ }
+ } else if (action.equals(ACTION_LEVEL_TEST)) {
+ testmode = true;
+ post(new Runnable() {
+ int curLevel = 0;
+ int incr = 1;
+ int saveLevel = level;
+ int savePlugged = plugType;
+ Intent dummy = new Intent(Intent.ACTION_BATTERY_CHANGED);
+ @Override
+ public void run() {
+ if (curLevel < 0) {
+ testmode = false;
+ dummy.putExtra("level", saveLevel);
+ dummy.putExtra("plugged", savePlugged);
+ dummy.putExtra("testmode", false);
+ } else {
+ dummy.putExtra("level", curLevel);
+ dummy.putExtra("plugged", incr > 0
+ ? BatteryManager.BATTERY_PLUGGED_AC : 0);
+ dummy.putExtra("testmode", true);
+ }
+ getContext().sendBroadcast(dummy);
+
+ if (!testmode) return;
+
+ curLevel += incr;
+ if (curLevel == 100) {
+ incr *= -1;
+ }
+ postDelayed(this, 200);
+ }
+ });
+ }
+ }
+
+ protected boolean shouldIndicateCharging() {
+ if (status == BatteryManager.BATTERY_STATUS_CHARGING) {
+ return true;
+ }
+ if (plugged) {
+ return status == BatteryManager.BATTERY_STATUS_FULL;
+ }
+ return false;
+ }
+ }
+
+ @Override
+ public void onAttachedToWindow() {
+ super.onAttachedToWindow();
+
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(Intent.ACTION_BATTERY_CHANGED);
+ filter.addAction(ACTION_LEVEL_TEST);
+ final Intent sticky = getContext().registerReceiver(mTracker, filter);
+ if (sticky != null) {
+ // preload the battery level
+ mTracker.onReceive(getContext(), sticky);
+ }
+ mBatteryController.addStateChangedCallback(this);
+ mAttached = true;
+ }
+
+ @Override
+ public void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+
+ mAttached = false;
+ getContext().unregisterReceiver(mTracker);
+ mBatteryController.removeStateChangedCallback(this);
+ }
public BatteryMeterView(Context context) {
this(context, null, 0);
@@ -104,8 +220,8 @@ public class BatteryMeterView extends View implements DemoMode,
final Resources res = context.getResources();
TypedArray atts = context.obtainStyledAttributes(attrs, R.styleable.BatteryMeterView,
defStyle, 0);
- final int frameColor = atts.getColor(R.styleable.BatteryMeterView_frameColor,
- context.getColor(R.color.batterymeter_frame_color));
+ mFrameColor = atts.getColor(R.styleable.BatteryMeterView_frameColor,
+ res.getColor(R.color.batterymeter_frame_color));
TypedArray levels = res.obtainTypedArray(R.array.batterymeter_color_levels);
TypedArray colors = res.obtainTypedArray(R.array.batterymeter_color_values);
@@ -118,9 +234,8 @@ public class BatteryMeterView extends View implements DemoMode,
levels.recycle();
colors.recycle();
atts.recycle();
- updateShowPercent();
mWarningString = context.getString(R.string.battery_meter_very_low_overlay_symbol);
- mCriticalLevel = mContext.getResources().getInteger(
+ mCriticalLevel = getContext().getResources().getInteger(
com.android.internal.R.integer.config_criticalBatteryWarningLevel);
mButtonHeightFraction = context.getResources().getFraction(
R.fraction.battery_button_height_fraction, 1, 1);
@@ -129,66 +244,46 @@ public class BatteryMeterView extends View implements DemoMode,
mSubpixelSmoothingRight = context.getResources().getFraction(
R.fraction.battery_subpixel_smoothing_right, 1, 1);
- mFramePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
- mFramePaint.setColor(frameColor);
- mFramePaint.setDither(true);
- mFramePaint.setStrokeWidth(0);
- mFramePaint.setStyle(Paint.Style.FILL_AND_STROKE);
-
- mBatteryPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
- mBatteryPaint.setDither(true);
- mBatteryPaint.setStrokeWidth(0);
- mBatteryPaint.setStyle(Paint.Style.FILL_AND_STROKE);
-
- mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
- Typeface font = Typeface.create("sans-serif-condensed", Typeface.BOLD);
- mTextPaint.setTypeface(font);
- mTextPaint.setTextAlign(Paint.Align.CENTER);
-
- mWarningTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
- mWarningTextPaint.setColor(mColors[1]);
- font = Typeface.create("sans-serif", Typeface.BOLD);
- mWarningTextPaint.setTypeface(font);
- mWarningTextPaint.setTextAlign(Paint.Align.CENTER);
-
- mChargeColor = context.getColor(R.color.batterymeter_charge_color);
-
- mBoltPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
- mBoltPaint.setColor(context.getColor(R.color.batterymeter_bolt_color));
- mBoltPoints = loadBoltPoints(res);
-
mDarkModeBackgroundColor =
context.getColor(R.color.dark_mode_icon_color_dual_tone_background);
mDarkModeFillColor = context.getColor(R.color.dark_mode_icon_color_dual_tone_fill);
mLightModeBackgroundColor =
context.getColor(R.color.light_mode_icon_color_dual_tone_background);
mLightModeFillColor = context.getColor(R.color.light_mode_icon_color_dual_tone_fill);
- }
- @Override
- public void onAttachedToWindow() {
- super.onAttachedToWindow();
+ setAnimationsEnabled(true);
+ }
- IntentFilter filter = new IntentFilter();
- filter.addAction(Intent.ACTION_BATTERY_CHANGED);
- filter.addAction(ACTION_LEVEL_TEST);
- final Intent sticky = getContext().registerReceiver(mTracker, filter);
- if (sticky != null) {
- // preload the battery level
- mTracker.onReceive(getContext(), sticky);
+ protected BatteryMeterDrawable createBatteryMeterDrawable(BatteryMeterMode mode) {
+ Resources res = mContext.getResources();
+ switch (mode) {
+ case BATTERY_METER_CIRCLE:
+ return new CircleBatteryMeterDrawable(res);
+ case BATTERY_METER_ICON_LANDSCAPE:
+ return new NormalBatteryMeterDrawable(res, true);
+ case BATTERY_METER_TEXT:
+ case BATTERY_METER_GONE:
+ return null;
+ default:
+ return new NormalBatteryMeterDrawable(res, false);
}
- mBatteryController.addStateChangedCallback(this);
- getContext().getContentResolver().registerContentObserver(
- Settings.System.getUriFor(SHOW_PERCENT_SETTING), false, mSettingObserver);
}
@Override
- public void onDetachedFromWindow() {
- super.onDetachedFromWindow();
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ int width = MeasureSpec.getSize(widthMeasureSpec);
+ int height = MeasureSpec.getSize(heightMeasureSpec);
+
+ if (mMeterMode == BatteryMeterMode.BATTERY_METER_CIRCLE) {
+ height += (CircleBatteryMeterDrawable.STROKE_WITH / 3);
+ width = height;
+ } else if (mMeterMode == BatteryMeterMode.BATTERY_METER_TEXT) {
+ onSizeChanged(width, height, 0, 0); // Force a size changed event
+ } else if (mMeterMode.compareTo(BatteryMeterMode.BATTERY_METER_ICON_LANDSCAPE) == 0) {
+ width = (int)(height * 1.2f);
+ }
- getContext().unregisterReceiver(mTracker);
- mBatteryController.removeStateChangedCallback(this);
- getContext().getContentResolver().unregisterContentObserver(mSettingObserver);
+ setMeasuredDimension(width, height);
}
public void setBatteryController(BatteryController batteryController) {
@@ -207,35 +302,85 @@ public class BatteryMeterView extends View implements DemoMode,
invalidate();
}
- private static float[] loadBoltPoints(Resources res) {
- final int[] pts = res.getIntArray(R.array.batterymeter_bolt_points);
- int maxX = 0, maxY = 0;
- for (int i = 0; i < pts.length; i += 2) {
- maxX = Math.max(maxX, pts[i]);
- maxY = Math.max(maxY, pts[i + 1]);
+ public void setAnimationsEnabled(boolean enabled) {
+ if (mAnimationsEnabled != enabled) {
+ mAnimationsEnabled = enabled;
+ setLayerType(mAnimationsEnabled ? LAYER_TYPE_HARDWARE : LAYER_TYPE_NONE, null);
+ invalidate();
}
- final float[] ptsF = new float[pts.length];
- for (int i = 0; i < pts.length; i += 2) {
- ptsF[i] = (float)pts[i] / maxX;
- ptsF[i + 1] = (float)pts[i + 1] / maxY;
+ }
+
+ @Override
+ public void onBatteryStyleChanged(int style, int percentMode) {
+ boolean showInsidePercent = percentMode == BatteryController.PERCENTAGE_MODE_INSIDE;
+ BatteryMeterMode meterMode = BatteryMeterMode.BATTERY_METER_ICON_PORTRAIT;
+
+ switch (style) {
+ case BatteryController.STYLE_CIRCLE:
+ meterMode = BatteryMeterMode.BATTERY_METER_CIRCLE;
+ break;
+ case BatteryController.STYLE_GONE:
+ meterMode = BatteryMeterMode.BATTERY_METER_GONE;
+ showInsidePercent = false;
+ break;
+ case BatteryController.STYLE_ICON_LANDSCAPE:
+ meterMode = BatteryMeterMode.BATTERY_METER_ICON_LANDSCAPE;
+ break;
+ case BatteryController.STYLE_TEXT:
+ meterMode = BatteryMeterMode.BATTERY_METER_TEXT;
+ showInsidePercent = false;
+ break;
+ default:
+ break;
}
- return ptsF;
+
+ setMode(meterMode);
+ mShowPercent = showInsidePercent;
+ invalidate();
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+ super.onSizeChanged(w, h, oldw, oldh);
mHeight = h;
mWidth = w;
- mWarningTextPaint.setTextSize(h * 0.75f);
- mWarningTextHeight = -mWarningTextPaint.getFontMetrics().ascent;
+ if (mBatteryMeterDrawable != null) {
+ mBatteryMeterDrawable.onSizeChanged(w, h, oldw, oldh);
+ }
}
- private void updateShowPercent() {
- mShowPercent = 0 != Settings.System.getInt(getContext().getContentResolver(),
- SHOW_PERCENT_SETTING, 0);
+ public void setMode(BatteryMeterMode mode) {
+ if (mMeterMode == mode) {
+ return;
+ }
+
+ mMeterMode = mode;
+ BatteryTracker tracker = mDemoMode ? mDemoTracker : mTracker;
+ if (mode == BatteryMeterMode.BATTERY_METER_GONE ||
+ mode == BatteryMeterMode.BATTERY_METER_TEXT) {
+ setVisibility(View.GONE);
+ mBatteryMeterDrawable = null;
+ } else {
+ if (mBatteryMeterDrawable != null) {
+ mBatteryMeterDrawable.onDispose();
+ }
+ mBatteryMeterDrawable = createBatteryMeterDrawable(mode);
+ if (mMeterMode == BatteryMeterMode.BATTERY_METER_ICON_PORTRAIT ||
+ mMeterMode == BatteryMeterMode.BATTERY_METER_ICON_LANDSCAPE) {
+ ((NormalBatteryMeterDrawable)mBatteryMeterDrawable).loadBoltPoints(
+ mContext.getResources());
+ }
+ if (tracker.present) {
+ setVisibility(View.VISIBLE);
+ requestLayout();
+ invalidate();
+ } else {
+ setVisibility(View.GONE);
+ }
+ }
}
- private int getColorForLevel(int percent) {
+ public int getColorForLevel(int percent) {
// If we are in power save mode, always use the normal color.
if (mPowerSaveEnabled) {
@@ -259,13 +404,11 @@ public class BatteryMeterView extends View implements DemoMode,
}
public void setDarkIntensity(float darkIntensity) {
- int backgroundColor = getBackgroundColor(darkIntensity);
- int fillColor = getFillColor(darkIntensity);
- mIconTint = fillColor;
- mFramePaint.setColor(backgroundColor);
- mBoltPaint.setColor(fillColor);
- mChargeColor = fillColor;
- invalidate();
+ if (mBatteryMeterDrawable != null) {
+ int backgroundColor = getBackgroundColor(darkIntensity);
+ int fillColor = getFillColor(darkIntensity);
+ mBatteryMeterDrawable.setDarkIntensity(backgroundColor, fillColor);
+ }
}
private int getBackgroundColor(float darkIntensity) {
@@ -283,261 +426,574 @@ public class BatteryMeterView extends View implements DemoMode,
}
@Override
- public void draw(Canvas c) {
- BatteryTracker tracker = mDemoMode ? mDemoTracker : mTracker;
- final int level = tracker.level;
-
- if (level == BatteryTracker.UNKNOWN_LEVEL) return;
-
- float drawFrac = (float) level / 100f;
- final int pt = getPaddingTop();
- final int pl = getPaddingLeft();
- final int pr = getPaddingRight();
- final int pb = getPaddingBottom();
- final int height = mHeight - pt - pb;
- final int width = mWidth - pl - pr;
-
- final int buttonHeight = (int) (height * mButtonHeightFraction);
-
- mFrame.set(0, 0, width, height);
- mFrame.offset(pl, pt);
-
- // button-frame: area above the battery body
- mButtonFrame.set(
- mFrame.left + Math.round(width * 0.25f),
- mFrame.top,
- mFrame.right - Math.round(width * 0.25f),
- mFrame.top + buttonHeight);
-
- mButtonFrame.top += mSubpixelSmoothingLeft;
- mButtonFrame.left += mSubpixelSmoothingLeft;
- mButtonFrame.right -= mSubpixelSmoothingRight;
-
- // frame: battery body area
- mFrame.top += buttonHeight;
- mFrame.left += mSubpixelSmoothingLeft;
- mFrame.top += mSubpixelSmoothingLeft;
- mFrame.right -= mSubpixelSmoothingRight;
- mFrame.bottom -= mSubpixelSmoothingRight;
-
- // set the battery charging color
- mBatteryPaint.setColor(tracker.plugged ? mChargeColor : getColorForLevel(level));
-
- if (level >= FULL) {
- drawFrac = 1f;
- } else if (level <= mCriticalLevel) {
- drawFrac = 0f;
+ protected void onDraw(Canvas canvas) {
+ if (mBatteryMeterDrawable != null) {
+ BatteryTracker tracker = mDemoMode ? mDemoTracker : mTracker;
+ mBatteryMeterDrawable.onDraw(canvas, tracker);
}
+ }
- final float levelTop = drawFrac == 1f ? mButtonFrame.top
- : (mFrame.top + (mFrame.height() * (1f - drawFrac)));
-
- // define the battery shape
- mShapePath.reset();
- mShapePath.moveTo(mButtonFrame.left, mButtonFrame.top);
- mShapePath.lineTo(mButtonFrame.right, mButtonFrame.top);
- mShapePath.lineTo(mButtonFrame.right, mFrame.top);
- mShapePath.lineTo(mFrame.right, mFrame.top);
- mShapePath.lineTo(mFrame.right, mFrame.bottom);
- mShapePath.lineTo(mFrame.left, mFrame.bottom);
- mShapePath.lineTo(mFrame.left, mFrame.top);
- mShapePath.lineTo(mButtonFrame.left, mFrame.top);
- mShapePath.lineTo(mButtonFrame.left, mButtonFrame.top);
-
- if (tracker.plugged) {
- // define the bolt shape
- final float bl = mFrame.left + mFrame.width() / 4.5f;
- final float bt = mFrame.top + mFrame.height() / 6f;
- final float br = mFrame.right - mFrame.width() / 7f;
- final float bb = mFrame.bottom - mFrame.height() / 10f;
- if (mBoltFrame.left != bl || mBoltFrame.top != bt
- || mBoltFrame.right != br || mBoltFrame.bottom != bb) {
- mBoltFrame.set(bl, bt, br, bb);
- mBoltPath.reset();
- mBoltPath.moveTo(
- mBoltFrame.left + mBoltPoints[0] * mBoltFrame.width(),
- mBoltFrame.top + mBoltPoints[1] * mBoltFrame.height());
- for (int i = 2; i < mBoltPoints.length; i += 2) {
+ @Override
+ public boolean hasOverlappingRendering() {
+ return false;
+ }
+
+ @Override
+ public void dispatchDemoCommand(String command, Bundle args) {
+ if (getVisibility() == View.VISIBLE) {
+ if (!mDemoMode && command.equals(COMMAND_ENTER)) {
+ mDemoMode = true;
+ mDemoTracker.level = mTracker.level;
+ mDemoTracker.plugged = mTracker.plugged;
+ } else if (mDemoMode && command.equals(COMMAND_EXIT)) {
+ mDemoMode = false;
+ postInvalidate();
+ } else if (mDemoMode && command.equals(COMMAND_BATTERY)) {
+ String level = args.getString("level");
+ String plugged = args.getString("plugged");
+ if (level != null) {
+ mDemoTracker.level = Math.min(Math.max(Integer.parseInt(level), 0), 100);
+ }
+ if (plugged != null) {
+ mDemoTracker.plugged = Boolean.parseBoolean(plugged);
+ }
+ postInvalidate();
+ }
+ }
+ }
+
+ protected interface BatteryMeterDrawable {
+ void onDraw(Canvas c, BatteryTracker tracker);
+ void onSizeChanged(int w, int h, int oldw, int oldh);
+ void onDispose();
+ void setDarkIntensity(int backgroundColor, int fillColor);
+ }
+
+ protected class NormalBatteryMeterDrawable implements BatteryMeterDrawable {
+ private static final boolean SINGLE_DIGIT_PERCENT = false;
+ private static final boolean SHOW_100_PERCENT = false;
+
+ private boolean mDisposed;
+
+ protected final boolean mHorizontal;
+
+ private final Paint mFramePaint, mBatteryPaint, mWarningTextPaint, mTextPaint, mBoltPaint;
+ private float mTextHeight, mWarningTextHeight;
+
+ private int mChargeColor;
+ private final float[] mBoltPoints;
+ private final Path mBoltPath = new Path();
+
+ private final RectF mFrame = new RectF();
+ private final RectF mButtonFrame = new RectF();
+ private final RectF mBoltFrame = new RectF();
+
+ public NormalBatteryMeterDrawable(Resources res, boolean horizontal) {
+ super();
+ mHorizontal = horizontal;
+ mDisposed = false;
+
+ mFramePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ mFramePaint.setColor(mFrameColor);
+ mFramePaint.setDither(true);
+ mFramePaint.setStrokeWidth(0);
+ mFramePaint.setStyle(Paint.Style.FILL_AND_STROKE);
+
+ mBatteryPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ mBatteryPaint.setDither(true);
+ mBatteryPaint.setStrokeWidth(0);
+ mBatteryPaint.setStyle(Paint.Style.FILL_AND_STROKE);
+
+ mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ Typeface font = Typeface.create("sans-serif-condensed", Typeface.BOLD);
+ mTextPaint.setTypeface(font);
+ mTextPaint.setTextAlign(Paint.Align.CENTER);
+
+ mWarningTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ mWarningTextPaint.setColor(mColors[1]);
+ font = Typeface.create("sans-serif", Typeface.BOLD);
+ mWarningTextPaint.setTypeface(font);
+ mWarningTextPaint.setTextAlign(Paint.Align.CENTER);
+
+ mChargeColor = getResources().getColor(R.color.batterymeter_charge_color);
+
+ mBoltPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ mBoltPaint.setColor(res.getColor(R.color.batterymeter_bolt_color));
+ mBoltPoints = loadBoltPoints(res);
+ }
+
+ @Override
+ public void onDraw(Canvas c, BatteryTracker tracker) {
+ if (mDisposed) return;
+
+ final int level = tracker.level;
+
+ if (level == BatteryTracker.UNKNOWN_LEVEL) return;
+
+ float drawFrac = (float) level / 100f;
+ final int pt = getPaddingTop() + (mHorizontal ? (int)(mHeight * 0.12f) : 0);
+ final int pl = getPaddingLeft();
+ final int pr = getPaddingRight();
+ final int pb = getPaddingBottom() + (mHorizontal ? (int)(mHeight * 0.08f) : 0);
+ final int height = mHeight - pt - pb;
+ final int width = mWidth - pl - pr;
+
+ final int buttonHeight = (int) ((mHorizontal ? width : height) * mButtonHeightFraction);
+
+ mFrame.set(0, 0, width, height);
+ mFrame.offset(pl, pt);
+
+ if (mHorizontal) {
+ mButtonFrame.set(
+ /*cover frame border of intersecting area*/
+ width - buttonHeight - mFrame.left,
+ mFrame.top + Math.round(height * 0.25f),
+ mFrame.right,
+ mFrame.bottom - Math.round(height * 0.25f));
+
+ mButtonFrame.top += mSubpixelSmoothingLeft;
+ mButtonFrame.bottom -= mSubpixelSmoothingRight;
+ mButtonFrame.right -= mSubpixelSmoothingRight;
+ } else {
+ // button-frame: area above the battery body
+ mButtonFrame.set(
+ mFrame.left + Math.round(width * 0.25f),
+ mFrame.top,
+ mFrame.right - Math.round(width * 0.25f),
+ mFrame.top + buttonHeight);
+
+ mButtonFrame.top += mSubpixelSmoothingLeft;
+ mButtonFrame.left += mSubpixelSmoothingLeft;
+ mButtonFrame.right -= mSubpixelSmoothingRight;
+ }
+
+ // frame: battery body area
+
+ if (mHorizontal) {
+ mFrame.right -= buttonHeight;
+ } else {
+ mFrame.top += buttonHeight;
+ }
+ mFrame.left += mSubpixelSmoothingLeft;
+ mFrame.top += mSubpixelSmoothingLeft;
+ mFrame.right -= mSubpixelSmoothingRight;
+ mFrame.bottom -= mSubpixelSmoothingRight;
+
+ // set the battery charging color
+ mBatteryPaint.setColor(tracker.plugged ? mChargeColor : getColorForLevel(level));
+
+ if (level >= FULL) {
+ drawFrac = 1f;
+ } else if (level <= mCriticalLevel) {
+ drawFrac = 0f;
+ }
+
+ final float levelTop;
+
+ if (drawFrac == 1f) {
+ if (mHorizontal) {
+ levelTop = mButtonFrame.right;
+ } else {
+ levelTop = mButtonFrame.top;
+ }
+ } else {
+ if (mHorizontal) {
+ levelTop = (mFrame.right - (mFrame.width() * (1f - drawFrac)));
+ } else {
+ levelTop = (mFrame.top + (mFrame.height() * (1f - drawFrac)));
+ }
+ }
+
+ // define the battery shape
+ mShapePath.reset();
+ mShapePath.moveTo(mButtonFrame.left, mButtonFrame.top);
+ if (mHorizontal) {
+ mShapePath.lineTo(mButtonFrame.right, mButtonFrame.top);
+ mShapePath.lineTo(mButtonFrame.right, mButtonFrame.bottom);
+ mShapePath.lineTo(mButtonFrame.left, mButtonFrame.bottom);
+ mShapePath.lineTo(mFrame.right, mFrame.bottom);
+ mShapePath.lineTo(mFrame.left, mFrame.bottom);
+ mShapePath.lineTo(mFrame.left, mFrame.top);
+ mShapePath.lineTo(mButtonFrame.left, mFrame.top);
+ mShapePath.lineTo(mButtonFrame.left, mButtonFrame.top);
+ } else {
+ mShapePath.lineTo(mButtonFrame.right, mButtonFrame.top);
+ mShapePath.lineTo(mButtonFrame.right, mFrame.top);
+ mShapePath.lineTo(mFrame.right, mFrame.top);
+ mShapePath.lineTo(mFrame.right, mFrame.bottom);
+ mShapePath.lineTo(mFrame.left, mFrame.bottom);
+ mShapePath.lineTo(mFrame.left, mFrame.top);
+ mShapePath.lineTo(mButtonFrame.left, mFrame.top);
+ mShapePath.lineTo(mButtonFrame.left, mButtonFrame.top);
+ }
+
+ if (tracker.plugged) {
+ // define the bolt shape
+ final float bl = mFrame.left + mFrame.width() / (mHorizontal ? 9f : 4.5f);
+ final float bt = mFrame.top + mFrame.height() / (mHorizontal ? 4.5f : 6f);
+ final float br = mFrame.right - mFrame.width() / (mHorizontal ? 6f : 7f);
+ final float bb = mFrame.bottom - mFrame.height() / (mHorizontal ? 7f : 10f);
+ if (mBoltFrame.left != bl || mBoltFrame.top != bt
+ || mBoltFrame.right != br || mBoltFrame.bottom != bb) {
+ mBoltFrame.set(bl, bt, br, bb);
+ mBoltPath.reset();
+ mBoltPath.moveTo(
+ mBoltFrame.left + mBoltPoints[0] * mBoltFrame.width(),
+ mBoltFrame.top + mBoltPoints[1] * mBoltFrame.height());
+ for (int i = 2; i < mBoltPoints.length; i += 2) {
+ mBoltPath.lineTo(
+ mBoltFrame.left + mBoltPoints[i] * mBoltFrame.width(),
+ mBoltFrame.top + mBoltPoints[i + 1] * mBoltFrame.height());
+ }
mBoltPath.lineTo(
- mBoltFrame.left + mBoltPoints[i] * mBoltFrame.width(),
- mBoltFrame.top + mBoltPoints[i + 1] * mBoltFrame.height());
+ mBoltFrame.left + mBoltPoints[0] * mBoltFrame.width(),
+ mBoltFrame.top + mBoltPoints[1] * mBoltFrame.height());
+ }
+
+ float boltPct = mHorizontal ?
+ (mBoltFrame.left - levelTop) / (mBoltFrame.left - mBoltFrame.right) :
+ (mBoltFrame.bottom - levelTop) / (mBoltFrame.bottom - mBoltFrame.top);
+ boltPct = Math.min(Math.max(boltPct, 0), 1);
+ if (boltPct <= BOLT_LEVEL_THRESHOLD) {
+ // draw the bolt if opaque
+ c.drawPath(mBoltPath, mBoltPaint);
+ } else {
+ // otherwise cut the bolt out of the overall shape
+ mShapePath.op(mBoltPath, Path.Op.DIFFERENCE);
+ }
+ }
+
+ // compute percentage text
+ boolean pctOpaque = false;
+ float pctX = 0, pctY = 0;
+ String pctText = null;
+ if (!tracker.plugged && level > mCriticalLevel && mShowPercent) {
+ mTextPaint.setColor(getColorForLevel(level));
+ final float full = mHorizontal ? 0.60f : 0.45f;
+ final float nofull = mHorizontal ? 0.75f : 0.6f;
+ final float single = mHorizontal ? 0.86f : 0.75f;
+ mTextPaint.setTextSize(height *
+ (SINGLE_DIGIT_PERCENT ? single
+ : (tracker.level == 100 ? full : nofull)));
+ mTextHeight = -mTextPaint.getFontMetrics().ascent;
+ pctText = String.valueOf(SINGLE_DIGIT_PERCENT ? (level/10) : level);
+ pctX = mWidth * 0.5f;
+ pctY = (mHeight + mTextHeight) * 0.47f;
+ if (mHorizontal) {
+ pctOpaque = pctX > levelTop;
+ } else {
+ pctOpaque = levelTop > pctY;
+ }
+ if (!pctOpaque) {
+ mTextPath.reset();
+ mTextPaint.getTextPath(pctText, 0, pctText.length(), pctX, pctY, mTextPath);
+ // cut the percentage text out of the overall shape
+ mShapePath.op(mTextPath, Path.Op.DIFFERENCE);
}
- mBoltPath.lineTo(
- mBoltFrame.left + mBoltPoints[0] * mBoltFrame.width(),
- mBoltFrame.top + mBoltPoints[1] * mBoltFrame.height());
}
- float boltPct = (mBoltFrame.bottom - levelTop) / (mBoltFrame.bottom - mBoltFrame.top);
- boltPct = Math.min(Math.max(boltPct, 0), 1);
- if (boltPct <= BOLT_LEVEL_THRESHOLD) {
- // draw the bolt if opaque
- c.drawPath(mBoltPath, mBoltPaint);
+ // draw the battery shape background
+ c.drawPath(mShapePath, mFramePaint);
+
+ // draw the battery shape, clipped to charging level
+ if (mHorizontal) {
+ mFrame.right = levelTop;
} else {
- // otherwise cut the bolt out of the overall shape
- mShapePath.op(mBoltPath, Path.Op.DIFFERENCE);
+ mFrame.top = levelTop;
+ }
+ mClipPath.reset();
+ mClipPath.addRect(mFrame, Path.Direction.CCW);
+ mShapePath.op(mClipPath, Path.Op.INTERSECT);
+ c.drawPath(mShapePath, mBatteryPaint);
+
+ if (!tracker.plugged) {
+ if (level <= mCriticalLevel) {
+ // draw the warning text
+ final float x = mWidth * 0.5f;
+ final float y = (mHeight + mWarningTextHeight) * 0.48f;
+ c.drawText(mWarningString, x, y, mWarningTextPaint);
+ } else if (pctOpaque) {
+ // draw the percentage text
+ c.drawText(pctText, pctX, pctY, mTextPaint);
+ }
}
}
- // compute percentage text
- boolean pctOpaque = false;
- float pctX = 0, pctY = 0;
- String pctText = null;
- if (!tracker.plugged && level > mCriticalLevel && mShowPercent) {
- mTextPaint.setColor(getColorForLevel(level));
- mTextPaint.setTextSize(height *
- (SINGLE_DIGIT_PERCENT ? 0.75f
- : (tracker.level == 100 ? 0.38f : 0.5f)));
- mTextHeight = -mTextPaint.getFontMetrics().ascent;
- pctText = String.valueOf(SINGLE_DIGIT_PERCENT ? (level/10) : level);
- pctX = mWidth * 0.5f;
- pctY = (mHeight + mTextHeight) * 0.47f;
- pctOpaque = levelTop > pctY;
- if (!pctOpaque) {
- mTextPath.reset();
- mTextPaint.getTextPath(pctText, 0, pctText.length(), pctX, pctY, mTextPath);
- // cut the percentage text out of the overall shape
- mShapePath.op(mTextPath, Path.Op.DIFFERENCE);
- }
+ @Override
+ public void onDispose() {
+ mDisposed = true;
+ }
+
+ @Override
+ public void setDarkIntensity(int backgroundColor, int fillColor) {
+ mIconTint = fillColor;
+ mFramePaint.setColor(backgroundColor);
+ mBoltPaint.setColor(fillColor);
+ mChargeColor = fillColor;
+ invalidate();
+ }
+
+ @Override
+ public void onSizeChanged(int w, int h, int oldw, int oldh) {
+ mHeight = h;
+ mWidth = w;
+ mWarningTextPaint.setTextSize(h * 0.75f);
+ mWarningTextHeight = -mWarningTextPaint.getFontMetrics().ascent;
}
- // draw the battery shape background
- c.drawPath(mShapePath, mFramePaint);
-
- // draw the battery shape, clipped to charging level
- mFrame.top = levelTop;
- mClipPath.reset();
- mClipPath.addRect(mFrame, Path.Direction.CCW);
- mShapePath.op(mClipPath, Path.Op.INTERSECT);
- c.drawPath(mShapePath, mBatteryPaint);
-
- if (!tracker.plugged) {
- if (level <= mCriticalLevel) {
- // draw the warning text
- final float x = mWidth * 0.5f;
- final float y = (mHeight + mWarningTextHeight) * 0.48f;
- c.drawText(mWarningString, x, y, mWarningTextPaint);
- } else if (pctOpaque) {
- // draw the percentage text
- c.drawText(pctText, pctX, pctY, mTextPaint);
+ private float[] loadBoltPoints(Resources res) {
+ final int[] pts = res.getIntArray((mHorizontal
+ ? R.array.batterymeter_inverted_bolt_points
+ : R.array.batterymeter_bolt_points));
+ int maxX = 0, maxY = 0;
+ for (int i = 0; i < pts.length; i += 2) {
+ maxX = Math.max(maxX, pts[i]);
+ maxY = Math.max(maxY, pts[i + 1]);
+ }
+ final float[] ptsF = new float[pts.length];
+ for (int i = 0; i < pts.length; i += 2) {
+ ptsF[i] = (float)pts[i] / maxX;
+ ptsF[i + 1] = (float)pts[i + 1] / maxY;
}
+ return ptsF;
}
}
- @Override
- public boolean hasOverlappingRendering() {
- return false;
- }
+ protected class CircleBatteryMeterDrawable implements BatteryMeterDrawable {
+ private static final boolean SINGLE_DIGIT_PERCENT = false;
+ private static final boolean SHOW_100_PERCENT = false;
- private boolean mDemoMode;
- private BatteryTracker mDemoTracker = new BatteryTracker();
+ private static final int FULL = 96;
- @Override
- public void dispatchDemoCommand(String command, Bundle args) {
- if (!mDemoMode && command.equals(COMMAND_ENTER)) {
- mDemoMode = true;
- mDemoTracker.level = mTracker.level;
- mDemoTracker.plugged = mTracker.plugged;
- } else if (mDemoMode && command.equals(COMMAND_EXIT)) {
- mDemoMode = false;
- postInvalidate();
- } else if (mDemoMode && command.equals(COMMAND_BATTERY)) {
- String level = args.getString("level");
- String plugged = args.getString("plugged");
- if (level != null) {
- mDemoTracker.level = Math.min(Math.max(Integer.parseInt(level), 0), 100);
- }
- if (plugged != null) {
- mDemoTracker.plugged = Boolean.parseBoolean(plugged);
- }
- postInvalidate();
+ public static final float STROKE_WITH = 6.5f;
+
+ private boolean mDisposed;
+
+ private int mAnimOffset;
+ private boolean mIsAnimating; // stores charge-animation status to reliably
+ //remove callbacks
+
+ private int mCircleSize; // draw size of circle
+ private RectF mRectLeft; // contains the precalculated rect used in drawArc(),
+ // derived from mCircleSize
+ private float mTextX, mTextY; // precalculated position for drawText() to appear centered
+
+ private Paint mTextPaint;
+ private Paint mFrontPaint;
+ private Paint mBackPaint;
+ private Paint mBoltPaint;
+ private Paint mWarningTextPaint;
+
+ private final RectF mBoltFrame = new RectF();
+
+ private int mChargeColor;
+ private final float[] mBoltPoints;
+ private final Path mBoltPath = new Path();
+
+ public CircleBatteryMeterDrawable(Resources res) {
+ super();
+ mDisposed = false;
+
+ mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ Typeface font = Typeface.create("sans-serif-condensed", Typeface.BOLD);
+ mTextPaint.setTypeface(font);
+ mTextPaint.setTextAlign(Paint.Align.CENTER);
+
+ mFrontPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ mFrontPaint.setStrokeCap(Paint.Cap.BUTT);
+ mFrontPaint.setDither(true);
+ mFrontPaint.setStrokeWidth(0);
+ mFrontPaint.setStyle(Paint.Style.STROKE);
+
+ mBackPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ mBackPaint.setColor(res.getColor(R.color.batterymeter_frame_color));
+ mBackPaint.setStrokeCap(Paint.Cap.BUTT);
+ mBackPaint.setDither(true);
+ mBackPaint.setStrokeWidth(0);
+ mBackPaint.setStyle(Paint.Style.STROKE);
+
+ mWarningTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ mWarningTextPaint.setColor(mColors[1]);
+ font = Typeface.create("sans-serif", Typeface.BOLD);
+ mWarningTextPaint.setTypeface(font);
+ mWarningTextPaint.setTextAlign(Paint.Align.CENTER);
+
+ mChargeColor = getResources().getColor(R.color.batterymeter_charge_color);
+
+ mBoltPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ mBoltPaint.setColor(res.getColor(R.color.batterymeter_bolt_color));
+ mBoltPoints = loadBoltPoints(res);
}
- }
- private final class BatteryTracker extends BroadcastReceiver {
- public static final int UNKNOWN_LEVEL = -1;
+ @Override
+ public void onDraw(Canvas c, BatteryTracker tracker) {
+ if (mDisposed) return;
- // current battery status
- int level = UNKNOWN_LEVEL;
- String percentStr;
- int plugType;
- boolean plugged;
- int health;
- int status;
- String technology;
- int voltage;
- int temperature;
- boolean testmode = false;
+ if (mRectLeft == null) {
+ initSizeBasedStuff();
+ }
+
+ drawCircle(c, tracker, mTextX, mRectLeft);
+ if (mAnimationsEnabled) {
+ updateChargeAnim(tracker);
+ }
+ }
@Override
- public void onReceive(Context context, Intent intent) {
- final String action = intent.getAction();
- if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {
- if (testmode && ! intent.getBooleanExtra("testmode", false)) return;
+ public void onDispose() {
+ mDisposed = true;
+ }
- level = (int)(100f
- * intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0)
- / intent.getIntExtra(BatteryManager.EXTRA_SCALE, 100));
+ @Override
+ public void setDarkIntensity(int backgroundColor, int fillColor) {
+ mIconTint = fillColor;
+ mBoltPaint.setColor(fillColor);
+ mChargeColor = fillColor;
+ invalidate();
+ }
- plugType = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0);
- plugged = plugType != 0;
- health = intent.getIntExtra(BatteryManager.EXTRA_HEALTH,
- BatteryManager.BATTERY_HEALTH_UNKNOWN);
- status = intent.getIntExtra(BatteryManager.EXTRA_STATUS,
- BatteryManager.BATTERY_STATUS_UNKNOWN);
- technology = intent.getStringExtra(BatteryManager.EXTRA_TECHNOLOGY);
- voltage = intent.getIntExtra(BatteryManager.EXTRA_VOLTAGE, 0);
- temperature = intent.getIntExtra(BatteryManager.EXTRA_TEMPERATURE, 0);
+ @Override
+ public void onSizeChanged(int w, int h, int oldw, int oldh) {
+ initSizeBasedStuff();
+ }
- setContentDescription(
- context.getString(R.string.accessibility_battery_level, level));
- postInvalidate();
- } else if (action.equals(ACTION_LEVEL_TEST)) {
- testmode = true;
- post(new Runnable() {
- int curLevel = 0;
- int incr = 1;
- int saveLevel = level;
- int savePlugged = plugType;
- Intent dummy = new Intent(Intent.ACTION_BATTERY_CHANGED);
- @Override
- public void run() {
- if (curLevel < 0) {
- testmode = false;
- dummy.putExtra("level", saveLevel);
- dummy.putExtra("plugged", savePlugged);
- dummy.putExtra("testmode", false);
- } else {
- dummy.putExtra("level", curLevel);
- dummy.putExtra("plugged", incr > 0 ? BatteryManager.BATTERY_PLUGGED_AC
- : 0);
- dummy.putExtra("testmode", true);
- }
- getContext().sendBroadcast(dummy);
+ private float[] loadBoltPoints(Resources res) {
+ final int[] pts = res.getIntArray(R.array.batterymeter_bolt_points);
+ int maxX = 0, maxY = 0;
+ for (int i = 0; i < pts.length; i += 2) {
+ maxX = Math.max(maxX, pts[i]);
+ maxY = Math.max(maxY, pts[i + 1]);
+ }
+ final float[] ptsF = new float[pts.length];
+ for (int i = 0; i < pts.length; i += 2) {
+ ptsF[i] = (float)pts[i] / maxX;
+ ptsF[i + 1] = (float)pts[i + 1] / maxY;
+ }
+ return ptsF;
+ }
- if (!testmode) return;
+ private void drawCircle(Canvas canvas, BatteryTracker tracker,
+ float textX, RectF drawRect) {
+ boolean unknownStatus = tracker.status == BatteryManager.BATTERY_STATUS_UNKNOWN;
+ int level = tracker.level;
+ Paint paint;
- curLevel += incr;
- if (curLevel == 100) {
- incr *= -1;
- }
- postDelayed(this, 200);
- }
- });
+ if (unknownStatus) {
+ paint = mBackPaint;
+ level = 100; // Draw all the circle;
+ } else {
+ paint = mFrontPaint;
+ paint.setColor(getColorForLevel(level));
+ if (tracker.status == BatteryManager.BATTERY_STATUS_FULL) {
+ level = 100;
+ }
+ }
+
+ // draw thin gray ring first
+ canvas.drawArc(drawRect, 270, 360, false, mBackPaint);
+ if (level != 0) {
+ // draw colored arc representing charge level
+ canvas.drawArc(drawRect, 270 + mAnimOffset, 3.6f * level, false, paint);
+ }
+ // if chosen by options, draw percentage text in the middle
+ // always skip percentage when 100, so layout doesnt break
+ if (unknownStatus) {
+ mTextPaint.setColor(paint.getColor());
+ canvas.drawText("?", textX, mTextY, mTextPaint);
+
+ } else if (tracker.plugged) {
+ canvas.drawPath(mBoltPath, mBoltPaint);
+ } else {
+ if (level > mCriticalLevel
+ && (mShowPercent && !(tracker.level == 100 && !SHOW_100_PERCENT))) {
+ // draw the percentage text
+ String pctText = String.valueOf(SINGLE_DIGIT_PERCENT ? (level/10) : level);
+ mTextPaint.setColor(paint.getColor());
+ canvas.drawText(pctText, textX, mTextY, mTextPaint);
+ } else if (level <= mCriticalLevel) {
+ // draw the warning text
+ canvas.drawText(mWarningString, textX, mTextY, mWarningTextPaint);
+ }
}
}
- }
- private final class SettingObserver extends ContentObserver {
- public SettingObserver() {
- super(new Handler());
+ /**
+ * updates the animation counter
+ * cares for timed callbacks to continue animation cycles
+ * uses mInvalidate for delayed invalidate() callbacks
+ */
+ private void updateChargeAnim(BatteryTracker tracker) {
+ // Stop animation when battery is full or after the meter
+ // rotated back to 0 after unplugging.
+ if (!tracker.shouldIndicateCharging()
+ || tracker.status == BatteryManager.BATTERY_STATUS_FULL
+ || tracker.level == 0) {
+ if (mIsAnimating) {
+ mIsAnimating = false;
+ mAnimOffset = 0;
+ }
+ return;
+ }
+
+ mIsAnimating = true;
+
+ if (mAnimOffset > 360) {
+ mAnimOffset = 0;
+ } else {
+ mAnimOffset += 3;
+ }
+
+ postInvalidateDelayed(50);
}
- @Override
- public void onChange(boolean selfChange, Uri uri) {
- super.onChange(selfChange, uri);
- updateShowPercent();
- postInvalidate();
+ /**
+ * initializes all size dependent variables
+ * sets stroke width and text size of all involved paints
+ * YES! i think the method name is appropriate
+ */
+ private void initSizeBasedStuff() {
+ mCircleSize = Math.min(getMeasuredWidth(), getMeasuredHeight());
+ mTextPaint.setTextSize(mCircleSize / 2f);
+ mWarningTextPaint.setTextSize(mCircleSize / 2f);
+
+ float strokeWidth = mCircleSize / STROKE_WITH;
+ mFrontPaint.setStrokeWidth(strokeWidth);
+ mBackPaint.setStrokeWidth(strokeWidth);
+
+ // calculate rectangle for drawArc calls
+ int pLeft = getPaddingLeft();
+ mRectLeft = new RectF(pLeft + strokeWidth / 2.0f, 0 + strokeWidth / 2.0f, mCircleSize
+ - strokeWidth / 2.0f + pLeft, mCircleSize - strokeWidth / 2.0f);
+
+ // calculate Y position for text
+ Rect bounds = new Rect();
+ mTextPaint.getTextBounds("99", 0, "99".length(), bounds);
+ mTextX = mCircleSize / 2.0f + getPaddingLeft();
+ // the +1dp at end of formula balances out rounding issues.works out on all resolutions
+ mTextY = mCircleSize / 2.0f + (bounds.bottom - bounds.top) / 2.0f
+ - strokeWidth / 2.0f + getResources().getDisplayMetrics().density;
+
+ // draw the bolt
+ final float bl = (int) (mRectLeft.left + mRectLeft.width() / 3.2f);
+ final float bt = (int) (mRectLeft.top + mRectLeft.height() / 4f);
+ final float br = (int) (mRectLeft.right - mRectLeft.width() / 5.2f);
+ final float bb = (int) (mRectLeft.bottom - mRectLeft.height() / 8f);
+ if (mBoltFrame.left != bl || mBoltFrame.top != bt
+ || mBoltFrame.right != br || mBoltFrame.bottom != bb) {
+ mBoltFrame.set(bl, bt, br, bb);
+ mBoltPath.reset();
+ mBoltPath.moveTo(
+ mBoltFrame.left + mBoltPoints[0] * mBoltFrame.width(),
+ mBoltFrame.top + mBoltPoints[1] * mBoltFrame.height());
+ for (int i = 2; i < mBoltPoints.length; i += 2) {
+ mBoltPath.lineTo(
+ mBoltFrame.left + mBoltPoints[i] * mBoltFrame.width(),
+ mBoltFrame.top + mBoltPoints[i + 1] * mBoltFrame.height());
+ }
+ mBoltPath.lineTo(
+ mBoltFrame.left + mBoltPoints[0] * mBoltFrame.width(),
+ mBoltFrame.top + mBoltPoints[1] * mBoltFrame.height());
+ }
}
}
-
}
diff --git a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
index 8556afc..5a6f3c9 100644
--- a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
+++ b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
@@ -236,7 +236,9 @@ public class ImageWallpaper extends WallpaperService {
Log.d(TAG, "Visibility changed to visible=" + visible);
}
mVisible = visible;
- drawFrame();
+ if (visible) {
+ drawFrame();
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/cm/GlowBackground.java b/packages/SystemUI/src/com/android/systemui/cm/GlowBackground.java
new file mode 100644
index 0000000..8b4bf06
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/cm/GlowBackground.java
@@ -0,0 +1,83 @@
+package com.android.systemui.cm;
+
+import android.animation.Animator;
+import android.animation.ObjectAnimator;
+import android.animation.ValueAnimator;
+import android.graphics.Canvas;
+import android.graphics.ColorFilter;
+import android.graphics.Paint;
+import android.graphics.drawable.Drawable;
+import android.view.animation.AnticipateOvershootInterpolator;
+
+public class GlowBackground extends Drawable implements ValueAnimator.AnimatorUpdateListener {
+
+ private static final int MAX_CIRCLE_SIZE = 150;
+
+ private final Paint mPaint;
+ private Animator mAnimator;
+ private float mCircleSize;
+
+ public GlowBackground(int color) {
+ mPaint = new Paint();
+ mPaint.setColor(color);
+ }
+
+ private void startAnimation(boolean hide) {
+ if (mAnimator != null) {
+ mAnimator.cancel();
+ }
+ if (hide && mCircleSize == 0f) {
+ return;
+ } else if (!hide && mCircleSize == MAX_CIRCLE_SIZE) {
+ return;
+ }
+ mAnimator = getAnimator(hide);
+ mAnimator.start();
+ }
+
+ private Animator getAnimator(boolean hide) {
+ float start = mCircleSize;
+ float end = MAX_CIRCLE_SIZE;
+ if (hide) {
+ end = 0f;
+ }
+ ValueAnimator animator = ObjectAnimator.ofFloat(start, end);
+ animator.setInterpolator(new AnticipateOvershootInterpolator());
+ animator.setDuration(300);
+ animator.addUpdateListener(this);
+ return animator;
+ }
+
+ @Override
+ public void draw(Canvas canvas) {
+ canvas.drawCircle(getBounds().width() / 2, getBounds().height() / 2, mCircleSize, mPaint);
+ }
+
+ @Override
+ public void setAlpha(int i) {
+ }
+
+ @Override
+ public void setColorFilter(ColorFilter colorFilter) {
+ }
+
+ @Override
+ public int getOpacity() {
+ return 0;
+ }
+
+ @Override
+ public void onAnimationUpdate(ValueAnimator valueAnimator) {
+ mCircleSize = (Float) valueAnimator.getAnimatedValue();
+ invalidateSelf();
+ }
+
+ public void hideGlow() {
+ startAnimation(true);
+ }
+
+ public void showGlow() {
+ startAnimation(false);
+ }
+}
+
diff --git a/packages/SystemUI/src/com/android/systemui/cm/LockscreenShortcutsActivity.java b/packages/SystemUI/src/com/android/systemui/cm/LockscreenShortcutsActivity.java
new file mode 100644
index 0000000..d8cfa5e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/cm/LockscreenShortcutsActivity.java
@@ -0,0 +1,239 @@
+package com.android.systemui.cm;
+
+import com.android.settingslib.cm.ShortcutPickHelper;
+import com.android.systemui.R;
+import com.android.systemui.cm.LockscreenShortcutsHelper.Shortcuts;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.res.ColorStateList;
+import android.graphics.Color;
+import android.graphics.ColorMatrix;
+import android.graphics.ColorMatrixColorFilter;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.text.TextUtils;
+import android.view.MenuItem;
+import android.view.MotionEvent;
+import android.view.View;
+import android.widget.ImageView;
+
+import java.util.ArrayList;
+
+public class LockscreenShortcutsActivity extends Activity implements View.OnClickListener,
+ ShortcutPickHelper.OnPickListener, View.OnTouchListener, LockscreenShortcutsHelper.OnChangeListener {
+
+ private static final int[] sIconIds = new int[]{R.id.left_button, R.id.right_button};
+ private static final String ACTION_APP = "action_app";
+
+ private ActionHolder mActions;
+ private ShortcutPickHelper mPicker;
+ private LockscreenShortcutsHelper mShortcutHelper;
+ private View mSelectedView;
+ private ColorMatrixColorFilter mFilter;
+ private ColorStateList mDefaultTintList;
+
+ @Override
+ public void shortcutPicked(String uri, String friendlyName, boolean isApplication) {
+ onTargetChange(uri);
+ }
+
+ @Override
+ public boolean onTouch(View v, MotionEvent event) {
+ switch (event.getAction()) {
+ case MotionEvent.ACTION_DOWN:
+ GlowBackground background = (GlowBackground) v.getBackground();
+ background.showGlow();
+ break;
+ case MotionEvent.ACTION_UP:
+ case MotionEvent.ACTION_CANCEL:
+ background = (GlowBackground) v.getBackground();
+ background.hideGlow();
+ break;
+ }
+ return false;
+ }
+
+ @Override
+ public void onChange() {
+ updateDrawables();
+ }
+
+ private class ActionHolder {
+ private ArrayList<CharSequence> mAvailableEntries = new ArrayList<CharSequence>();
+ private ArrayList<String> mAvailableValues = new ArrayList<String>();
+
+ public void addAction(String action, int entryResId) {
+ mAvailableEntries.add(getString(entryResId));
+ mAvailableValues.add(action);
+ }
+
+ public int getActionIndex(String action) {
+ int count = mAvailableValues.size();
+ for (int i = 0; i < count; i++) {
+ if (TextUtils.equals(mAvailableValues.get(i), action)) {
+ return i;
+ }
+ }
+
+ return -1;
+ }
+
+ public String getAction(int index) {
+ if (index > mAvailableValues.size()) {
+ return null;
+ }
+
+ return mAvailableValues.get(index);
+ }
+
+ public CharSequence[] getEntries() {
+ return mAvailableEntries.toArray(new CharSequence[mAvailableEntries.size()]);
+ }
+ };
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.lockscreen_shortcuts);
+ getActionBar().setDisplayHomeAsUpEnabled(true);
+
+ mPicker = new ShortcutPickHelper(this, this);
+ mShortcutHelper = new LockscreenShortcutsHelper(this, this);
+ ColorMatrix cm = new ColorMatrix();
+ cm.setSaturation(0);
+ mFilter = new ColorMatrixColorFilter(cm);
+ ImageView unlockButton = (ImageView) findViewById(R.id.middle_button);
+ mDefaultTintList = unlockButton.getImageTintList();
+ createActionList();
+ initiateViews();
+ updateDrawables();
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ switch (item.getItemId()) {
+ case android.R.id.home:
+ finish();
+ return true;
+ }
+ return super.onOptionsItemSelected(item);
+ }
+
+ private void initiateViews() {
+ int size = getResources().getDimensionPixelSize(R.dimen.lockscreen_icon_size);
+ for (int id : sIconIds) {
+ View v = findViewById(id);
+ v.setOnClickListener(this);
+ v.setOnTouchListener(this);
+ GlowBackground background = new GlowBackground(Color.WHITE);
+ background.setBounds(0, 0, size, size);
+ v.setBackground(background);
+ }
+ }
+
+ private void updateDrawables() {
+ for (int i = 0; i < sIconIds.length; i++) {
+ int id = sIconIds[i];
+ ImageView v = (ImageView) findViewById(id);
+ v.setImageTintList(null);
+ v.setColorFilter(null);
+ Shortcuts shortcut = Shortcuts.values()[i];
+ v.setTag(mShortcutHelper.getUriForTarget(shortcut));
+ Drawable drawable;
+ if (mShortcutHelper.isTargetEmpty(shortcut)) {
+ drawable = getResources().getDrawable(R.drawable.ic_lockscreen_shortcuts_blank);
+ } else {
+ drawable = mShortcutHelper.getDrawableForTarget(shortcut);
+ if (drawable == null) {
+ drawable = getResources().getDrawable(shortcut == Shortcuts.LEFT_SHORTCUT
+ ? R.drawable.ic_phone_24dp : R.drawable.ic_camera_alt_24dp);
+ v.setImageTintList(mDefaultTintList);
+ } else {
+ v.setColorFilter(mFilter);
+ }
+ }
+ v.setImageDrawable(drawable);
+ }
+ }
+
+ private void createActionList() {
+ mActions = new ActionHolder();
+ mActions.addAction(LockscreenShortcutsHelper.NONE, R.string.lockscreen_none_target);
+ mActions.addAction(LockscreenShortcutsHelper.DEFAULT, R.string.lockscreen_default_target);
+ mActions.addAction(ACTION_APP, R.string.select_application);
+ }
+
+ @Override
+ public void onActivityResult(int requestCode, int resultCode, Intent data) {
+ mPicker.onActivityResult(requestCode, resultCode, data);
+ super.onActivityResult(requestCode, resultCode, data);
+ }
+
+ @Override
+ public void onClick(View v) {
+ mSelectedView = v;
+
+ final GlowBackground background = (GlowBackground) mSelectedView.getBackground();
+
+ mSelectedView.postOnAnimation(new Runnable() {
+ @Override
+ public void run() {
+ background.showGlow();
+ }
+ });
+
+ final DialogInterface.OnClickListener l = new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int item) {
+ onTargetChange(mActions.getAction(item));
+ dialog.dismiss();
+ }
+ };
+
+ final DialogInterface.OnCancelListener cancel = new DialogInterface.OnCancelListener() {
+ @Override
+ public void onCancel(DialogInterface dialog) {
+ onTargetChange(null);
+ }
+ };
+
+ final AlertDialog dialog = new AlertDialog.Builder(this)
+ .setTitle(R.string.lockscreen_choose_action_title)
+ .setItems(mActions.getEntries(), l)
+ .setOnCancelListener(cancel)
+ .create();
+
+ dialog.show();
+ }
+
+ private void onTargetChange(String uri) {
+ if (uri == null) {
+ final GlowBackground background = (GlowBackground) mSelectedView.getBackground();
+ background.hideGlow();
+ return;
+ }
+
+ if (uri.equals(ACTION_APP)) {
+ mPicker.pickShortcut(null, null, 0);
+ } else {
+ mSelectedView.setTag(uri);
+ saveCustomActions();
+ GlowBackground background = (GlowBackground) mSelectedView.getBackground();
+ background.hideGlow();
+ }
+ }
+
+ private void saveCustomActions() {
+ ArrayList<String> targets = new ArrayList<String>();
+ for (int id : sIconIds) {
+ View v = findViewById(id);
+ String uri = (String) v.getTag();
+ targets.add(uri);
+ }
+ mShortcutHelper.saveTargets(targets);
+ }
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/cm/LockscreenShortcutsHelper.java b/packages/SystemUI/src/com/android/systemui/cm/LockscreenShortcutsHelper.java
new file mode 100644
index 0000000..12b9810
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/cm/LockscreenShortcutsHelper.java
@@ -0,0 +1,196 @@
+package com.android.systemui.cm;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.database.ContentObserver;
+import android.graphics.Bitmap;
+import android.graphics.ColorFilter;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.Looper;
+
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.List;
+
+import com.android.systemui.R;
+import cyanogenmod.providers.CMSettings;
+
+public class LockscreenShortcutsHelper {
+
+ private Handler mHandler;
+
+ public enum Shortcuts {
+ LEFT_SHORTCUT(0),
+ RIGHT_SHORTCUT(1);
+
+ private final int index;
+
+ Shortcuts(int index) {
+ this.index = index;
+ }
+ }
+
+ public static final String DEFAULT = "default";
+ public static final String NONE = "none";
+ private static final String DELIMITER = "|";
+
+ private final Context mContext;
+ private OnChangeListener mListener;
+ private List<String> mTargetActivities;
+
+ public interface OnChangeListener {
+ void onChange();
+ }
+
+ public LockscreenShortcutsHelper(Context context, OnChangeListener listener) {
+ mContext = context;
+ if (listener != null) {
+ mListener = listener;
+ mHandler = new Handler(Looper.getMainLooper());
+ mContext.getContentResolver().registerContentObserver(
+ CMSettings.Secure.getUriFor(CMSettings.Secure.LOCKSCREEN_TARGETS), false, mObserver);
+ }
+ fetchTargets();
+ }
+
+ private ContentObserver mObserver = new ContentObserver(null) {
+ @Override
+ public void onChange(boolean selfChange, Uri uri) {
+ fetchTargets();
+ if (mListener != null && mHandler != null) {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ mListener.onChange();
+ }
+ });
+ }
+ }
+ };
+
+ public void cleanup() {
+ mContext.getContentResolver().unregisterContentObserver(mObserver);
+ mListener = null;
+ }
+
+ public static class TargetInfo {
+ public Drawable icon;
+ public ColorFilter colorFilter;
+ public String uri;
+ public TargetInfo(Drawable icon, ColorFilter colorFilter, String uri) {
+ this.icon = icon;
+ this.colorFilter = colorFilter;
+ this.uri = uri;
+ }
+ }
+
+ private void fetchTargets() {
+ mTargetActivities = CMSettings.Secure.getDelimitedStringAsList(mContext.getContentResolver(),
+ CMSettings.Secure.LOCKSCREEN_TARGETS, DELIMITER);
+ int itemsToPad = Shortcuts.values().length - mTargetActivities.size();
+ if (itemsToPad > 0) {
+ for (int i = 0; i < itemsToPad; i++) {
+ mTargetActivities.add(DEFAULT);
+ }
+ }
+ }
+
+ public Drawable getDrawableForTarget(Shortcuts shortcut) {
+ Intent intent = getIntent(shortcut);
+ if (intent != null) {
+ PackageManager pm = mContext.getPackageManager();
+ ActivityInfo info = intent.resolveActivityInfo(pm, PackageManager.GET_ACTIVITIES);
+ if (info != null) {
+ return getScaledDrawable(info.loadIcon(pm));
+ }
+ }
+ return null;
+ }
+
+ public String getUriForTarget(Shortcuts shortcuts) {
+ return mTargetActivities.get(shortcuts.index);
+ }
+
+ private Drawable getScaledDrawable(Drawable drawable) {
+ if (drawable instanceof BitmapDrawable) {
+ Resources res = mContext.getResources();
+ int width = res.getDimensionPixelSize(R.dimen.keyguard_affordance_icon_width);
+ int height = res.getDimensionPixelSize(R.dimen.keyguard_affordance_icon_height);
+ return new BitmapDrawable(mContext.getResources(),
+ Bitmap.createScaledBitmap(((BitmapDrawable) drawable).getBitmap(),
+ width, height, true));
+ } else {
+ return drawable;
+ }
+ }
+
+ private String getFriendlyActivityName(Intent intent, boolean labelOnly) {
+ PackageManager pm = mContext.getPackageManager();
+ ActivityInfo ai = intent.resolveActivityInfo(pm, PackageManager.GET_ACTIVITIES);
+ String friendlyName = null;
+ if (ai != null) {
+ friendlyName = ai.loadLabel(pm).toString();
+ if (friendlyName == null && !labelOnly) {
+ friendlyName = ai.name;
+ }
+ }
+ return friendlyName != null || labelOnly ? friendlyName : intent.toUri(0);
+ }
+
+ private String getFriendlyShortcutName(Intent intent) {
+ String activityName = getFriendlyActivityName(intent, true);
+ String name = intent.getStringExtra(Intent.EXTRA_SHORTCUT_NAME);
+
+ if (activityName != null && name != null) {
+ return activityName + ": " + name;
+ }
+ return name != null ? name : intent.toUri(0);
+ }
+
+ public String getFriendlyNameForUri(Shortcuts shortcut) {
+ Intent intent = getIntent(shortcut);
+ if (Intent.ACTION_MAIN.equals(intent.getAction())) {
+ return getFriendlyActivityName(intent, false);
+ }
+ return getFriendlyShortcutName(intent);
+ }
+
+ public boolean isTargetCustom(Shortcuts shortcut) {
+ if (mTargetActivities == null || mTargetActivities.isEmpty()) {
+ return false;
+ }
+ String action = mTargetActivities.get(shortcut.index);
+ if (DEFAULT.equals(action)) {
+ return false;
+ }
+
+ return NONE.equals(action) || getIntent(shortcut) != null;
+ }
+
+ public boolean isTargetEmpty(Shortcuts shortcut) {
+ return mTargetActivities != null &&
+ !mTargetActivities.isEmpty() &&
+ mTargetActivities.get(shortcut.index).equals(NONE);
+ }
+
+ public Intent getIntent(Shortcuts shortcut) {
+ Intent intent = null;
+ try {
+ intent = Intent.parseUri(mTargetActivities.get(shortcut.index), 0);
+ } catch (URISyntaxException e) {
+ e.printStackTrace();
+ }
+ return intent;
+ }
+
+ public void saveTargets(ArrayList<String> targets) {
+ CMSettings.Secure.putListAsDelimitedString(mContext.getContentResolver(),
+ CMSettings.Secure.LOCKSCREEN_TARGETS, DELIMITER, targets);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/cm/SpamMessageProvider.java b/packages/SystemUI/src/com/android/systemui/cm/SpamMessageProvider.java
new file mode 100644
index 0000000..7afa04d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/cm/SpamMessageProvider.java
@@ -0,0 +1,204 @@
+package com.android.systemui.cm;
+
+import android.content.ContentProvider;
+import android.content.ContentValues;
+import android.content.UriMatcher;
+import android.database.Cursor;
+import android.database.DatabaseUtils;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteQueryBuilder;
+import android.net.Uri;
+import android.text.TextUtils;
+
+import com.android.internal.util.cm.SpamFilter;
+import com.android.internal.util.cm.SpamFilter.SpamContract.PackageTable;
+import com.android.internal.util.cm.SpamFilter.SpamContract.NotificationTable;
+
+public class SpamMessageProvider extends ContentProvider {
+ public static final String AUTHORITY = SpamFilter.AUTHORITY;
+
+ private static final String UPDATE_COUNT_QUERY =
+ "UPDATE " + NotificationTable.TABLE_NAME +
+ " SET " + NotificationTable.LAST_BLOCKED + "=%d," +
+ NotificationTable.COUNT + "=" + NotificationTable.COUNT + "+1 " +
+ " WHERE " + NotificationTable.ID + "='%s'";
+
+ private static final UriMatcher sURIMatcher = new UriMatcher(UriMatcher.NO_MATCH);
+ private static final int PACKAGES = 0;
+ private static final int MESSAGES = 1;
+ private static final int PACKAGE_FOR_ID = 2;
+ private static final int MESSAGE_UPDATE_COUNT = 3;
+ private static final int MESSAGE_FOR_ID = 4;
+ static {
+ sURIMatcher.addURI(AUTHORITY, "packages", PACKAGES);
+ sURIMatcher.addURI(AUTHORITY, "messages", MESSAGES);
+ sURIMatcher.addURI(AUTHORITY, "message/#", MESSAGE_FOR_ID);
+ sURIMatcher.addURI(AUTHORITY, "message/inc_count/#", MESSAGE_UPDATE_COUNT);
+ }
+
+ private SpamOpenHelper mDbHelper;
+
+ @Override
+ public boolean onCreate() {
+ mDbHelper = new SpamOpenHelper(getContext());
+ return true;
+ }
+
+ @Override
+ public Cursor query(Uri uri, String[] projection, String selection,
+ String[] selectionArgs, String sortOrder) {
+ int match = sURIMatcher.match(uri);
+ switch (match) {
+ case PACKAGE_FOR_ID:
+ return mDbHelper.getReadableDatabase().query(PackageTable.TABLE_NAME,
+ new String[]{NotificationTable.ID}, PackageTable.PACKAGE_NAME + "=?",
+ new String[]{uri.getLastPathSegment()}, null, null, null);
+ case PACKAGES:
+ return mDbHelper.getReadableDatabase().query(PackageTable.TABLE_NAME,
+ projection, selection, selectionArgs, null, null, sortOrder);
+ case MESSAGES:
+ SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
+ qb.setTables(NotificationTable.TABLE_NAME + " LEFT OUTER JOIN " + PackageTable.TABLE_NAME +
+ " ON (" + NotificationTable.TABLE_NAME + "." + NotificationTable.PACKAGE_ID + " = "
+ + PackageTable.TABLE_NAME + "." + PackageTable.ID + ")");
+ SQLiteDatabase db = mDbHelper.getReadableDatabase();
+ return qb.query(db, projection, selection, selectionArgs,
+ null, null, null);
+ case MESSAGE_FOR_ID:
+ qb = new SQLiteQueryBuilder();
+ qb.setTables(NotificationTable.TABLE_NAME + " LEFT OUTER JOIN " + PackageTable.TABLE_NAME +
+ " ON (" + NotificationTable.TABLE_NAME + "." + NotificationTable.PACKAGE_ID + " = "
+ + PackageTable.TABLE_NAME + "." + PackageTable.ID + ")");
+ qb.appendWhere(NotificationTable.TABLE_NAME + "." + NotificationTable.ID + "="
+ + uri.getLastPathSegment());
+ return qb.query(mDbHelper.getReadableDatabase(),
+ null, null, null, null,
+ null, null);
+ default:
+ return null;
+ }
+ }
+
+ private long getPackageId(String pkg) {
+ long rowId = -1;
+ Cursor idCursor = mDbHelper.getReadableDatabase().query(PackageTable.TABLE_NAME,
+ new String[]{NotificationTable.ID}, PackageTable.PACKAGE_NAME + "=?",
+ new String[]{pkg}, null, null, null);
+ if (idCursor != null) {
+ if (idCursor.moveToFirst()) {
+ rowId = idCursor.getLong(0);
+ }
+ idCursor.close();
+ }
+ return rowId;
+ }
+
+ @Override
+ public String getType(Uri uri) {
+ return null;
+ }
+
+ @Override
+ public Uri insert(Uri uri, ContentValues values) {
+ if (values == null) {
+ return null;
+ }
+ int match = sURIMatcher.match(uri);
+ switch (match) {
+ case MESSAGES:
+ String msgText = values.getAsString(NotificationTable.MESSAGE_TEXT);
+ String packageName = values.getAsString(PackageTable.PACKAGE_NAME);
+ if (TextUtils.isEmpty(msgText) || TextUtils.isEmpty(packageName)) {
+ return null;
+ }
+ values.clear();
+ values.put(PackageTable.PACKAGE_NAME, packageName);
+ long packageId = getPackageId(packageName);
+ if (packageId == -1) {
+ SQLiteDatabase writableDb = mDbHelper.getWritableDatabase();
+ packageId = writableDb.insert(
+ PackageTable.TABLE_NAME, null, values);
+ }
+ if (packageId != -1) {
+ values.clear();
+ values.put(NotificationTable.MESSAGE_TEXT, msgText);
+ values.put(NotificationTable.NORMALIZED_TEXT,
+ SpamFilter.getNormalizedContent(msgText));
+ values.put(NotificationTable.PACKAGE_ID, packageId);
+ values.put(NotificationTable.LAST_BLOCKED, System.currentTimeMillis());
+ long id = mDbHelper.getReadableDatabase().insert(NotificationTable.TABLE_NAME,
+ null, values);
+ if (id != -1) {
+ notifyChange(String.valueOf(id));
+ }
+ }
+ return null;
+ default:
+ return null;
+ }
+ }
+
+ private void notifyChange(String id) {
+ Uri uri = Uri.withAppendedPath(SpamFilter.NOTIFICATION_URI,
+ id);
+ getContext().getContentResolver().notifyChange(uri, null);
+ }
+
+ private void removePackageIfNecessary(int packageId) {
+ long numEntries = DatabaseUtils.queryNumEntries(mDbHelper.getReadableDatabase(),
+ NotificationTable.TABLE_NAME, NotificationTable.PACKAGE_ID + "=?",
+ new String[]{String.valueOf(packageId)});
+ if (numEntries == 0) {
+ SQLiteDatabase writableDb = mDbHelper.getWritableDatabase();
+ writableDb.delete(PackageTable.TABLE_NAME, PackageTable.ID + "=?",
+ new String[]{String.valueOf(packageId)});
+ }
+ }
+
+ @Override
+ public int delete(Uri uri, String selection, String[] selectionArgs) {
+ int match = sURIMatcher.match(uri);
+ switch (match) {
+ case MESSAGE_FOR_ID:
+ int packageId = -1;
+ Cursor idCursor = mDbHelper.getReadableDatabase().query(NotificationTable.TABLE_NAME,
+ new String[]{NotificationTable.PACKAGE_ID}, NotificationTable.ID + "=?",
+ new String[]{uri.getLastPathSegment()}, null, null, null);
+ if (idCursor != null) {
+ if (idCursor.moveToFirst()) {
+ packageId = idCursor.getInt(0);
+ }
+ idCursor.close();
+ }
+ SQLiteDatabase writableDb = mDbHelper.getWritableDatabase();
+ String id = uri.getLastPathSegment();
+ int result = writableDb.delete(NotificationTable.TABLE_NAME,
+ NotificationTable.ID + "=?", new String[]{id});
+ removePackageIfNecessary(packageId);
+ if (result > 0) {
+ notifyChange(id);
+ }
+ return result;
+ default:
+ return 0;
+ }
+ }
+
+ @Override
+ public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
+ int match = sURIMatcher.match(uri);
+ switch (match) {
+ case MESSAGE_UPDATE_COUNT:
+ String id = uri.getLastPathSegment();
+ String formattedQuery = String.format(UPDATE_COUNT_QUERY,
+ System.currentTimeMillis(), id);
+ SQLiteDatabase writableDb = mDbHelper.getWritableDatabase();
+ writableDb.execSQL(formattedQuery);
+ notifyChange(id);
+ return 0;
+ default:
+ return 0;
+ }
+ }
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/cm/SpamOpenHelper.java b/packages/SystemUI/src/com/android/systemui/cm/SpamOpenHelper.java
new file mode 100644
index 0000000..45dc91c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/cm/SpamOpenHelper.java
@@ -0,0 +1,46 @@
+package com.android.systemui.cm;
+
+import com.android.internal.util.cm.SpamFilter.SpamContract.NotificationTable;
+import com.android.internal.util.cm.SpamFilter.SpamContract.PackageTable;
+
+import android.content.Context;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteOpenHelper;
+
+public class SpamOpenHelper extends SQLiteOpenHelper {
+
+ private static final String DATABASE_NAME = "spam.db";
+ private static final int VERSION = 4;
+ private static final String CREATE_PACKAGES_TABLE =
+ "create table " + PackageTable.TABLE_NAME + "(" +
+ PackageTable.ID + " INTEGER PRIMARY KEY," +
+ PackageTable.PACKAGE_NAME + " TEXT UNIQUE);";
+ private static final String CREATE_NOTIFICATIONS_TABLE =
+ "create table " + NotificationTable.TABLE_NAME + "(" +
+ NotificationTable.ID + " INTEGER PRIMARY KEY AUTOINCREMENT," +
+ NotificationTable.PACKAGE_ID + " INTEGER," +
+ NotificationTable.MESSAGE_TEXT + " STRING," +
+ NotificationTable.LAST_BLOCKED + " INTEGER," +
+ NotificationTable.NORMALIZED_TEXT + " STRING," +
+ NotificationTable.COUNT + " INTEGER DEFAULT 0);";
+
+ private Context mContext;
+
+ public SpamOpenHelper(Context context) {
+ super(context, DATABASE_NAME, null, VERSION);
+ mContext = context;
+ }
+
+ @Override
+ public void onCreate(SQLiteDatabase db) {
+ db.execSQL(CREATE_PACKAGES_TABLE);
+ db.execSQL(CREATE_NOTIFICATIONS_TABLE);
+ }
+
+ @Override
+ public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+ mContext.deleteDatabase(DATABASE_NAME);
+ onCreate(db);
+ }
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/cm/UserContentObserver.java b/packages/SystemUI/src/com/android/systemui/cm/UserContentObserver.java
new file mode 100644
index 0000000..5ece744
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/cm/UserContentObserver.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2014 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 com.android.systemui.cm;
+
+import android.app.ActivityManagerNative;
+import android.app.IUserSwitchObserver;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.IRemoteCallback;
+import android.os.RemoteException;
+import android.util.Log;
+
+/**
+ * Simple extension of ContentObserver that also listens for user switch events to call update
+ */
+public abstract class UserContentObserver extends ContentObserver {
+ private static final String TAG = "UserContentObserver";
+
+ private Runnable mUpdateRunnable;
+
+ private IUserSwitchObserver mUserSwitchObserver = new IUserSwitchObserver.Stub() {
+ @Override
+ public void onUserSwitching(int newUserId, IRemoteCallback reply) {
+ }
+ @Override
+ public void onUserSwitchComplete(int newUserId) throws RemoteException {
+ mHandler.post(mUpdateRunnable);
+ }
+ @Override
+ public void onForegroundProfileSwitch(int newProfileId) {
+ }
+ };
+
+ private Handler mHandler;
+
+ public UserContentObserver(Handler handler) {
+ super(handler);
+ mHandler = handler;
+ mUpdateRunnable = new Runnable() {
+ @Override
+ public void run() {
+ update();
+ }
+ };
+ }
+
+ protected void observe() {
+ try {
+ ActivityManagerNative.getDefault().registerUserSwitchObserver(mUserSwitchObserver);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Unable to register user switch observer!", e);
+ }
+ }
+
+ protected void unobserve() {
+ try {
+ mHandler.removeCallbacks(mUpdateRunnable);
+ ActivityManagerNative.getDefault().unregisterUserSwitchObserver(mUserSwitchObserver);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Unable to unregister user switch observer!", e);
+ }
+ }
+
+ protected abstract void update();
+
+ @Override
+ public void onChange(boolean selfChange) {
+ update();
+ }
+
+ @Override
+ public void onChange(boolean selfChange, Uri uri) {
+ update();
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
index 39423f2..f223400 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
@@ -218,7 +218,7 @@ public class DozeService extends DreamService {
// Here we need a wakelock to stay awake until the pulse is finished.
mWakeLock.acquire();
mPulsing = true;
- if (!mDozeParameters.getProxCheckBeforePulse()) {
+ if (!mDozeParameters.getProxCheckBeforePulse(reason)) {
// skip proximity check
continuePulsing(reason);
return;
@@ -265,6 +265,7 @@ public class DozeService extends DreamService {
@Override
public void onPulseStarted() {
if (mPulsing && mDreaming) {
+ mContext.sendBroadcast(new Intent(Intent.ACTION_DOZE_PULSE_STARTING));
turnDisplayOn();
}
}
@@ -356,7 +357,7 @@ public class DozeService extends DreamService {
if (DEBUG) Log.d(mTag, "No more schedule resets remaining");
return;
}
- final long pulseDuration = mDozeParameters.getPulseDuration(false /*pickup*/);
+ final long pulseDuration = mDozeParameters.getPulseDuration(DozeLog.PULSE_REASON_NOTIFICATION);
boolean pulseImmediately = System.currentTimeMillis() >= notificationTimeMs;
if ((notificationTimeMs - mLastScheduleResetTime) >= pulseDuration) {
mScheduleResetsRemaining--;
diff --git a/packages/SystemUI/src/com/android/systemui/egg/CMLand.java b/packages/SystemUI/src/com/android/systemui/egg/CMLand.java
new file mode 100644
index 0000000..6020b45
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/egg/CMLand.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2014-2015 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 com.android.systemui.egg;
+
+import com.android.systemui.R;
+
+import android.content.Context;
+import android.util.AttributeSet;
+
+public class CMLand extends MLand {
+ public static final String TAG = "CMLand";
+
+ public CMLand(Context context) {
+ this(context, null);
+ }
+
+ public CMLand(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public CMLand(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ }
+
+ @Override
+ protected int getEggPlayer() {
+ return R.drawable.cid;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/egg/MLand.java b/packages/SystemUI/src/com/android/systemui/egg/MLand.java
index b84777b..1b22e04 100644
--- a/packages/SystemUI/src/com/android/systemui/egg/MLand.java
+++ b/packages/SystemUI/src/com/android/systemui/egg/MLand.java
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2015 The Android Open Source Project
+ * Copyright (C) 2014-2015 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.
@@ -210,6 +211,8 @@ public class MLand extends FrameLayout {
// we assume everything will be laid out left|top
setLayoutDirection(LAYOUT_DIRECTION_LTR);
+ Player.eggPlayer = getEggPlayer();
+
setupPlayers(DEFAULT_PLAYERS);
MetricsLogger.count(getContext(), "egg_mland_create", 1);
@@ -1007,7 +1010,7 @@ public class MLand extends FrameLayout {
public void step(long t_ms, long dt_ms, float t, float dt);
}
- private static class Player extends ImageView implements GameView {
+ protected static class Player extends ImageView implements GameView {
public float dv;
public int color;
private MLand mLand;
@@ -1017,6 +1020,8 @@ public class MLand extends FrameLayout {
private int mScore;
private TextView mScoreField;
+ protected static int eggPlayer;
+
private final int[] sColors = new int[] {
//0xFF78C557,
0xFFDB4437,
@@ -1088,7 +1093,7 @@ public class MLand extends FrameLayout {
public Player(Context context) {
super(context);
- setBackgroundResource(R.drawable.android);
+ setBackgroundResource(eggPlayer);
getBackground().setTintMode(PorterDuff.Mode.SRC_ATOP);
color = sColors[(sNextColor++%sColors.length)];
getBackground().setTint(color);
@@ -1438,4 +1443,8 @@ public class MLand extends FrameLayout {
v = z = 0;
}
}
+
+ protected int getEggPlayer() {
+ return R.drawable.android;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/egg/MLandActivity.java b/packages/SystemUI/src/com/android/systemui/egg/MLandActivity.java
index cdda45f..6fd7387 100644
--- a/packages/SystemUI/src/com/android/systemui/egg/MLandActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/egg/MLandActivity.java
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2015 The Android Open Source Project
+ * Copyright (C) 2014-2015 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.
@@ -29,7 +30,14 @@ public class MLandActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- setContentView(R.layout.mland);
+ final boolean isCM = getIntent().getBooleanExtra("is_cm", false);
+ if (isCM) {
+ setContentView(R.layout.cmland);
+ mLand = (CMLand) findViewById(R.id.world);
+ } else {
+ setContentView(R.layout.mland);
+ mLand = (MLand) findViewById(R.id.world);
+ }
mLand = (MLand) findViewById(R.id.world);
mLand.setScoreFieldHolder((ViewGroup) findViewById(R.id.scores));
final View welcome = findViewById(R.id.welcome);
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 055b5ef..fbd8dac 100644..100755
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -56,6 +56,9 @@ import android.view.WindowManagerPolicy;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
+import cyanogenmod.app.Profile;
+import cyanogenmod.app.ProfileManager;
+
import com.android.internal.policy.IKeyguardDrawnCallback;
import com.android.internal.policy.IKeyguardExitCallback;
import com.android.internal.policy.IKeyguardStateCallback;
@@ -135,6 +138,9 @@ public class KeyguardViewMediator extends SystemUI {
private static final String DELAYED_KEYGUARD_ACTION =
"com.android.internal.policy.impl.PhoneWindowManager.DELAYED_KEYGUARD";
+ private static final String DISMISS_KEYGUARD_SECURELY_ACTION =
+ "com.android.keyguard.action.DISMISS_KEYGUARD_SECURELY";
+
// used for handler messages
private static final int SHOW = 2;
private static final int HIDE = 3;
@@ -187,7 +193,7 @@ public class KeyguardViewMediator extends SystemUI {
private AudioManager mAudioManager;
private StatusBarManager mStatusBarManager;
private boolean mSwitchingUser;
-
+ private ProfileManager mProfileManager;
private boolean mSystemReady;
private boolean mBootCompleted;
private boolean mBootSendUserPresent;
@@ -555,8 +561,10 @@ public class KeyguardViewMediator extends SystemUI {
mShowKeyguardWakeLock = mPM.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "show keyguard");
mShowKeyguardWakeLock.setReferenceCounted(false);
-
+ mProfileManager = ProfileManager.getInstance(mContext);
mContext.registerReceiver(mBroadcastReceiver, new IntentFilter(DELAYED_KEYGUARD_ACTION));
+ mContext.registerReceiver(mBroadcastReceiver, new IntentFilter(DISMISS_KEYGUARD_SECURELY_ACTION),
+ android.Manifest.permission.CONTROL_KEYGUARD, null);
mKeyguardDisplayManager = new KeyguardDisplayManager(mContext);
@@ -793,7 +801,7 @@ public class KeyguardViewMediator extends SystemUI {
}
private void maybeSendUserPresentBroadcast() {
- if (mSystemReady && mLockPatternUtils.isLockScreenDisabled(
+ if (mSystemReady && isKeyguardDisabled(
KeyguardUpdateMonitor.getCurrentUser())) {
// Lock screen is disabled because the user has set the preference to "None".
// In this case, send out ACTION_USER_PRESENT here instead of in
@@ -802,6 +810,25 @@ public class KeyguardViewMediator extends SystemUI {
}
}
+ private boolean isKeyguardDisabled(int userId) {
+ if (!mExternallyEnabled) {
+ if (DEBUG) Log.d(TAG, "isKeyguardDisabled: keyguard is disabled externally");
+ return true;
+ }
+ if (mLockPatternUtils.isLockScreenDisabled(userId)) {
+ if (DEBUG) Log.d(TAG, "isKeyguardDisabled: keyguard is disabled by setting");
+ return true;
+ }
+ Profile profile = mProfileManager.getActiveProfile();
+ if (profile != null) {
+ if (profile.getScreenLockMode().getValue() == Profile.LockMode.DISABLE) {
+ if (DEBUG) Log.d(TAG, "isKeyguardDisabled: keyguard is disabled by profile");
+ return true;
+ }
+ }
+ return false;
+ }
+
/**
* A dream started. We should lock after the usual screen-off lock timeout but only
* if there is a secure lock pattern.
@@ -1066,7 +1093,7 @@ public class KeyguardViewMediator extends SystemUI {
return;
}
- if (mLockPatternUtils.isLockScreenDisabled(KeyguardUpdateMonitor.getCurrentUser())
+ if (isKeyguardDisabled(KeyguardUpdateMonitor.getCurrentUser())
&& !lockedOrMissing) {
if (DEBUG) Log.d(TAG, "doKeyguard: not showing because lockscreen is off");
return;
@@ -1203,6 +1230,10 @@ public class KeyguardViewMediator extends SystemUI {
doKeyguardLocked(null);
}
}
+ } else if (DISMISS_KEYGUARD_SECURELY_ACTION.equals(intent.getAction())) {
+ synchronized (KeyguardViewMediator.this) {
+ dismiss();
+ }
}
}
};
@@ -1437,7 +1468,8 @@ public class KeyguardViewMediator extends SystemUI {
ActivityManagerNative.getDefault().keyguardGoingAway(
mStatusBarKeyguardViewManager.shouldDisableWindowAnimationsForUnlock()
|| mWakeAndUnlocking,
- mStatusBarKeyguardViewManager.isGoingToNotificationShade());
+ mStatusBarKeyguardViewManager.isGoingToNotificationShade(),
+ mStatusBarKeyguardViewManager.isKeyguardShowingMedia());
} catch (RemoteException e) {
Log.e(TAG, "Error while calling WindowManager", e);
}
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
index 9459740..a1a11ca 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
@@ -16,23 +16,30 @@
package com.android.systemui.power;
+import android.app.Notification;
+import android.app.NotificationManager;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.database.ContentObserver;
+import android.media.Ringtone;
+import android.media.RingtoneManager;
+import android.net.Uri;
import android.os.BatteryManager;
import android.os.Handler;
import android.os.PowerManager;
import android.os.SystemClock;
import android.os.UserHandle;
+import android.os.Vibrator;
import android.provider.Settings;
import android.util.Log;
import android.util.Slog;
import com.android.systemui.SystemUI;
import com.android.systemui.statusbar.phone.PhoneStatusBar;
+import cyanogenmod.providers.CMSettings;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -57,6 +64,9 @@ public class PowerUI extends SystemUI {
private long mScreenOffTime = -1;
+ // For filtering ACTION_POWER_DISCONNECTED on boot
+ boolean mIgnoreFirstPowerEvent = true;
+
public void start() {
mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
mScreenOffTime = mPowerManager.isScreenOn() ? -1 : SystemClock.elapsedRealtime();
@@ -140,6 +150,8 @@ public class PowerUI extends SystemUI {
filter.addAction(Intent.ACTION_USER_SWITCHED);
filter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGING);
filter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED);
+ filter.addAction(Intent.ACTION_POWER_CONNECTED);
+ filter.addAction(Intent.ACTION_POWER_DISCONNECTED);
mContext.registerReceiver(this, filter, null, mHandler);
updateSaverMode();
}
@@ -165,6 +177,10 @@ public class PowerUI extends SystemUI {
final boolean plugged = mPlugType != 0;
final boolean oldPlugged = oldPlugType != 0;
+ if (mIgnoreFirstPowerEvent && plugged) {
+ mIgnoreFirstPowerEvent = false;
+ }
+
int oldBucket = findBatteryLevelBucket(oldBatteryLevel);
int bucket = findBatteryLevelBucket(mBatteryLevel);
@@ -214,12 +230,44 @@ public class PowerUI extends SystemUI {
updateSaverMode();
} else if (PowerManager.ACTION_POWER_SAVE_MODE_CHANGING.equals(action)) {
setSaverMode(intent.getBooleanExtra(PowerManager.EXTRA_POWER_SAVE_MODE, false));
+ } else if (Intent.ACTION_POWER_CONNECTED.equals(action)
+ || Intent.ACTION_POWER_DISCONNECTED.equals(action)) {
+ final ContentResolver cr = mContext.getContentResolver();
+
+ if (mIgnoreFirstPowerEvent) {
+ mIgnoreFirstPowerEvent = false;
+ } else {
+ if (CMSettings.Global.getInt(cr,
+ CMSettings.Global.POWER_NOTIFICATIONS_ENABLED, 0) == 1) {
+ playPowerNotificationSound();
+ }
+ }
} else {
Slog.w(TAG, "unknown intent: " + intent);
}
}
};
+ void playPowerNotificationSound() {
+ final ContentResolver cr = mContext.getContentResolver();
+ final String soundPath =
+ CMSettings.Global.getString(cr, CMSettings.Global.POWER_NOTIFICATIONS_RINGTONE);
+
+ if (soundPath != null) {
+ Ringtone powerRingtone = RingtoneManager.getRingtone(mContext, Uri.parse(soundPath));
+ if (powerRingtone != null) {
+ powerRingtone.play();
+ }
+ }
+ if (CMSettings.Global.getInt(cr,
+ CMSettings.Global.POWER_NOTIFICATIONS_VIBRATE, 0) == 1) {
+ Vibrator vibrator = (Vibrator) mContext.getSystemService(Context.VIBRATOR_SERVICE);
+ if (vibrator != null) {
+ vibrator.vibrate(250);
+ }
+ }
+ }
+
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
pw.print("mLowBatteryAlertCloseLevel=");
pw.println(mLowBatteryAlertCloseLevel);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSBooleanSettingRow.java b/packages/SystemUI/src/com/android/systemui/qs/QSBooleanSettingRow.java
new file mode 100644
index 0000000..ca0783e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSBooleanSettingRow.java
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2015 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 com.android.systemui.qs;
+
+import android.annotation.Nullable;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.provider.Settings;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.View;
+import android.widget.CompoundButton;
+import android.widget.LinearLayout;
+import android.widget.Switch;
+import android.widget.TextView;
+
+import com.android.systemui.R;
+import cyanogenmod.providers.CMSettings;
+
+public class QSBooleanSettingRow extends LinearLayout implements View.OnClickListener {
+
+ private static final String TAG = "QSSettingRow";
+
+ public static final int TABLE_SYSTEM = 0;
+ public static final int TABLE_GLOBAL = 1;
+ public static final int TABLE_SECURE = 2;
+
+ public static final int TABLE_CM_SYSTEM = 3;
+ public static final int TABLE_CM_GLOBAL = 4;
+ public static final int TABLE_CM_SECURE = 5;
+
+ int mWhichTable;
+ String mTitle;
+ String mKey;
+ private TextView mText;
+ private Switch mSwitch;
+
+ public QSBooleanSettingRow(Context context) {
+ this(context, null);
+ }
+
+ public QSBooleanSettingRow(Context context, @Nullable AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public QSBooleanSettingRow(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
+ this(context, attrs, defStyleAttr, 0);
+ }
+
+ public QSBooleanSettingRow(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ View.inflate(context, R.layout.qs_settings_row, this);
+
+ setOrientation(HORIZONTAL);
+ setClickable(true);
+ setOnClickListener(this);
+
+ mText = (TextView) findViewById(R.id.title);
+ mSwitch = (Switch) findViewById(R.id.switcher);
+
+ TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.QuickSettingsRow,
+ defStyleAttr, defStyleRes);
+
+ mWhichTable = a.getInteger(R.styleable.QuickSettingsRow_table, -1);
+
+ mTitle = a.getString(R.styleable.QuickSettingsRow_android_title);
+ mKey = a.getString(R.styleable.QuickSettingsRow_android_key);
+
+ if (mText != null) {
+ mText.setText(mTitle);
+ mText.setClickable(false);
+ mText.setFocusable(false);
+ }
+
+ if (mSwitch != null) {
+ mSwitch.setClickable(false);
+ mSwitch.setFocusable(false);
+ mSwitch.setChecked(getCurrent());
+ mSwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
+ @Override
+ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+ if (false) Log.d(TAG, "onCheckedChanged() called with "
+ + "buttonView = [" + buttonView + "], isChecked = [" + isChecked
+ + "] and table: " + mWhichTable + ", and key: " + mKey);
+ applyChange(isChecked);
+ }
+ });
+ }
+
+ a.recycle();
+ }
+
+ private void applyChange(boolean value) {
+ ContentResolver cr = getContext().getContentResolver();
+ switch (mWhichTable) {
+ case TABLE_GLOBAL:
+ Settings.Global.putInt(cr, mKey, value ? 1 : 0);
+ break;
+ case TABLE_SECURE:
+ Settings.Secure.putInt(cr, mKey, value ? 1 : 0);
+ break;
+ case TABLE_SYSTEM:
+ Settings.System.putInt(cr, mKey, value ? 1 : 0);
+ break;
+ case TABLE_CM_GLOBAL:
+ CMSettings.Global.putInt(cr, mKey, value ? 1 : 0);
+ break;
+ case TABLE_CM_SECURE:
+ CMSettings.Secure.putInt(cr, mKey, value ? 1 : 0);
+ break;
+ case TABLE_CM_SYSTEM:
+ CMSettings.System.putInt(cr, mKey, value ? 1 : 0);
+ break;
+ }
+ }
+
+ private boolean getCurrent() {
+ ContentResolver cr = getContext().getContentResolver();
+ int ret = 0;
+ try {
+ switch (mWhichTable) {
+ case TABLE_GLOBAL:
+ ret = Settings.Global.getInt(cr, mKey);
+ break;
+ case TABLE_SECURE:
+ ret = Settings.Secure.getInt(cr, mKey);
+ break;
+ case TABLE_SYSTEM:
+ ret = Settings.System.getInt(cr, mKey);
+ break;
+ case TABLE_CM_GLOBAL:
+ ret = CMSettings.Global.getInt(cr, mKey);
+ break;
+ case TABLE_CM_SECURE:
+ ret = CMSettings.Secure.getInt(cr, mKey);
+ break;
+ case TABLE_CM_SYSTEM:
+ ret = CMSettings.System.getInt(cr, mKey);
+ break;
+ }
+ } catch (Settings.SettingNotFoundException|CMSettings.CMSettingNotFoundException e) {
+ Log.e(TAG, "need to add a default setting for key: " + mKey
+ + " in table: " + mWhichTable);
+ e.printStackTrace();
+ }
+ return ret == 1;
+ }
+
+ @Override
+ public void onClick(View v) {
+ mSwitch.setChecked(!mSwitch.isChecked());
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSContainer.java b/packages/SystemUI/src/com/android/systemui/qs/QSContainer.java
index cfe8d07..74f4cbb 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSContainer.java
@@ -63,7 +63,7 @@ public class QSContainer extends FrameLayout {
*/
public int getDesiredHeight() {
if (mQSPanel.isClosingDetail()) {
- return mQSPanel.getGridHeight() + getPaddingTop() + getPaddingBottom();
+ return mQSPanel.getGridHeight() + getPaddingBottom();
} else {
return getMeasuredHeight();
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSDetailClipper.java b/packages/SystemUI/src/com/android/systemui/qs/QSDetailClipper.java
index a318efc..8b89a65 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSDetailClipper.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSDetailClipper.java
@@ -36,6 +36,10 @@ public class QSDetailClipper {
mBackground = (TransitionDrawable) detail.getBackground();
}
+ public boolean isAnimating() {
+ return mAnimator != null && mAnimator.isRunning();
+ }
+
public void animateCircularClip(int x, int y, boolean in, AnimatorListener listener) {
if (mAnimator != null) {
mAnimator.cancel();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSDetailItemsGrid.java b/packages/SystemUI/src/com/android/systemui/qs/QSDetailItemsGrid.java
new file mode 100644
index 0000000..07e01e4
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSDetailItemsGrid.java
@@ -0,0 +1,154 @@
+/**
+ * Copyright (c) 2015, 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 com.android.systemui.qs;
+
+import android.content.Context;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+
+import android.widget.BaseAdapter;
+
+import cyanogenmod.app.CustomTile;
+
+import com.android.systemui.qs.tiles.UserDetailItemView;
+import com.android.systemui.R;
+
+/**
+ * Quick settings common detail grid view with circular items.
+ */
+public class QSDetailItemsGrid extends PseudoGridView {
+ private static final String TAG = "QSDetailItemsGrid";
+ private QSDetailItemsGridAdapter mDetailItemsGridAdapter;
+
+ public QSDetailItemsGrid(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public static QSDetailItemsGrid inflate(Context context, ViewGroup parent, boolean attach) {
+ return (QSDetailItemsGrid) LayoutInflater.from(context).inflate(
+ R.layout.qs_detail_items_grid, parent, attach);
+ }
+
+ public QSDetailItemsGridAdapter createAndSetAdapter(String externalPackage,
+ CustomTile.ExpandedItem[] items) {
+ mDetailItemsGridAdapter = new QSDetailItemsGridAdapter(externalPackage, mContext, items);
+ ViewGroupAdapterBridge.link(this, mDetailItemsGridAdapter);
+ return mDetailItemsGridAdapter;
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ setOnTouchListener(new OnTouchListener() {
+ // Setting on Touch Listener for handling the touch inside ScrollView
+ @Override
+ public boolean onTouch(View v, MotionEvent event) {
+ // Disallow the touch request for parent scroll on touch of child view
+ v.getParent().requestDisallowInterceptTouchEvent(true);
+ return false;
+ }
+ });
+ }
+
+ public static class QSDetailItemsGridAdapter extends BaseAdapter implements OnClickListener {
+ private String mPkg;
+ private Context mContext;
+ private CustomTile.ExpandedItem[] mItems;
+ private OnPseudoGriditemClickListener mOnPseudoGridItemClickListener;
+
+ public interface OnPseudoGriditemClickListener {
+ void onPsuedoGridItemClick(View view, CustomTile.ExpandedItem item);
+ }
+
+ public QSDetailItemsGridAdapter(String packageName,
+ Context context, CustomTile.ExpandedItem[] items) {
+ mPkg = packageName;
+ mContext = context;
+ mItems = items;
+ }
+
+ public void setOnPseudoGridItemClickListener(OnPseudoGriditemClickListener
+ onPseudoGridItemClickListener) {
+ mOnPseudoGridItemClickListener = onPseudoGridItemClickListener;
+ }
+
+ @Override
+ public int getCount() {
+ return mItems.length;
+ }
+
+ @Override
+ public CustomTile.ExpandedItem getItem(int position) {
+ return mItems[position];
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return position;
+ }
+
+ @Override
+ public View getView(int i, View convertView, ViewGroup parent) {
+ UserDetailItemView v = UserDetailItemView.convertOrInflate(
+ mContext, convertView, parent);
+ CustomTile.ExpandedItem item = getItem(i);
+ Drawable d = null;
+ if (item.itemDrawableResourceId != 0 && item.itemBitmapResource == null) {
+ try {
+ d = getPackageContext(mPkg, mContext).getResources()
+ .getDrawable(item.itemDrawableResourceId);
+ } catch (Throwable t) {
+ Log.w(TAG, "Error creating package context" + mPkg +
+ " id=" + item.itemDrawableResourceId, t);
+ }
+ } else {
+ d = new BitmapDrawable(mContext.getResources(), item.itemBitmapResource);
+ }
+ if (v != convertView) {
+ v.setOnClickListener(this);
+ }
+ String name = item.itemTitle;
+ v.setActivated(true);
+ v.bind(name, d);
+ v.setTag(item);
+ return v;
+ }
+
+ @Override
+ public void onClick(View view) {
+ CustomTile.ExpandedItem item = (CustomTile.ExpandedItem) view.getTag();
+ mOnPseudoGridItemClickListener.onPsuedoGridItemClick(view, item);
+ }
+ }
+
+ private static Context getPackageContext(String pkg, Context context) {
+ Context packageContext;
+ try {
+ packageContext = context.createPackageContext(pkg, 0);
+ } catch (Throwable t) {
+ Log.w(TAG, "Error creating package context" + pkg, t);
+ return null;
+ }
+ return packageContext;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSDetailItemsList.java b/packages/SystemUI/src/com/android/systemui/qs/QSDetailItemsList.java
new file mode 100644
index 0000000..794af49
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSDetailItemsList.java
@@ -0,0 +1,214 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs;
+
+import android.content.Context;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.text.TextUtils;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.ListAdapter;
+import android.widget.ListView;
+
+import android.widget.TextView;
+import com.android.systemui.R;
+
+import cyanogenmod.app.CustomTile;
+
+import java.util.List;
+
+/**
+ * Quick settings common detail list view with line items.
+ */
+public class QSDetailItemsList extends LinearLayout {
+ private static final String TAG = "QSDetailItemsList";
+
+ private ListView mListView;
+ private View mEmpty;
+ private TextView mEmptyText;
+ private ImageView mEmptyIcon;
+
+ public QSDetailItemsList(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ mContext = context;
+ mTag = TAG;
+ }
+
+ public static QSDetailItemsList convertOrInflate(Context context,
+ View convertView, ViewGroup parent) {
+ if (convertView instanceof QSDetailItemsList) {
+ return (QSDetailItemsList) convertView;
+ }
+ LayoutInflater inflater = LayoutInflater.from(context);
+ return (QSDetailItemsList) inflater.inflate(R.layout.qs_detail_items_list, parent, false);
+ }
+
+ public void setAdapter(ListAdapter adapter) {
+ mListView.setAdapter(adapter);
+ }
+
+ public ListView getListView() {
+ return mListView;
+ }
+
+ public void setEmptyState(int icon, int text) {
+ mEmptyIcon.setImageResource(icon);
+ mEmptyText.setText(text);
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ mListView = (ListView) findViewById(android.R.id.list);
+ mListView.setOnTouchListener(new OnTouchListener() {
+ // Setting on Touch Listener for handling the touch inside ScrollView
+ @Override
+ public boolean onTouch(View v, MotionEvent event) {
+ // Disallow the touch request for parent scroll on touch of child view
+ v.getParent().requestDisallowInterceptTouchEvent(true);
+ return false;
+ }
+ });
+ mEmpty = findViewById(android.R.id.empty);
+ mEmpty.setVisibility(GONE);
+ mEmptyText = (TextView) mEmpty.findViewById(android.R.id.title);
+ mEmptyIcon = (ImageView) mEmpty.findViewById(android.R.id.icon);
+ mListView.setEmptyView(mEmpty);
+ }
+
+ public static class QSCustomDetailListAdapter extends ArrayAdapter<CustomTile.ExpandedItem> {
+ private String mPackage;
+
+ public QSCustomDetailListAdapter(String externalPackage, Context context,
+ List<CustomTile.ExpandedItem> objects) {
+ super(context, R.layout.qs_detail_item, objects);
+ mPackage = externalPackage;
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ LayoutInflater inflater = LayoutInflater.from(getContext());
+ LinearLayout view = (LinearLayout) inflater.inflate(
+ R.layout.qs_detail_item, parent, false);
+
+ view.setClickable(false); // let list view handle this
+
+ final CustomTile.ExpandedItem item = getItem(position);
+ Drawable d = null;
+ if (item.itemDrawableResourceId != 0 && item.itemBitmapResource == null) {
+ try {
+ d = getPackageContext(mPackage, getContext()).getResources()
+ .getDrawable(item.itemDrawableResourceId);
+ } catch (Throwable t) {
+ Log.w(TAG, "Error creating package context" + mPackage +
+ " id=" + item.itemDrawableResourceId, t);
+ }
+ } else {
+ d = new BitmapDrawable(getContext().getResources(), item.itemBitmapResource);
+ }
+ final ImageView iv = (ImageView) view.findViewById(android.R.id.icon);
+ iv.setImageDrawable(d);
+ iv.getOverlay().clear();
+ //TODO: hide icon for the time being until the API supports granular item manipulation
+ final ImageView iv2 = (ImageView) view.findViewById(android.R.id.icon2);
+ iv2.setVisibility(View.GONE);
+ final TextView title = (TextView) view.findViewById(android.R.id.title);
+ title.setText(item.itemTitle);
+ final TextView summary = (TextView) view.findViewById(android.R.id.summary);
+ final boolean twoLines = !TextUtils.isEmpty(item.itemSummary);
+ title.setMaxLines(twoLines ? 1 : 2);
+ summary.setVisibility(twoLines ? VISIBLE : GONE);
+ summary.setText(twoLines ? item.itemSummary : null);
+ view.setMinimumHeight(getContext().getResources().getDimensionPixelSize(
+ twoLines ? R.dimen.qs_detail_item_height_twoline
+ : R.dimen.qs_detail_item_height));
+ return view;
+ }
+ }
+
+ private static Context getPackageContext(String pkg, Context context) {
+ Context packageContext;
+ try {
+ packageContext = context.createPackageContext(pkg, 0);
+ } catch (Throwable t) {
+ Log.w(TAG, "Error creating package context" + pkg, t);
+ return null;
+ }
+ return packageContext;
+ }
+
+ public static class QSDetailListAdapter extends ArrayAdapter<QSDetailItems.Item> {
+ private QSDetailItems.Callback mCallback;
+
+ public QSDetailListAdapter(Context context, List<QSDetailItems.Item> objects) {
+ super(context, R.layout.qs_detail_item, objects);
+ }
+
+ public void setCallback(QSDetailItems.Callback cb) {
+ mCallback = cb;
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ LayoutInflater inflater = LayoutInflater.from(getContext());
+ LinearLayout view = (LinearLayout) inflater.inflate(
+ R.layout.qs_detail_item, parent, false);
+
+ view.setClickable(false); // let list view handle this
+
+ final QSDetailItems.Item item = getItem(position);
+
+ final ImageView iv = (ImageView) view.findViewById(android.R.id.icon);
+ iv.setImageResource(item.icon);
+ iv.getOverlay().clear();
+ if (item.overlay != null) {
+ item.overlay.setBounds(0, 0, item.overlay.getIntrinsicWidth(),
+ item.overlay.getIntrinsicHeight());
+ iv.getOverlay().add(item.overlay);
+ }
+ final TextView title = (TextView) view.findViewById(android.R.id.title);
+ title.setText(item.line1);
+ final TextView summary = (TextView) view.findViewById(android.R.id.summary);
+ final boolean twoLines = !TextUtils.isEmpty(item.line2);
+ title.setMaxLines(twoLines ? 1 : 2);
+ summary.setVisibility(twoLines ? VISIBLE : GONE);
+ summary.setText(twoLines ? item.line2 : null);
+ view.setMinimumHeight(getContext().getResources().getDimensionPixelSize(
+ twoLines ? R.dimen.qs_detail_item_height_twoline : R.dimen.qs_detail_item_height));
+
+ final ImageView disconnect = (ImageView) view.findViewById(android.R.id.icon2);
+ disconnect.setVisibility(item.canDisconnect ? VISIBLE : GONE);
+ disconnect.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ if (mCallback != null) {
+ mCallback.onDetailItemDisconnect(item);
+ }
+ }
+ });
+ return view;
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSDragPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSDragPanel.java
new file mode 100644
index 0000000..5e62858
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSDragPanel.java
@@ -0,0 +1,1705 @@
+/*
+ * Copyright (C) 2015 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 com.android.systemui.qs;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.app.ActivityManager;
+import android.app.AlertDialog;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.res.Resources;
+import android.content.res.Configuration;
+import android.graphics.Canvas;
+import android.graphics.PointF;
+import android.graphics.drawable.Drawable;
+import android.os.Handler;
+import android.os.UserHandle;
+import android.support.v4.view.PagerAdapter;
+import android.support.v4.view.ViewPager;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.DragEvent;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewTreeObserver;
+import android.widget.EditText;
+import android.widget.ImageView;
+import android.widget.TextView;
+import com.android.internal.logging.MetricsLogger;
+import com.android.systemui.FontSizeUtils;
+import com.android.systemui.R;
+import com.android.systemui.cm.UserContentObserver;
+import com.android.systemui.qs.tiles.EditTile;
+import com.android.systemui.qs.tiles.IntentTile;
+import com.android.systemui.settings.BrightnessController;
+import com.android.systemui.settings.ToggleSlider;
+import com.android.systemui.statusbar.phone.QSTileHost;
+import com.android.systemui.statusbar.phone.SystemUIDialog;
+import com.android.systemui.statusbar.policy.BrightnessMirrorController;
+import com.android.systemui.tuner.QsTuner;
+
+import com.viewpagerindicator.CirclePageIndicator;
+import cyanogenmod.providers.CMSettings;
+
+import cyanogenmod.app.StatusBarPanelCustomTile;
+import cyanogenmod.providers.CMSettings;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+public class QSDragPanel extends QSPanel implements View.OnDragListener, View.OnLongClickListener {
+
+ private static final String TAG = "QSDragPanel";
+
+ public static final boolean DEBUG_DRAG = false;
+ private static final int INITIAL_OFFSCREEN_PAGE_LIMIT = 3;
+
+ protected final ArrayList<QSPage> mPages = new ArrayList<>();
+
+ protected QSViewPager mViewPager;
+ protected PagerAdapter mPagerAdapter;
+ QSPanelTopView mQsPanelTop;
+ CirclePageIndicator mPageIndicator;
+
+ private TextView mDetailRemoveButton;
+ private DragTileRecord mDraggingRecord;
+ private boolean mEditing;
+ private boolean mDragging;
+ private float mLastTouchLocationX, mLastTouchLocationY;
+ private int mLocationHits;
+ private int mLastLeftShift = -1;
+ private int mLastRightShift = -1;
+ private boolean mRestored;
+ private boolean mRestoring;
+ // whether the current view we are dragging in has shifted tiles
+ private boolean mMovedByLocation = false;
+
+ protected boolean mFirstRowLarge = true;
+ private SettingsObserver mSettingsObserver;
+
+ List<TileRecord> mCurrentlyAnimating
+ = Collections.synchronizedList(new ArrayList<TileRecord>());
+ private Collection<QSTile<?>> mTempTiles = null;
+
+ public QSDragPanel(Context context) {
+ this(context, null);
+ }
+
+ public QSDragPanel(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @Override
+ protected void setupViews() {
+ updateResources();
+
+ mDetail = LayoutInflater.from(mContext).inflate(R.layout.qs_detail, this, false);
+ mDetailContent = (ViewGroup) mDetail.findViewById(android.R.id.content);
+ mDetailRemoveButton = (TextView) mDetail.findViewById(android.R.id.button3);
+ mDetailSettingsButton = (TextView) mDetail.findViewById(android.R.id.button2);
+ mDetailDoneButton = (TextView) mDetail.findViewById(android.R.id.button1);
+ updateDetailText();
+ mDetail.setVisibility(GONE);
+ mDetail.setClickable(true);
+
+ mQsPanelTop = (QSPanelTopView) LayoutInflater.from(mContext).inflate(R.layout.qs_tile_top, this, false);
+
+ mBrightnessView = mQsPanelTop.getBrightnessView();
+ mFooter = new QSFooter(this, mContext);
+
+ getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
+ @Override
+ public void onGlobalLayout() {
+ getViewTreeObserver().removeOnGlobalLayoutListener(this);
+
+ ViewPager.LayoutParams params = new ViewPager.LayoutParams();
+ params.isDecor = true;
+
+ mViewPager.addView(mQsPanelTop, params);
+
+ mQsPanelTop.setOnDragListener(QSDragPanel.this);
+ mPageIndicator.setOnDragListener(QSDragPanel.this);
+ mViewPager.setOnDragListener(QSDragPanel.this);
+ }
+ });
+
+ // add target click listener
+ mQsPanelTop.findViewById(R.id.add_target).setOnClickListener(
+ new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ showAddDialog();
+ }
+ });
+ mViewPager = new QSViewPager(getContext());
+ mViewPager.setDragPanel(this);
+
+ mPageIndicator = new CirclePageIndicator(getContext());
+ addView(mDetail);
+ addView(mViewPager);
+ addView(mPageIndicator);
+ addView(mFooter.getView());
+
+ mClipper = new QSDetailClipper(mDetail);
+
+ mBrightnessController = new BrightnessController(getContext(),
+ (ImageView) mQsPanelTop.getBrightnessView().findViewById(R.id.brightness_icon),
+ (ToggleSlider) mQsPanelTop.getBrightnessView().findViewById(R.id.brightness_slider));
+
+ mDetailDoneButton.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ announceForAccessibility(
+ mContext.getString(R.string.accessibility_desc_quick_settings));
+ closeDetail();
+ }
+ });
+
+ mPagerAdapter = new PagerAdapter() {
+ @Override
+ public Object instantiateItem(ViewGroup container, int position) {
+ if (DEBUG_DRAG) {
+ Log.d(TAG, "instantiateItem() called with "
+ + "container = [" + container + "], position = [" + position + "]");
+ }
+
+ if (mEditing && position == 0) {
+ QSSettings qss = (QSSettings)
+ View.inflate(container.getContext(), R.layout.qs_settings, null);
+ qss.setHost(mHost);
+ container.addView(qss, 0);
+ return qss;
+ } else {
+ QSPage page = new QSPage(container.getContext(),
+ QSDragPanel.this, mEditing ? position - 1 : position);
+
+ container.addView(page);
+ int viewPos = page.getPageIndex();
+ if (viewPos > mPages.size()) {
+ mPages.add(page);
+ } else {
+ mPages.add(viewPos, page);
+ }
+ return page;
+ }
+ }
+
+ @Override
+ public void destroyItem(ViewGroup container, int position, Object object) {
+ if (DEBUG_DRAG) {
+ Log.d(TAG, "destroyItem() called with " + "container = ["
+ + container + "], position = [" + position + "], object = ["
+ + object + "]");
+ }
+ if (object instanceof View) {
+ if (object instanceof QSPage) {
+ mPages.remove(object);
+ }
+ container.removeView((View) object);
+ }
+ }
+
+ @Override
+ public int getItemPosition(Object object) {
+ if (object instanceof QSPage) {
+
+ final int indexOf = ((QSPage) object).getPageIndex();
+ Log.v(TAG, "getItemPosition() for: " + object + ", returning: " + indexOf);
+ if (mEditing) return indexOf + 1;
+ else return indexOf;
+
+ } else if (object instanceof QSSettings) {
+
+ if (mEditing) return 0;
+ else return POSITION_NONE;
+
+ }
+ return super.getItemPosition(object);
+ }
+
+ @Override
+ public int getCount() {
+ final int qsPages = Math.max(getCurrentMaxPageCount(), 1);
+
+ if (mEditing) return qsPages + 1;
+ return qsPages;
+ }
+
+ @Override
+ public boolean isViewFromObject(View view, Object object) {
+ return view == object;
+ }
+ };
+ mViewPager.setAdapter(mPagerAdapter);
+ mViewPager.setOffscreenPageLimit(INITIAL_OFFSCREEN_PAGE_LIMIT);
+
+ mPageIndicator.setViewPager(mViewPager);
+ mPageIndicator.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
+
+ @Override
+ public void onPageScrolled(int position, float positionOffset,
+ int positionOffsetPixels) {
+ Log.i(TAG, "onPageScrolled() called with " + "position = ["
+ + position + "], positionOffset = [" + positionOffset
+ + "], positionOffsetPixels = [" + positionOffsetPixels + "]");
+
+ if (mEditing) {
+ float targetTranslationX = 0;
+
+ // targetTranslationX = where it's supposed to be - diff
+ int homeLocation = mViewPager.getMeasuredWidth();
+
+ // how far away from homeLocation is the scroll?
+ if (positionOffsetPixels < homeLocation
+ && position == 0) {
+ targetTranslationX = homeLocation - positionOffsetPixels;
+ }
+ mQsPanelTop.setTranslationX(targetTranslationX);
+ }
+ }
+
+ @Override
+ public void onPageSelected(int position) {
+ if (mDragging && position != mDraggingRecord.page
+ && !mViewPager.isFakeDragging() && !mRestoring) {
+ Log.w(TAG, "moving drag record to page: " + position);
+
+ // remove it from the previous page and add it here
+ final QSPage sourceP = getPage(mDraggingRecord.page);
+ final QSPage targetP = getPage(position);
+
+ sourceP.removeView(mDraggingRecord.tileView);
+ mDraggingRecord.page = position;
+ targetP.addView(mDraggingRecord.tileView);
+
+ // set coords off screen until we're ready to place it
+ mDraggingRecord.tileView.setX(-mDraggingRecord.tileView.getMeasuredWidth());
+ mDraggingRecord.tileView.setY(-mDraggingRecord.tileView.getMeasuredHeight());
+ }
+ }
+
+ @Override
+ public void onPageScrollStateChanged(int state) {
+ }
+ });
+ mViewPager.setOverScrollMode(OVER_SCROLL_NEVER);
+
+ setClipChildren(false);
+
+ mSettingsObserver = new SettingsObserver(new Handler());
+ }
+
+ @Override
+ public boolean hasOverlappingRendering() {
+ return mClipper.isAnimating() || mEditing;
+ }
+
+ @Override
+ public void setBrightnessMirror(BrightnessMirrorController c) {
+ super.onFinishInflate();
+ ToggleSlider brightnessSlider =
+ (ToggleSlider) mQsPanelTop.findViewById(R.id.brightness_slider);
+ ToggleSlider mirror = (ToggleSlider) c.getMirror().findViewById(R.id.brightness_slider);
+ brightnessSlider.setMirror(mirror);
+ brightnessSlider.setMirrorController(c);
+ }
+
+ protected void drawTile(TileRecord r, QSTile.State state) {
+ final int visibility = state.visible || mEditing ? VISIBLE : GONE;
+ setTileVisibility(r.tileView, visibility);
+ r.tileView.onStateChanged(state);
+ }
+
+ @Override
+ public void setListening(boolean listening) {
+ if (mListening == listening) return;
+ mListening = listening;
+ for (TileRecord r : mRecords) {
+ r.tile.setListening(mListening);
+ }
+ mFooter.setListening(mListening);
+ if (mListening) {
+ refreshAllTiles();
+ }
+ if (mListening) {
+ mSettingsObserver.observe();
+ } else {
+ mSettingsObserver.unobserve();
+ }
+
+ if (isLaidOut() && listening && showBrightnessSlider()) {
+ mBrightnessController.registerCallbacks();
+ } else {
+ mBrightnessController.unregisterCallbacks();
+ }
+ }
+
+ public void setEditing(boolean editing) {
+ if (mEditing == editing) return;
+ mEditing = editing;
+
+ if (!editing) {
+ // persist the new config.
+ List<String> newTiles = new ArrayList<>();
+ for (TileRecord record : mRecords) {
+ newTiles.add(mHost.getSpec(record.tile));
+ }
+ mHost.setTiles(newTiles);
+
+ refreshAllTiles();
+
+ mQsPanelTop.animate().translationX(0).start();
+ }
+
+ // clear the record state
+ for (TileRecord record : mRecords) {
+ setupRecord(record);
+ drawTile(record, record.tile.getState());
+ }
+ mQsPanelTop.setEditing(editing);
+ mPageIndicator.setEditing(editing);
+ mPagerAdapter.notifyDataSetChanged();
+
+ ensurePagerState();
+ requestLayout();
+ }
+
+ protected void onStartDrag() {
+ mQsPanelTop.onStartDrag();
+ }
+
+ protected void onStopDrag() {
+ mDraggingRecord.tileView.setAlpha(1f);
+
+ mDraggingRecord = null;
+ mDragging = false;
+ mRestored = false;
+
+ mLastLeftShift = -1;
+ mLastRightShift = -1;
+
+ mQsPanelTop.onStopDrag();
+
+ requestLayout();
+ }
+
+ protected View getDropTarget() {
+ return mQsPanelTop.getDropTarget();
+ }
+
+ public View getBrightnessView() {
+ return mQsPanelTop.getBrightnessView();
+ }
+
+ public boolean isEditing() {
+ return mEditing;
+ }
+
+ protected int getPagesForCount(int size) {
+ return (int) Math.ceil(size / (double) getTilesPerPage());
+ }
+
+ protected int getCurrentMaxPageCount() {
+ int initialSize = mRecords.size();
+ if (mTempTiles != null) {
+ return getPagesForCount(initialSize + mTempTiles.size());
+ }
+ return getPagesForCount(initialSize);
+ }
+
+ @Override
+ protected void updateDetailText() {
+ super.updateDetailText();
+ mDetailRemoveButton.setText(R.string.quick_settings_remove);
+ }
+
+ /**
+ * @return returns the number of pages that has at least 1 visible tile
+ */
+ protected int getVisibleTilePageCount() {
+ // if all tiles are invisible on the page, do not count it
+ int pages = 0;
+
+ int lastPage = -1;
+ boolean allTilesInvisible = true;
+
+ for (TileRecord record : mRecords) {
+ DragTileRecord dr = (DragTileRecord) record;
+ if (dr.destinationPage != lastPage) {
+ if (!allTilesInvisible) {
+ pages++;
+ }
+ lastPage = dr.destinationPage;
+ allTilesInvisible = true;
+ }
+ if (allTilesInvisible && dr.tile.getState().visible) {
+ allTilesInvisible = false;
+ }
+ }
+ // last tile may have set this
+ if (!allTilesInvisible) {
+ pages++;
+ }
+ return pages;
+ }
+
+ public void setTiles(Collection<QSTile<?>> tiles) {
+ if (DEBUG_DRAG) {
+ Log.i(TAG, "setTiles() called with " + "tiles = ["
+ + tiles + "], mTempTiles: " + mTempTiles);
+ if (mTempTiles != null) {
+ Log.e(TAG, "temp tiles being overridden... : " +
+ Arrays.toString(mTempTiles.toArray()));
+ }
+ }
+ for (Record record : mRecords) {
+ if (record instanceof DragTileRecord) {
+ DragTileRecord dr = (DragTileRecord) record;
+ mPages.get(dr.page).removeView(dr.tileView);
+ }
+ }
+ mRecords.clear();
+ if (isLaidOut()) {
+ for (QSTile<?> tile : tiles) {
+ addTile(tile);
+ }
+ if (isShowingDetail()) {
+ mDetail.bringToFront();
+ }
+ } else if (!isLaidOut()) {
+ if (DEBUG_DRAG) {
+ Log.w(TAG, "setting temporary tiles to layout");
+ }
+ mTempTiles = Collections.synchronizedCollection(new ArrayList<QSTile<?>>(tiles));
+ }
+ mPagerAdapter.notifyDataSetChanged();
+ requestLayout();
+ ensurePagerState();
+ }
+
+ protected void addTile(final QSTile<?> tile) {
+ if (DEBUG_DRAG) {
+ Log.d(TAG, "+++ addTile() called with " + "tile = [" + tile + "]");
+ }
+ final DragTileRecord r = new DragTileRecord();
+
+ mRecords.add(r);
+ mPagerAdapter.notifyDataSetChanged();
+
+ int potentialPageIdx = getPagesForCount(mRecords.size()) - 1;
+
+ r.tile = tile;
+ r.page = potentialPageIdx;
+ r.destinationPage = r.page;
+ r.tileView = tile.createTileView(mContext);
+ r.tileView.setVisibility(View.GONE);
+ final QSTile.Callback callback = new QSTile.Callback() {
+ @Override
+ public void onStateChanged(QSTile.State state) {
+ if (!r.openingDetail) {
+ drawTile(r, state);
+ }
+ }
+
+ @Override
+ public void onShowDetail(boolean show) {
+ showDetail(show, r);
+ }
+
+ @Override
+ public void onToggleStateChanged(boolean state) {
+ if (mDetailRecord == r) {
+ fireToggleStateChanged(state);
+ }
+ }
+
+ @Override
+ public void onScanStateChanged(boolean state) {
+ r.scanState = state;
+ if (mDetailRecord == r) {
+ fireScanStateChanged(r.scanState);
+ }
+ }
+
+ @Override
+ public void onAnnouncementRequested(CharSequence announcement) {
+ announceForAccessibility(announcement);
+ }
+ };
+ r.tile.setCallback(callback);
+ final OnClickListener click = new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ if (!mEditing || r.tile instanceof EditTile) {
+ r.tile.click();
+ }
+ }
+ };
+ final OnClickListener clickSecondary = new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ if (!mEditing) {
+ r.tile.secondaryClick();
+ }
+ }
+ };
+ final OnLongClickListener longClick = new OnLongClickListener() {
+ @Override
+ public boolean onLongClick(View v) {
+ if (!mEditing) {
+ r.tile.longClick();
+ } else {
+ QSDragPanel.this.onLongClick(r.tileView);
+ }
+ return true;
+ }
+ };
+ r.tileView.init(click, clickSecondary, longClick);
+ r.tile.setListening(mListening);
+ r.tile.refreshState();
+ if (mEditing) {
+ // force it to be visible, we'll refresh its state once editing is done
+ r.tile.getState().visible = true;
+ }
+ callback.onStateChanged(r.tile.getState());
+
+ mPages.get(r.page).addView(r.tileView);
+
+ ensurePagerState();
+
+ if (DEBUG_DRAG) {
+ Log.d(TAG, "--- addTile() called with " + "tile = [" + tile + "]");
+ }
+ }
+
+ public void ensurePagerState() {
+ if (!isShowingDetail()) {
+ final boolean pagingEnabled = getVisibleTilePageCount() > 1 || mDragging || mEditing;
+ mViewPager.setPagingEnabled(pagingEnabled);
+ }
+ }
+
+ public int getTilesPerPage() {
+ if (!mFirstRowLarge) {
+ return QSTileHost.TILES_PER_PAGE + 1;
+ }
+ return QSTileHost.TILES_PER_PAGE;
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ final int width = MeasureSpec.getSize(widthMeasureSpec);
+
+ if (isLaidOut()) {
+ mQsPanelTop.measure(exactly(width), MeasureSpec.UNSPECIFIED);
+ }
+ mViewPager.measure(exactly(width), MeasureSpec.UNSPECIFIED);
+ mPageIndicator.measure(exactly(width), MeasureSpec.UNSPECIFIED);
+ mFooter.getView().measure(exactly(width), MeasureSpec.UNSPECIFIED);
+
+ int h = mBrightnessPaddingTop
+ + mViewPager.getMeasuredHeight()
+ + mPageIndicator.getMeasuredHeight();
+ if (mFooter.hasFooter()) {
+ h += mFooter.getView().getMeasuredHeight();
+ }
+ mDetail.measure(exactly(width), MeasureSpec.UNSPECIFIED);
+ if (mDetail.getMeasuredHeight() < h) {
+ mDetail.measure(exactly(width), exactly(h));
+ }
+ mGridHeight = h;
+ setMeasuredDimension(width, Math.max(h, mDetail.getMeasuredHeight()));
+
+ for (TileRecord record : mRecords) {
+ setupRecord(record);
+ }
+ }
+
+ private void setupRecord(TileRecord record) {
+ record.tileView.setEditing(mEditing);
+ record.tileView.setOnDragListener(mEditing ? this : null);
+ }
+
+ public static int exactly(int size) {
+ return MeasureSpec.makeMeasureSpec(size, MeasureSpec.EXACTLY);
+ }
+
+ @Override
+ protected void handleShowDetailTile(TileRecord r, boolean show) {
+ if (r instanceof DragTileRecord) {
+ if ((mDetailRecord != null) == show && mDetailRecord == r) return;
+
+ if (show) {
+ r.detailAdapter = r.tile.getDetailAdapter();
+ if (r.detailAdapter == null) return;
+ }
+ r.tile.setDetailListening(show);
+ int x = (int) ((DragTileRecord) r).destination.x + r.tileView.getWidth() / 2;
+ int y = mViewPager.getTop() + (int) ((DragTileRecord) r).destination.y + r.tileView.getHeight() / 2;
+ handleShowDetailImpl(r, show, x, y);
+ } else {
+ super.handleShowDetailTile(r, show);
+ }
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int l, int t, int r, int b) {
+ final int w = getWidth();
+
+ int top = mBrightnessPaddingTop;
+
+ mViewPager.layout(0, top, w, top + mViewPager.getMeasuredHeight());
+ top += mViewPager.getMeasuredHeight();
+
+ // layout page indicator below view pager
+ mPageIndicator.layout(0, top, w, top + mPageIndicator.getMeasuredHeight());
+
+ // detail takes up whole height
+ mDetail.layout(0, 0, mDetail.getMeasuredWidth(), getMeasuredHeight());
+
+ if (mFooter.hasFooter()) {
+ View footer = mFooter.getView();
+ footer.layout(0, getMeasuredHeight() - footer.getMeasuredHeight(),
+ footer.getMeasuredWidth(), getMeasuredHeight());
+ }
+
+ if (mTempTiles != null) {
+ final Iterator<QSTile<?>> iterator = mTempTiles.iterator();
+ while (iterator.hasNext()) {
+ addTile(iterator.next());
+ iterator.remove();
+ }
+ mTempTiles = null;
+ mPagerAdapter.notifyDataSetChanged();
+ }
+ ensurePagerState();
+ }
+
+ protected int getRowTop(int row) {
+ int baseHeight = mBrightnessView.getMeasuredHeight() + mBrightnessPaddingTop;
+ if (row <= 0) return baseHeight;
+ return baseHeight + mLargeCellHeight - mDualTileUnderlap + (row - 1) * mCellHeight;
+ }
+
+ public int getColumnCount() {
+ return mColumns;
+ }
+
+ public int getColumnCount(int page, int row) {
+ int cols = 0;
+ for (Record record : mRecords) {
+ if (record instanceof DragTileRecord) {
+ DragTileRecord dr = (DragTileRecord) record;
+ if (dr.tileView.getVisibility() == GONE) continue;
+ if (dr.destinationPage != page) continue;
+ if (dr.row == row) cols++;
+ }
+ }
+
+ if (isEditing() && (isDragging() || mRestoring) && !isDragRecordAttached()) {
+ // if shifting tiles back, and one moved from previous page
+
+ // if it's the very last row on the last page, we should add an extra column to account
+ // for where teh dragging record would go
+ DragTileRecord record = (DragTileRecord) mRecords.get(mRecords.size() - 1);
+
+ if (record.destinationPage == page && record.row == row && cols < getColumnCount()) {
+ cols++;
+ if (DEBUG_DRAG) {
+ Log.w(TAG, "adding another col, cols: " + cols + ", last: " + record
+ + ", drag: " + mDraggingRecord + ", ");
+ }
+ }
+ }
+ return cols;
+ }
+
+ public int getMaxRows() {
+ int max = 0;
+ for (TileRecord record : mRecords) {
+ if (record.row > max) {
+ max = record.row;
+ }
+ }
+ return max;
+ }
+
+ public int getLeft(int page, int row, int col) {
+ final boolean firstRowLarge = mFirstRowLarge && page == 0 && row == 0;
+ int cols = firstRowLarge ? 2 : mColumns;
+ return getLeft(row, col, cols, firstRowLarge);
+ }
+
+ public int getLeft(int page, int row, int col, int cols) {
+ final boolean firstRowLarge = mFirstRowLarge && page == 0 && row == 0;
+ return getLeft(row, col, cols, firstRowLarge);
+ }
+
+ public int getLeft(int row, int col, int cols, boolean firstRowLarge) {
+ final int cw = row == 0 && firstRowLarge ? mLargeCellWidth : mCellWidth;
+ final int extra = (getWidth() - cw * cols) / (cols + 1);
+ int left = col * cw + (col + 1) * extra;
+ return left;
+ }
+
+ public QSPage getCurrentPage() {
+ return mPages.get(mViewPager.getCurrentItem());
+ }
+
+ public QSPage getPage(int pos) {
+ if (pos >= mPages.size()) {
+ return null;
+ }
+ return mPages.get(pos);
+ }
+
+ private TileRecord getRecord(View v) {
+ for (TileRecord record : mRecords) {
+ if (record.tileView == v) {
+ return record;
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public boolean onDrag(View v, DragEvent event) {
+ final DragTileRecord targetTile = (DragTileRecord) getRecord(v);
+ boolean originatingTileEvent = mDraggingRecord != null && v == mDraggingRecord.tileView;
+
+ final int dragRecordIndex = mRecords.indexOf(mDraggingRecord);
+ boolean dragRecordAttached = dragRecordIndex != -1;
+ switch (event.getAction()) {
+ case DragEvent.ACTION_DRAG_STARTED:
+ if (originatingTileEvent) {
+ if (DEBUG_DRAG) {
+ Log.v(TAG, "ACTION_DRAG_STARTED on target view.");
+ }
+ mRestored = false;
+ }
+ return true;
+
+ case DragEvent.ACTION_DRAG_ENTERED:
+ if (DEBUG_DRAG) {
+ Log.v(TAG, "ACTION_DRAG_ENTERED on view with tile: " + targetTile);
+ }
+ mLocationHits = 0;
+ mMovedByLocation = false;
+
+ if (!originatingTileEvent && v != getDropTarget() && targetTile != null) {
+ if (DEBUG_DRAG) {
+ Log.e(TAG, "entered tile " + targetTile);
+ }
+ if (mCurrentlyAnimating.isEmpty()
+ && !mViewPager.isFakeDragging()
+ && !dragRecordAttached) {
+ mMovedByLocation = true;
+ shiftTiles(targetTile, true);
+ } else {
+ if (DEBUG_DRAG) {
+ Log.w(TAG, "ignoring action enter for animating tiles and fake drags");
+ }
+ }
+ }
+
+ return true;
+ case DragEvent.ACTION_DRAG_ENDED:
+ if (DEBUG_DRAG) {
+ Log.v(TAG, "ACTION_DRAG_ENDED on view: " + v + "(tile: "
+ + targetTile + "), result: " + event.getResult());
+ }
+ if (originatingTileEvent && !event.getResult()) {
+ // view pager probably ate the event
+ restoreDraggingTilePosition(v);
+ }
+
+ return true;
+
+ case DragEvent.ACTION_DROP:
+ if (DEBUG_DRAG) {
+ Log.v(TAG, "ACTION_DROP, event loc: " + event.getX() + ", " + event.getY()
+ + " + with tile: " + targetTile + " and view: " + v);
+ }
+ mLastTouchLocationX = event.getX();
+ mLastTouchLocationY = event.getY();
+
+ if (isDropTargetEvent(event, v)) {
+ if (DEBUG_DRAG) {
+ Log.d(TAG, "dropping on delete target!!");
+ }
+ if (mDraggingRecord.tile instanceof EditTile) {
+ mQsPanelTop.toast(R.string.quick_settings_cannot_delete_edit_tile);
+ restoreDraggingTilePosition(v);
+ return true;
+ } else {
+ mRestored = true;
+ getPage(mDraggingRecord.page).removeView(mDraggingRecord.tileView);
+
+ // what spec is this tile?
+ String spec = mHost.getSpec(mDraggingRecord.tile);
+ if (DEBUG_DRAG) {
+ Log.w(TAG, "removing tile: " + mDraggingRecord + " with spec: " + spec);
+ }
+ mHost.remove(spec);
+ onStopDrag();
+ }
+ } else {
+ restoreDraggingTilePosition(v);
+ }
+ return true;
+
+ case DragEvent.ACTION_DRAG_EXITED:
+ if (DEBUG_DRAG) {
+ if (targetTile != null) {
+ Log.v(TAG, "ACTION_DRAG_EXITED on view with tile: " + targetTile);
+ } else {
+ Log.v(TAG, "ACTION_DRAG_EXITED on view: " + v);
+ }
+ }
+ if (originatingTileEvent
+ && mCurrentlyAnimating.isEmpty()
+ && !mViewPager.isFakeDragging()
+ && dragRecordAttached
+ && mLastLeftShift == -1) {
+
+ if (DEBUG_DRAG) {
+ Log.v(TAG, "target: " + targetTile + ", hit mLastRightShift: "
+ + mLastRightShift + ", mLastLeftShift: "
+ + mLastLeftShift + ", dragRecordIndex: "
+ + dragRecordIndex);
+ }
+
+ // move tiles back
+ shiftTiles(mDraggingRecord, false);
+ return true;
+ }
+ // fall through so exit events can trigger a left shift
+ case DragEvent.ACTION_DRAG_LOCATION:
+ mLastTouchLocationX = event.getX();
+ mLastTouchLocationY = event.getY();
+
+ // do nothing if we're animating tiles
+ if (mCurrentlyAnimating.isEmpty() && !mViewPager.isFakeDragging()) {
+ if (v == mViewPager) {
+ // do we need to change pages?
+ int x = (int) event.getX();
+ int width = mViewPager.getWidth();
+ int scrollPadding = (int) (width * QSViewPager.SCROLL_PERCENT);
+ if (x < scrollPadding) {
+ if (mViewPager.canScrollHorizontally(-1)) {
+ mViewPager.animatePagerTransition(false);
+ return true;
+ }
+ } else if (x > width - scrollPadding) {
+ if (mViewPager.canScrollHorizontally(1)) {
+ mViewPager.animatePagerTransition(true);
+ return true;
+ }
+ }
+ }
+ if (DEBUG_DRAG) {
+ Log.v(TAG, "location hit:// target: " + targetTile
+ + ", hit mLastRightShift: " + mLastRightShift
+ + ", mLastLeftShift: " + mLastLeftShift
+ + ", dragRecordIndex: " + dragRecordIndex
+ + ", originatingTileEvent: " + originatingTileEvent
+ + ", mLocationHits: " + mLocationHits
+ + ", mMovedByLocation: " + mMovedByLocation);
+ }
+
+ if (v != getDropTarget() && targetTile != null && !dragRecordAttached) {
+ // dragging around on another tile
+ if (mLocationHits++ == 30) {
+ if (DEBUG_DRAG) {
+ Log.w(TAG, "shifting right due to location hits.");
+ }
+ // add dragging tile to current page
+ shiftTiles(targetTile, true);
+ mMovedByLocation = true;
+ } else {
+ mLocationHits++;
+ }
+ } else if (mLastRightShift != -1 // right has shifted recently
+ && mLastLeftShift == -1 // -1 means its attached
+ && dragRecordIndex == mLastRightShift
+ && !originatingTileEvent
+ && !mMovedByLocation /* helps avoid continuous shifting */) {
+ // check if the location is on another tile/view
+ // that is not the last drag index, shift back left to revert back and
+ // potentially get ready for shifting right
+ if (DEBUG_DRAG) {
+ Log.w(TAG, "conditions met to reverse!!!! shifting left. <<<<<<<");
+ }
+ shiftTiles((DragTileRecord) mRecords.get(mLastRightShift), false);
+ mMovedByLocation = true;
+ }
+ } else {
+ if (DEBUG_DRAG) {
+ Log.i(TAG, "ignoring location event because things are animating, size: "
+ + mCurrentlyAnimating.size());
+ }
+ }
+ return true;
+ default:
+ Log.w(TAG, "unhandled event");
+ }
+ return false;
+ }
+
+ private boolean isDropTargetEvent(DragEvent event, View v) {
+ if (DEBUG_DRAG) {
+ Log.d(TAG, "isDropTargetEvent() called with " + "event = [" + event + "], v = [" + v + "]");
+ }
+ if (v == getDropTarget() || v == mQsPanelTop) {
+ if (DEBUG_DRAG) {
+ Log.d(TAG, "isDropTargetEvent() returns true by view");
+ }
+ return true;
+ }
+
+ if (v == mViewPager && mLastTouchLocationY <= getRowTop(0)) {
+ if (DEBUG_DRAG) {
+ Log.d(TAG, "isDropTargetEvent() returns true by loc");
+ }
+ return true;
+ }
+
+ return false;
+ }
+
+ private void restoreDraggingTilePosition(View v) {
+ if (mRestored) {
+ return;
+ }
+ mRestored = true;
+ mRestoring = true;
+ mCurrentlyAnimating.add(mDraggingRecord);
+
+ if (DEBUG_DRAG) {
+ Log.i(TAG, "restoreDraggingTilePosition() called with "
+ + "v = [" + (v.getTag() != null ? v.getTag() : v) + "]");
+ }
+ final boolean dragRecordDetached = mRecords.indexOf(mDraggingRecord) == -1;
+
+ if (DEBUG_DRAG) {
+ Log.v(TAG, "mLastLeftShift: " + mLastLeftShift
+ + ", detached: " + dragRecordDetached + ", drag record: " + mDraggingRecord);
+ }
+
+ final QSPage originalPage = getPage(mDraggingRecord.page);
+ originalPage.removeView(mDraggingRecord.tileView);
+ addTransientView(mDraggingRecord.tileView, 0);
+ mDraggingRecord.tileView.setTransitionVisibility(View.VISIBLE);
+
+ // need to move center of the dragging view to the coords of the event.
+ final float touchEventBoxLeft = v.getX()
+ + (mLastTouchLocationX - (mDraggingRecord.tileView.getWidth() / 2));
+ final float touchEventBoxTop = v.getY()
+ + (mLastTouchLocationY - (mDraggingRecord.tileView.getHeight() / 2));
+
+ mDraggingRecord.tileView.setX(touchEventBoxLeft);
+ mDraggingRecord.tileView.setY(touchEventBoxTop);
+
+ if (dragRecordDetached) {
+ setToLastDestination(mDraggingRecord);
+ if (DEBUG_DRAG) {
+ Log.d(TAG, "setting drag record view to coords: x:" + touchEventBoxLeft
+ + ", y:" + touchEventBoxTop);
+ Log.d(TAG, "animating drag record to: " + mDraggingRecord + ", loc: "
+ + mDraggingRecord.destination);
+ }
+ } else {
+ mDraggingRecord.destination.x = getLeft(mDraggingRecord.destinationPage,
+ mDraggingRecord.row, mDraggingRecord.col,
+ getColumnCount(mDraggingRecord.destinationPage, mDraggingRecord.row));
+
+ mDraggingRecord.destination.y = getRowTop(mDraggingRecord.row);
+ }
+
+ // setup x destination to animate to
+ float destinationX = mDraggingRecord.destination.x;
+ if (mDraggingRecord.destinationPage + 1 > mViewPager.getCurrentItem()) {
+ destinationX += getWidth();
+ } else if (mDraggingRecord.destinationPage + 1 < mViewPager.getCurrentItem()) {
+ destinationX -= getWidth();
+ }
+
+ // setup y
+ float destinationY = mDraggingRecord.destination.y + mViewPager.getTop();
+
+ mDraggingRecord.tileView.animate()
+ .x(destinationX)
+ .y(destinationY) // part of the viewpager now
+ .setListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ mDraggingRecord.tileView.setAlpha(1);
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mViewPager.requestDisallowInterceptTouchEvent(false);
+
+ removeTransientView(mDraggingRecord.tileView);
+
+ final QSPage targetP = getPage(mDraggingRecord.destinationPage);
+
+ if (dragRecordDetached) {
+ Log.i(TAG, "drag record was detached");
+
+ } else {
+ Log.i(TAG, "drag record was attached");
+ }
+ mDraggingRecord.page = mDraggingRecord.destinationPage;
+ targetP.addView(mDraggingRecord.tileView);
+
+ mDraggingRecord.tileView.setX(mDraggingRecord.destination.x);
+ // reset this to be in the coords of the page, not viewpager anymore
+ mDraggingRecord.tileView.setY(mDraggingRecord.destination.y);
+
+ mCurrentlyAnimating.remove(mDraggingRecord);
+
+ mRestoring = false;
+
+ if (dragRecordDetached) {
+ mRecords.add(mDraggingRecord);
+ mPagerAdapter.notifyDataSetChanged();
+ }
+ onStopDrag();
+ }
+ });
+ }
+
+ private void setToNextDestination(DragTileRecord tile) {
+ if (DEBUG_DRAG) {
+ Log.i(TAG, "+++setToNextDestination() called with " + "tile = [" + tile + "], at: "
+ + tile.destination);
+ }
+ tile.col++;
+ int maxCols = getColumnCount();
+
+ if (tile.col >= maxCols) {
+ tile.col = 0;
+ tile.row++;
+ if (DEBUG_DRAG) {
+ Log.w(TAG, "reached max column count, shifting to next row: " + tile.row);
+ }
+ }
+
+ int maxRows = getMaxRows();
+
+ if (tile.row >= maxRows) {
+ tile.destinationPage = tile.destinationPage + 1;
+ tile.row = 0;
+ tile.col = 0;
+
+ if (DEBUG_DRAG) {
+ Log.w(TAG, "tile's destination page moved to: " + tile.destinationPage);
+ }
+ }
+ int columnCount = Math.max(1, getColumnCount(tile.destinationPage, tile.row));
+ if (DEBUG_DRAG) {
+ Log.w(TAG, "columCount initially at: " + columnCount);
+ }
+
+ if (!mRecords.contains(tile) && tile != mDraggingRecord) {
+ // increase column count for the destination location to account for this tile being added
+ columnCount++;
+ if (DEBUG_DRAG) {
+ Log.w(TAG, "column count adjusted to: " + columnCount);
+ }
+ }
+ boolean firstRowLarge = tile.row == 0 && tile.destinationPage == 0;
+
+ tile.destination.x = getLeft(tile.row, tile.col, columnCount, firstRowLarge);
+ tile.destination.y = getRowTop(tile.row);
+
+ if (DEBUG_DRAG) {
+ Log.i(TAG, "---setToNextDestination() called with " + "tile = [" + tile + "], now at: "
+ + tile.destination);
+ }
+ }
+
+ private void setToLastDestination(DragTileRecord record) {
+ DragTileRecord last = (DragTileRecord) mRecords.get(mRecords.size() - 1);
+ Log.d(TAG, "setToLastDestination() called with record = ["
+ + record + "], and last record is: " + last);
+ if (record != last && record.destinationPage <= last.destinationPage) {
+ record.destinationPage = last.destinationPage;
+ record.row = last.row;
+ record.col = last.col;
+ record.destination.x = last.destination.x;
+ record.destination.y = last.destination.y;
+ setToNextDestination(record);
+ }
+ }
+
+ @Override
+ public boolean onLongClick(View v) {
+ final DragTileRecord record = (DragTileRecord) getRecord(v);
+ if (record == null) {
+ // TODO couldn't find a matching tag?
+ Log.e(TAG, "got a null record on touch down.");
+ return false;
+ }
+
+ mDraggingRecord = record;
+
+ mDraggingRecord.tileView.setAlpha(0);
+ mDraggingRecord.tileView.setDual(false, false);
+ TileShadow mTileShadow = new TileShadow(mDraggingRecord.tileView);
+
+ v.startDrag(null, mTileShadow, null, 0);
+
+ mViewPager.requestDisallowInterceptTouchEvent(true);
+
+ onStartDrag();
+ mDragging = true;
+ return true;
+ }
+
+ private void shiftTiles(DragTileRecord startingTile, boolean forward) {
+ if (DEBUG_DRAG) {
+ Log.i(TAG, "shiftTiles() called with " + "startingTile = [" + startingTile
+ + "], forward = [" + forward + "]");
+ }
+
+ if (forward) {
+ // startingTile and all after will need to be shifted one to the right
+ // dragging tile needs room
+
+ final int destP = startingTile.destinationPage;
+ final int rowF = startingTile.row;
+ final int colF = startingTile.col;
+ PointF loc = new PointF(startingTile.destination.x, startingTile.destination.y);
+
+ // the index of the original position of the statingTile before it moved
+ int startingIndex = mRecords.indexOf(startingTile);
+ mLastRightShift = startingIndex;
+ mLastLeftShift = -1;
+
+ shiftAllTilesRight(startingIndex);
+ mRecords.add(startingIndex, mDraggingRecord);
+
+ mPagerAdapter.notifyDataSetChanged();
+
+ mDraggingRecord.col = colF;
+ mDraggingRecord.row = rowF;
+ mDraggingRecord.destination = loc;
+ mDraggingRecord.destinationPage = destP;
+
+ mDraggingRecord.tileView.setX(mDraggingRecord.destination.x);
+ mDraggingRecord.tileView.setY(mDraggingRecord.destination.y);
+
+ } else {
+ // it is also probably the dragging tile
+ final int startingIndex = mRecords.indexOf(startingTile);
+ mLastLeftShift = startingIndex;
+ mLastRightShift = -1;
+
+ final int draggingIndex = mRecords.indexOf(mDraggingRecord);
+
+ if (startingIndex != draggingIndex) {
+ if (DEBUG_DRAG) {
+ Log.e(TAG, "startinIndex: " + startingIndex + ", draggingIndex: "
+ + draggingIndex + ", and they differ!!!!");
+ }
+ }
+
+ // startingTile should be the "empty" tile that things should start shifting into
+ shiftAllTilesLeft(startingIndex);
+
+ // remove the dragging record
+ if (mRecords.remove(mDraggingRecord)) {
+ mPagerAdapter.notifyDataSetChanged();
+ if (DEBUG_DRAG) {
+ Log.v(TAG, "removed dragging record after moving tiles back");
+ }
+ }
+
+ // set coords off screen until we're ready to place it
+ mDraggingRecord.tileView.setX(-mDraggingRecord.tileView.getMeasuredWidth());
+ mDraggingRecord.tileView.setY(-mDraggingRecord.tileView.getMeasuredHeight());
+ }
+
+ mViewPager.getAdapter().notifyDataSetChanged();
+ }
+
+ private void shiftAllTilesRight(int startingIndex) {
+ int desiredColumnCount = -1;
+ for (int j = startingIndex; j < mRecords.size() - 1; j++) {
+ final DragTileRecord ti = (DragTileRecord) mRecords.get(j);
+ final DragTileRecord tnext = (DragTileRecord) mRecords.get(j + 1);
+
+ mCurrentlyAnimating.add(ti);
+ if (tnext.row != ti.row || desiredColumnCount == -1) {
+ desiredColumnCount = getColumnCount(tnext.destinationPage, tnext.row);
+ //Log.w(TAG, "updated desiredColumnCount: " + desiredColumnCount);
+ }
+
+ if (DEBUG_DRAG) {
+ Log.v(TAG, "moving " + ti + " to page " + tnext.destinationPage + ", at coords: "
+ + tnext.row + ", col: " + tnext.col + ", dest: " + tnext.destination);
+ }
+
+ ti.row = tnext.row;
+ ti.col = tnext.col;
+ ti.destination.x = getLeft(tnext.destinationPage, ti.row, ti.col, desiredColumnCount);
+ ti.destination.y = getRowTop(ti.row);
+
+ if (ti.destinationPage != tnext.destinationPage) {
+ ti.destinationPage = tnext.destinationPage;
+
+ final QSPage tilePageSource = getPage(ti.page);
+ final QSPage tilePageTarget = getPage(ti.destinationPage);
+ tilePageSource.removeView(ti.tileView);
+
+ tilePageSource.addTransientView(ti.tileView, 0);
+ ti.tileView.animate()
+ .x(ti.destination.x + getWidth())
+ .y(ti.destination.y)
+ .setListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ tilePageSource.removeTransientView(ti.tileView);
+ ti.page = tilePageTarget.getPageIndex();
+ tilePageTarget.addView(ti.tileView);
+ ti.tileView.setX(ti.destination.x);
+ ti.tileView.setY(ti.destination.y);
+
+ mCurrentlyAnimating.remove(ti);
+ requestLayout();
+ }
+ });
+
+ } else {
+ ti.tileView.animate()
+ .x(ti.destination.x)
+ .y(ti.destination.y)
+ .setListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mCurrentlyAnimating.remove(ti);
+ }
+ });
+ }
+ }
+
+ // need to do last tile manually
+ final DragTileRecord last = (DragTileRecord) mRecords.get(mRecords.size() - 1);
+ mCurrentlyAnimating.add(last);
+
+ if (DEBUG_DRAG) {
+ Log.i(TAG, "last tile shifting to the right: " + last);
+ }
+ setToNextDestination(last);
+ if (last.page != last.destinationPage) {
+ final QSPage tilePageSource = getPage(last.page);
+ final QSPage tilePageTarget = getPage(last.destinationPage);
+ tilePageSource.removeView(last.tileView);
+ tilePageSource.addTransientView(last.tileView, 0);
+
+ last.tileView.animate()
+ .x(last.destination.x + getWidth())
+ .y(last.destination.y)
+ .setListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ tilePageSource.removeTransientView(last.tileView);
+ last.page = tilePageTarget.getPageIndex();
+ tilePageTarget.addView(last.tileView);
+ last.tileView.setX(last.destination.x);
+ last.tileView.setY(last.destination.y);
+
+ if (DEBUG_DRAG) {
+ Log.i(TAG, "page shift finished: " + last);
+ }
+
+ mCurrentlyAnimating.remove(last);
+ requestLayout();
+ }
+ });
+ } else {
+ last.tileView.animate()
+ .x(last.destination.x)
+ .y(last.destination.y)
+ .setListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ if (DEBUG_DRAG) {
+ Log.i(TAG, "shift finished: " + last);
+ }
+
+ mCurrentlyAnimating.remove(last);
+ }
+ });
+ }
+ }
+
+ private void shiftAllTilesLeft(int startingIndex) {
+ DragTileRecord startingTile = (DragTileRecord) mRecords.get(startingIndex);
+
+ final PointF lastLocation = new PointF(startingTile.destination.x,
+ startingTile.destination.y);
+ PointF reallyTempLoc = new PointF();
+ int lastRow = startingTile.row, lastCol = startingTile.col, tempRow,
+ tempCol, lastPage = startingTile.destinationPage, tempPage;
+
+ int desiredColCount = getColumnCount(startingTile.destinationPage, startingTile.row);
+ for (int j = startingIndex + 1; j < mRecords.size(); j++) {
+ final DragTileRecord ti = (DragTileRecord) mRecords.get(j);
+
+ mCurrentlyAnimating.add(ti);
+
+ if (DEBUG_DRAG) {
+ Log.v(TAG, "moving " + ti + " to " + lastPage + ", at coords: "
+ + lastRow + ", col: " + lastCol);
+ Log.i(TAG, "and will have desiredColCount: " + desiredColCount);
+ }
+
+ final int columnCountF = desiredColCount;
+
+ if (ti.row != lastRow) {
+ desiredColCount = getColumnCount(ti.destinationPage, ti.row);
+ Log.e(TAG, "updating desired colum count to: " + desiredColCount);
+ }
+
+ // save current tile's loc
+ reallyTempLoc.x = ti.destination.x;
+ reallyTempLoc.y = ti.destination.y;
+
+ tempRow = ti.row;
+ tempCol = ti.col;
+ tempPage = ti.destinationPage;
+
+ ti.row = lastRow;
+ ti.col = lastCol;
+
+ ti.destination.x = getLeft(lastRow, lastCol, columnCountF,
+ lastPage == 0 && lastRow == 0);
+ ti.destination.y = getRowTop(lastRow);
+
+ final boolean dual = getPage(ti.destinationPage).dualRecord(ti);
+
+ if (ti.destinationPage != lastPage) {
+ ti.destinationPage = lastPage;
+
+ ti.tileView.setX(reallyTempLoc.x + getWidth());
+ ti.tileView.setY(reallyTempLoc.y);
+
+ final QSPage originalPage = getPage(ti.page);
+ final QSPage page = getPage(lastPage);
+
+ originalPage.removeView(ti.tileView);
+
+ ti.tileView.animate()
+ .x(ti.destination.x)
+ .y(ti.destination.y)
+ .setListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ page.addTransientView(ti.tileView, 0);
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ page.removeTransientView(ti.tileView);
+ ti.page = page.getPageIndex();
+ page.addView(ti.tileView);
+
+ mCurrentlyAnimating.remove(ti);
+ requestLayout();
+ }
+ });
+ } else {
+ ti.tileView.animate()
+ .x(ti.destination.x)
+ .y(ti.destination.y)
+ .setListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ if (ti.tileView.setDual(dual, ti.tile.hasDualTargetsDetails())) {
+ if (DEBUG_DRAG) {
+ Log.w(TAG, ti + " changed dual state to : "
+ + ti.tileView.isDual());
+ }
+ ti.tileView.handleStateChanged(ti.tile.getState());
+ ti.tileView.invalidate();
+ }
+
+ mCurrentlyAnimating.remove(ti);
+ requestLayout();
+ }
+ });
+ }
+
+ // update previous location
+ lastLocation.x = reallyTempLoc.x;
+ lastLocation.y = reallyTempLoc.y;
+
+ lastRow = tempRow;
+ lastCol = tempCol;
+ lastPage = tempPage;
+ }
+ }
+
+ @Override
+ protected void handleShowDetailImpl(Record r, boolean show, int x, int y) {
+ super.handleShowDetailImpl(r, show, x, y);
+ if (show) {
+ final StatusBarPanelCustomTile customTile = r.detailAdapter.getCustomTile();
+ mDetailRemoveButton.setVisibility(customTile != null ? VISIBLE : GONE);
+ mDetailRemoveButton.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ mHost.collapsePanels();
+ mHost.removeCustomTile(customTile);
+ }
+ });
+ }
+ }
+
+ public int getDesiredColumnCount(int page, int row) {
+ if (page == 0 && row == 0) {
+ return 2; // TODO change if large tiles are disabled
+ } else {
+ return mColumns;
+ }
+ }
+
+ @Override
+ protected void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+ FontSizeUtils.updateFontSize(mDetailRemoveButton, R.dimen.qs_detail_button_text_size);
+ }
+
+ @Override
+ public void setExpanded(boolean expanded) {
+ super.setExpanded(expanded);
+ if (!expanded) {
+ if (mEditing) {
+ setEditing(false);
+ }
+ }
+ }
+
+ public void updateResources() {
+ final Resources res = mContext.getResources();
+ final int columns = Math.max(1, res.getInteger(R.integer.quick_settings_num_columns));
+ mCellHeight = res.getDimensionPixelSize(R.dimen.qs_tile_height);
+ mCellWidth = (int) (mCellHeight * TILE_ASPECT);
+ mLargeCellHeight = res.getDimensionPixelSize(R.dimen.qs_dual_tile_height);
+ mLargeCellWidth = (int) (mLargeCellHeight * TILE_ASPECT);
+ mPanelPaddingBottom = res.getDimensionPixelSize(R.dimen.qs_panel_padding_bottom);
+ mDualTileUnderlap = res.getDimensionPixelSize(R.dimen.qs_dual_tile_padding_vertical);
+ mBrightnessPaddingTop = res.getDimensionPixelSize(R.dimen.qs_brightness_padding_top);
+ if (isLaidOut()) {
+ if (mColumns != columns) {
+ mColumns = columns;
+ postInvalidate();
+ }
+ for (TileRecord r : mRecords) {
+ r.tile.clearState();
+ }
+ if (mListening) {
+ refreshAllTiles();
+ }
+ updateDetailText();
+ }
+ }
+
+ public boolean isAnimating(TileRecord t) {
+ return mCurrentlyAnimating.contains(t);
+ }
+
+ // todo implement proper add tile ui
+ protected void showAddDialog() {
+ List<String> tiles = mHost.getTileSpecs();
+ int numBroadcast = 0;
+ for (int i = 0; i < tiles.size(); i++) {
+ if (tiles.get(i).startsWith(IntentTile.PREFIX)) {
+ numBroadcast++;
+ }
+ }
+ String[] defaults =
+ getContext().getString(R.string.quick_settings_tiles_default).split(",");
+ int availableSize = defaults.length + 1 - (tiles.size() - numBroadcast);
+ if (availableSize < 1) {
+ availableSize = 1;
+ }
+ final String[] available = new String[availableSize];
+ final String[] availableTiles = new String[availableSize];
+ int index = 0;
+ for (int i = 0; i < defaults.length; i++) {
+ if (tiles.contains(defaults[i])) {
+ continue;
+ }
+ int resource = mHost.getLabelResource(defaults[i]);
+ if (resource != 0) {
+ availableTiles[index] = defaults[i];
+ available[index++] = getContext().getString(resource);
+ } else {
+ availableTiles[index] = defaults[i];
+ available[index++] = defaults[i];
+ }
+ }
+ available[index++] = getContext().getString(R.string.broadcast_tile);
+
+ final AlertDialog d = new AlertDialog.Builder(getContext(), R.style.Theme_SystemUI_Dialog)
+ .setTitle(R.string.add_tile)
+ .setItems(available, new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ if (which < available.length - 1) {
+ add(availableTiles[which]);
+ } else {
+ showBroadcastTileDialog();
+ }
+ }
+ }).create();
+ SystemUIDialog.makeSystemUIDialog(d);
+ d.show();
+ }
+
+ public void showBroadcastTileDialog() {
+ final EditText editText = new EditText(getContext());
+ final AlertDialog d = new AlertDialog.Builder(getContext())
+ .setTitle(R.string.broadcast_tile)
+ .setView(editText)
+ .setNegativeButton(android.R.string.cancel, null)
+ .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ String action = editText.getText().toString();
+ if (isValid(action)) {
+ add(IntentTile.PREFIX + action + ')');
+ }
+ }
+ }).create();
+ SystemUIDialog.makeSystemUIDialog(d);
+ d.show();
+ }
+
+ private boolean isValid(String action) {
+ for (int i = 0; i < action.length(); i++) {
+ char c = action.charAt(i);
+ if (!Character.isAlphabetic(c) && !Character.isDigit(c) && c != '.') {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public void add(String tile) {
+ MetricsLogger.action(getContext(), MetricsLogger.TUNER_QS_ADD, tile);
+ List<String> tiles = new ArrayList<>(mHost.getTileSpecs());
+ tiles.add(tile);
+ mHost.setTiles(tiles);
+ }
+
+ public boolean isDragging() {
+ return mDragging;
+ }
+
+ public boolean isDragRecordAttached() {
+ return mDragging && mDraggingRecord != null && mRecords.indexOf(mDraggingRecord) >= 0;
+ }
+
+ public void goToSettingsPage() {
+ if (mEditing) {
+ mViewPager.setCurrentItem(0, true);
+ }
+ }
+
+ class SettingsObserver extends UserContentObserver {
+ SettingsObserver(Handler handler) {
+ super(handler);
+ }
+
+ @Override
+ protected void observe() {
+ super.observe();
+
+ ContentResolver resolver = mContext.getContentResolver();
+ resolver.registerContentObserver(CMSettings.Secure.getUriFor(
+ CMSettings.Secure.QS_USE_MAIN_TILES), false, this, UserHandle.USER_ALL);
+ update();
+ }
+
+ @Override
+ protected void unobserve() {
+ super.unobserve();
+
+ ContentResolver resolver = mContext.getContentResolver();
+ resolver.unregisterContentObserver(this);
+ }
+
+ @Override
+ public void update() {
+ ContentResolver resolver = mContext.getContentResolver();
+ int currentUserId = ActivityManager.getCurrentUser();
+ boolean firstRowLarge = CMSettings.Secure.getIntForUser(resolver,
+ CMSettings.Secure.QS_USE_MAIN_TILES, 1, currentUserId) == 1;
+ if (firstRowLarge != mFirstRowLarge) {
+ mFirstRowLarge = firstRowLarge;
+ setTiles(mHost.getTiles());
+ }
+ }
+ }
+
+ public static final class DragTileRecord extends TileRecord {
+ public int page;
+ public int destinationPage;
+ public PointF destination = new PointF();
+
+ @Override
+ public String toString() {
+ String label = tile instanceof QsTuner.DraggableTile ? tile.toString() :
+ tile.getClass().getSimpleName();
+
+ String p = "at page: " + page;
+ if (destinationPage != page) {
+ p += "{-> " + destinationPage + "} ";
+ }
+
+ return "[" + label + ", coords: (" + row + ", " + col + ") " + p + "]";
+ }
+ }
+
+ private static class TileShadow extends View.DragShadowBuilder {
+
+ public TileShadow(View view) {
+ super(view);
+ Drawable shadow = view.getContext().getDrawable(R.drawable.qs_tile_background_drag);
+ view.setBackground(shadow);
+ }
+
+ @Override
+ public void onDrawShadow(Canvas canvas) {
+ super.onDrawShadow(canvas);
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPage.java b/packages/SystemUI/src/com/android/systemui/qs/QSPage.java
new file mode 100644
index 0000000..be2f7e5
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPage.java
@@ -0,0 +1,147 @@
+package com.android.systemui.qs;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.util.Log;
+import android.view.View;
+import android.view.ViewGroup;
+import com.android.systemui.R;
+
+public class QSPage extends ViewGroup {
+
+ private static final String TAG = "QSPage";
+
+ static final float TILE_ASPECT = 1.2f;
+
+ private int mCellWidth;
+ private int mCellHeight;
+ private int mLargeCellWidth;
+ private int mLargeCellHeight;
+ private int mGridHeight;
+
+ private QSDragPanel mPanel;
+
+ private int mPage;
+
+ public QSPage(Context context, QSDragPanel panel, int page) {
+ super(context);
+ mPanel = panel;
+ mPage = page;
+ updateResources();
+ setClipChildren(false);
+ setClipToPadding(false);
+ setClipToOutline(false);
+ }
+
+ @Override
+ public boolean hasOverlappingRendering() {
+ return false;
+ }
+
+ public int getPageIndex() {
+ return mPage;
+ }
+
+ public void updateResources() {
+ final Resources res = mContext.getResources();
+ final int columns = Math.max(1, res.getInteger(R.integer.quick_settings_num_columns));
+ mCellHeight = res.getDimensionPixelSize(R.dimen.qs_tile_height);
+ mCellWidth = (int)(mCellHeight * TILE_ASPECT);
+ mLargeCellHeight = res.getDimensionPixelSize(R.dimen.qs_dual_tile_height);
+ mLargeCellWidth = (int)(mLargeCellHeight * TILE_ASPECT);
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ final int width = MeasureSpec.getSize(widthMeasureSpec);
+ if (mPanel.mCurrentlyAnimating.isEmpty() && !mPanel.isDragging()) {
+ int r = -1;
+ int c = -1;
+ int rows = 0;
+ for (QSPanel.TileRecord ts : mPanel.mRecords) {
+ QSDragPanel.DragTileRecord record = (QSDragPanel.DragTileRecord) ts;
+ if (record.page != mPage) continue;
+ if (record.tileView.getVisibility() == GONE) continue;
+
+ if (mPage == 0 && r == 0 && c == 1 && mPanel.mFirstRowLarge) {
+ r = 1;
+ c = 0;
+ } else if (r == -1 || c == (mPanel.getColumnCount() - 1)) {
+ r++;
+ c = 0;
+ } else {
+ c++;
+ }
+ record.row = r;
+ record.col = c;
+ rows = r + 1;
+ }
+ mGridHeight = mPanel.getRowTop(rows);
+ }
+
+ View previousView = mPanel.getBrightnessView();
+ for (QSPanel.TileRecord ts : mPanel.mRecords) {
+ QSDragPanel.DragTileRecord record = (QSDragPanel.DragTileRecord) ts;
+ if (record.page != mPage) continue;
+ if (record.page != record.destinationPage) continue;
+
+ final boolean dual = dualRecord(record);
+ if (record.tileView.setDual(dual, record.tile.hasDualTargetsDetails())) {
+ record.tileView.handleStateChanged(record.tile.getState());
+ }
+ if (record.tileView.getVisibility() == GONE) continue;
+ final int cw = dual ? mLargeCellWidth : mCellWidth;
+ final int ch = dual ? mLargeCellHeight : mCellHeight;
+ record.tileView.measure(exactly(cw), exactly(ch));
+ previousView = record.tileView.updateAccessibilityOrder(previousView);
+ }
+ setMeasuredDimension(width, mGridHeight);
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int l, int t, int r, int b) {
+ final int w = getWidth();
+ boolean isRtl = getLayoutDirection() == LAYOUT_DIRECTION_RTL;
+ for (QSPanel.TileRecord ts : mPanel.mRecords) {
+ QSDragPanel.DragTileRecord record = (QSDragPanel.DragTileRecord) ts;
+ if (record.page != mPage) continue;
+ if (record.page != record.destinationPage) continue;
+ if (record.tileView.getVisibility() == GONE) continue;
+
+ final int cols = mPanel.getColumnCount(mPage, record.row);
+
+ int left = mPanel.getLeft(record.row, record.col, cols, dualRecord(record));
+ final int top = mPanel.getRowTop(record.row);
+ int right;
+ int tileWith = record.tileView.getMeasuredWidth();
+ if (isRtl) {
+ right = w - left;
+ left = right - tileWith;
+ } else {
+ right = left + tileWith;
+ }
+ if (mPanel.isAnimating(record)) continue;
+ if (false) {
+ Log.v(TAG + "-" + mPage, "laying out " + record + ", top: " + top + ", left: " + left);
+ Log.d(TAG, record + " wiping translations: "
+ + record.tileView.getTranslationX()
+ + ", " + record.tileView.getTranslationY());
+ }
+ record.tileView.setTranslationX(0);
+ record.tileView.setTranslationY(0);
+
+ record.destination.x = record.tileView.getX();
+ record.destination.y = record.tileView.getY();
+
+ record.tileView.layout(left, top, right, top + record.tileView.getMeasuredHeight());
+ }
+ }
+
+ public boolean dualRecord(QSPanel.TileRecord record) {
+ return mPanel.mFirstRowLarge && record.row == 0 && mPage == 0;
+ }
+
+ private static int exactly(int size) {
+ return MeasureSpec.makeMeasureSpec(size, MeasureSpec.EXACTLY);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index 94d5170..1e6867d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -25,6 +25,8 @@ import android.content.res.Configuration;
import android.content.res.Resources;
import android.os.Handler;
import android.os.Message;
+import android.os.UserHandle;
+import android.provider.Settings;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
@@ -45,39 +47,41 @@ import com.android.systemui.statusbar.policy.BrightnessMirrorController;
import java.util.ArrayList;
import java.util.Collection;
+import cyanogenmod.app.StatusBarPanelCustomTile;
+import cyanogenmod.providers.CMSettings;
+
/** View that represents the quick settings tile panel. **/
public class QSPanel extends ViewGroup {
- private static final float TILE_ASPECT = 1.2f;
-
- private final Context mContext;
- protected final ArrayList<TileRecord> mRecords = new ArrayList<TileRecord>();
- private final View mDetail;
- private final ViewGroup mDetailContent;
- private final TextView mDetailSettingsButton;
- private final TextView mDetailDoneButton;
- protected final View mBrightnessView;
- private final QSDetailClipper mClipper;
+ protected static final float TILE_ASPECT = 1.2f;
+
+ protected final ArrayList<TileRecord> mRecords = new ArrayList<>();
+ protected View mDetail;
+ protected ViewGroup mDetailContent;
+ protected TextView mDetailSettingsButton;
+ protected TextView mDetailDoneButton;
+ protected View mBrightnessView;
+ protected QSDetailClipper mClipper;
private final H mHandler = new H();
- private int mColumns;
- private int mCellWidth;
- private int mCellHeight;
- private int mLargeCellWidth;
- private int mLargeCellHeight;
- private int mPanelPaddingBottom;
- private int mDualTileUnderlap;
- private int mBrightnessPaddingTop;
- private int mGridHeight;
+ protected int mColumns;
+ protected int mCellWidth;
+ protected int mCellHeight;
+ protected int mLargeCellWidth;
+ protected int mLargeCellHeight;
+ protected int mPanelPaddingBottom;
+ protected int mDualTileUnderlap;
+ protected int mBrightnessPaddingTop;
+ protected int mGridHeight;
private boolean mExpanded;
- private boolean mListening;
+ protected boolean mListening;
private boolean mClosingDetail;
- private Record mDetailRecord;
+ protected Record mDetailRecord;
private Callback mCallback;
- private BrightnessController mBrightnessController;
- private QSTileHost mHost;
+ protected BrightnessController mBrightnessController;
+ protected QSTileHost mHost;
- private QSFooter mFooter;
+ protected QSFooter mFooter;
private boolean mGridContentVisible = true;
public QSPanel(Context context) {
@@ -87,17 +91,23 @@ public class QSPanel extends ViewGroup {
public QSPanel(Context context, AttributeSet attrs) {
super(context, attrs);
mContext = context;
+ setupViews();
+ }
- mDetail = LayoutInflater.from(context).inflate(R.layout.qs_detail, this, false);
+ /**
+ * THIS IS OVERRIDDEN in QSDragPanel
+ */
+ protected void setupViews() {
+ mDetail = LayoutInflater.from(mContext).inflate(R.layout.qs_detail, this, false);
mDetailContent = (ViewGroup) mDetail.findViewById(android.R.id.content);
mDetailSettingsButton = (TextView) mDetail.findViewById(android.R.id.button2);
mDetailDoneButton = (TextView) mDetail.findViewById(android.R.id.button1);
updateDetailText();
mDetail.setVisibility(GONE);
mDetail.setClickable(true);
- mBrightnessView = LayoutInflater.from(context).inflate(
+ mBrightnessView = LayoutInflater.from(mContext).inflate(
R.layout.quick_settings_brightness_dialog, this, false);
- mFooter = new QSFooter(this, context);
+ mFooter = new QSFooter(this, mContext);
addView(mDetail);
addView(mBrightnessView);
addView(mFooter.getView());
@@ -118,7 +128,26 @@ public class QSPanel extends ViewGroup {
});
}
- private void updateDetailText() {
+ /**
+ * Enable/disable brightness slider.
+ */
+ protected boolean showBrightnessSlider() {
+ boolean brightnessSliderEnabled = CMSettings.System.getIntForUser(
+ mContext.getContentResolver(), CMSettings.System.QS_SHOW_BRIGHTNESS_SLIDER,
+ 1, UserHandle.USER_CURRENT) == 1;
+ ToggleSlider brightnessSlider = (ToggleSlider) findViewById(R.id.brightness_slider);
+ if (brightnessSliderEnabled) {
+ mBrightnessView.setVisibility(VISIBLE);
+ brightnessSlider.setVisibility(VISIBLE);
+ } else {
+ mBrightnessView.setVisibility(GONE);
+ brightnessSlider.setVisibility(GONE);
+ }
+ updateResources();
+ return brightnessSliderEnabled;
+ }
+
+ protected void updateDetailText() {
mDetailDoneButton.setText(R.string.quick_settings_done);
mDetailSettingsButton.setText(R.string.quick_settings_more_settings);
}
@@ -206,7 +235,7 @@ public class QSPanel extends ViewGroup {
if (mListening) {
refreshAllTiles();
}
- if (listening) {
+ if (listening && showBrightnessSlider()) {
mBrightnessController.registerCallbacks();
} else {
mBrightnessController.unregisterCallbacks();
@@ -236,11 +265,11 @@ public class QSPanel extends ViewGroup {
showDetail(show, r);
}
- private void showDetail(boolean show, Record r) {
+ protected void showDetail(boolean show, Record r) {
mHandler.obtainMessage(H.SHOW_DETAIL, show ? 1 : 0, 0, r).sendToTarget();
}
- private void setTileVisibility(View v, int visibility) {
+ protected void setTileVisibility(View v, int visibility) {
mHandler.obtainMessage(H.SET_TILE_VISIBILITY, visibility, 0, v).sendToTarget();
}
@@ -265,7 +294,7 @@ public class QSPanel extends ViewGroup {
}
}
- private void drawTile(TileRecord r, QSTile.State state) {
+ protected void drawTile(TileRecord r, QSTile.State state) {
final int visibility = state.visible ? VISIBLE : GONE;
setTileVisibility(r.tileView, visibility);
r.tileView.onStateChanged(state);
@@ -365,7 +394,7 @@ public class QSPanel extends ViewGroup {
}
}
- private void handleShowDetailTile(TileRecord r, boolean show) {
+ protected void handleShowDetailTile(TileRecord r, boolean show) {
if ((mDetailRecord != null) == show && mDetailRecord == r) return;
if (show) {
@@ -378,7 +407,7 @@ public class QSPanel extends ViewGroup {
handleShowDetailImpl(r, show, x, y);
}
- private void handleShowDetailImpl(Record r, boolean show, int x, int y) {
+ protected void handleShowDetailImpl(Record r, boolean show, int x, int y) {
boolean visibleDiff = (mDetailRecord != null) != show;
if (!visibleDiff && mDetailRecord == r) return; // already in right state
DetailAdapter detailAdapter = null;
@@ -433,7 +462,7 @@ public class QSPanel extends ViewGroup {
tileRecord.tileView.setVisibility(newVis);
}
}
- mBrightnessView.setVisibility(newVis);
+ mBrightnessView.setVisibility(showBrightnessSlider() ? newVis : GONE);
if (mGridContentVisible != visible) {
MetricsLogger.visibility(mContext, MetricsLogger.QS_PANEL, newVis);
}
@@ -458,15 +487,12 @@ public class QSPanel extends ViewGroup {
int r = -1;
int c = -1;
int rows = 0;
- boolean rowIsDual = false;
for (TileRecord record : mRecords) {
if (record.tileView.getVisibility() == GONE) continue;
// wrap to next column if we've reached the max # of columns
- // also don't allow dual + single tiles on the same row
- if (r == -1 || c == (mColumns - 1) || rowIsDual != record.tile.supportsDualTargets()) {
+ if (r == -1 || c == (mColumns - 1)) {
r++;
c = 0;
- rowIsDual = record.tile.supportsDualTargets();
} else {
c++;
}
@@ -477,7 +503,8 @@ public class QSPanel extends ViewGroup {
View previousView = mBrightnessView;
for (TileRecord record : mRecords) {
- if (record.tileView.setDual(record.tile.supportsDualTargets())) {
+ final boolean dualTarget = record.tile.hasDualTargetsDetails();
+ if (record.tileView.setDual(dualTarget, dualTarget)) {
record.tileView.handleStateChanged(record.tile.getState());
}
if (record.tileView.getVisibility() == GONE) continue;
@@ -535,7 +562,7 @@ public class QSPanel extends ViewGroup {
}
}
- private int getRowTop(int row) {
+ protected int getRowTop(int row) {
if (row <= 0) return mBrightnessView.getMeasuredHeight() + mBrightnessPaddingTop;
return mBrightnessView.getMeasuredHeight() + mBrightnessPaddingTop
+ mLargeCellHeight - mDualTileUnderlap + (row - 1) * mCellHeight;
@@ -556,13 +583,13 @@ public class QSPanel extends ViewGroup {
}
}
- private void fireToggleStateChanged(boolean state) {
+ protected void fireToggleStateChanged(boolean state) {
if (mCallback != null) {
mCallback.onToggleStateChanged(state);
}
}
- private void fireScanStateChanged(boolean state) {
+ protected void fireScanStateChanged(boolean state) {
if (mCallback != null) {
mCallback.onScanStateChanged(state);
}
@@ -589,14 +616,14 @@ public class QSPanel extends ViewGroup {
}
}
- private static class Record {
+ protected static class Record {
View detailView;
DetailAdapter detailAdapter;
int x;
int y;
}
- protected static final class TileRecord extends Record {
+ protected static class TileRecord extends Record {
public QSTile<?> tile;
public QSTileView tileView;
public int row;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanelTopView.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanelTopView.java
new file mode 100644
index 0000000..c2862e6
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanelTopView.java
@@ -0,0 +1,251 @@
+/*
+ * Copyright (C) 2015 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 com.android.systemui.qs;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.support.v4.view.animation.FastOutSlowInInterpolator;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.View;
+import android.view.ViewTreeObserver;
+import android.widget.FrameLayout;
+import android.widget.TextView;
+import com.android.systemui.R;
+
+public class QSPanelTopView extends FrameLayout {
+
+ private static final String TAG = "QSPanelTopView";
+
+ public static final int TOAST_DURATION = 2000;
+
+ protected View mEditTileInstructionView;
+ protected View mDropTarget;
+ protected View mBrightnessView;
+ protected TextView mToastView;
+
+ private boolean mEditing = false;
+ private boolean mDisplayingInstructions = false;
+ private boolean mDisplayingTrash = false;
+ private boolean mDisplayingToast = false;
+
+ private AnimatorSet mAnimator;
+
+ public QSPanelTopView(Context context, @Nullable AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public QSPanelTopView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
+ this(context, attrs, defStyleAttr, 0);
+ }
+
+ public QSPanelTopView(Context context, @Nullable AttributeSet attrs, int defStyleAttr,
+ int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ }
+
+ @Override
+ public boolean hasOverlappingRendering() {
+ return mEditing;
+ }
+
+ public View getDropTarget() {
+ return mDropTarget;
+ }
+
+ public View getBrightnessView() {
+ return mBrightnessView;
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ mDropTarget = findViewById(R.id.delete_container);
+ mEditTileInstructionView = findViewById(R.id.edit_container);
+ mBrightnessView = findViewById(R.id.brightness_container);
+ mToastView = (TextView) findViewById(R.id.qs_toast);
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ final int width = MeasureSpec.getSize(widthMeasureSpec);
+ mBrightnessView.measure(exactly(width), MeasureSpec.UNSPECIFIED);
+ int dh = mBrightnessView.getMeasuredHeight();
+
+ mDropTarget.measure(exactly(width), atMost(dh));
+ mEditTileInstructionView.measure(exactly(width), atMost(dh));
+ mToastView.measure(exactly(width), atMost(dh));
+
+ setMeasuredDimension(width, mBrightnessView.getMeasuredHeight());
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ boolean animateToState = !isLaidOut();
+ super.onLayout(changed, left, top, right, bottom);
+ if (animateToState) {
+ Log.e(TAG, "first layout animating to state!");
+ animateToState();
+ }
+ }
+
+ private static int atMost(int height) {
+ return MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST);
+ }
+
+ private static int exactly(int size) {
+ return MeasureSpec.makeMeasureSpec(size, MeasureSpec.EXACTLY);
+ }
+
+ public void setEditing(boolean editing) {
+ mEditing = editing;
+ if (editing) {
+ mDisplayingInstructions = true;
+ mDisplayingTrash = false;
+ } else {
+ mDisplayingInstructions = false;
+ mDisplayingTrash = false;
+ }
+ animateToState();
+ }
+
+ public void onStopDrag() {
+ mDisplayingTrash = false;
+ animateToState();
+ }
+
+ public void onStartDrag() {
+ mDisplayingTrash = true;
+ animateToState();
+ }
+
+ public void toast(int textStrResId) {
+ mDisplayingToast = true;
+ mToastView.setText(textStrResId);
+ animateToState();
+ }
+
+ private Runnable mAnimateRunnable = new Runnable() {
+ @Override
+ public void run() {
+ if (mAnimator != null) {
+ mAnimator.cancel();
+ }
+ mAnimator = new AnimatorSet();
+
+ final boolean showToast = mDisplayingToast;
+ final boolean showTrash = mDisplayingTrash && !mDisplayingToast;
+ final boolean showBrightness = !mEditing && !mDisplayingToast;
+ final boolean showInstructions = mEditing
+ && mDisplayingInstructions
+ && !mDisplayingTrash
+ && !mDisplayingToast;
+
+ /*Log.d(TAG, "animating to state: "
+ + " showBrightness: " + showBrightness
+ + " showInstructions: " + showInstructions
+ + " showTrash: " + showTrash
+ + " showToast: " + showToast
+ );*/
+
+ final Animator brightnessAnimator = showBrightnessSlider(showBrightness);
+ final Animator instructionAnimator = showInstructions(showInstructions);
+ final Animator trashAnimator = showTrash(showTrash);
+ final Animator toastAnimator = showToast(showToast);
+
+ mAnimator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ setLayerType(LAYER_TYPE_HARDWARE, null);
+
+ mDropTarget.setLayerType(LAYER_TYPE_HARDWARE, null);
+ mEditTileInstructionView.setLayerType(LAYER_TYPE_HARDWARE, null);
+ mBrightnessView.setLayerType(LAYER_TYPE_HARDWARE, null);
+ mToastView.setLayerType(LAYER_TYPE_HARDWARE, null);
+
+ mDropTarget.setVisibility(View.VISIBLE);
+ mEditTileInstructionView.setVisibility(View.VISIBLE);
+ mBrightnessView.setVisibility(View.VISIBLE);
+ mToastView.setVisibility(View.VISIBLE);
+
+ if (showToast) {
+ mToastView.bringToFront();
+ }
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mToastView.setVisibility(showToast ? View.VISIBLE : View.GONE);
+ mEditTileInstructionView.setVisibility(showInstructions ? View.VISIBLE : View.GONE);
+ mDropTarget.setVisibility(showTrash ? View.VISIBLE : View.GONE);
+ mBrightnessView.setVisibility(showBrightness ? View.VISIBLE : View.GONE);
+
+ setLayerType(LAYER_TYPE_NONE, null);
+
+ mDropTarget.setLayerType(LAYER_TYPE_NONE, null);
+ mEditTileInstructionView.setLayerType(LAYER_TYPE_NONE, null);
+ mBrightnessView.setLayerType(LAYER_TYPE_NONE, null);
+ mToastView.setLayerType(LAYER_TYPE_NONE, null);
+
+ if (showToast) {
+ mToastView.postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ mDisplayingToast = false;
+ animateToState();
+ }
+ }, TOAST_DURATION);
+ }
+ }
+ });
+
+ mAnimator.setDuration(500);
+ mAnimator.setInterpolator(new FastOutSlowInInterpolator());
+ mAnimator.setStartDelay(100);
+ mAnimator.playTogether(instructionAnimator, trashAnimator,
+ brightnessAnimator, toastAnimator);
+ mAnimator.start();
+ }
+ };
+
+ private void animateToState() {
+ post(mAnimateRunnable);
+ }
+ private Animator animateView(View v, boolean show) {
+ return ObjectAnimator.ofFloat(v, "translationY",
+ show ? 0 : -mBrightnessView.getMeasuredHeight());
+ }
+
+ private Animator showBrightnessSlider(boolean show) {
+ return animateView(mBrightnessView, show);
+ }
+
+ private Animator showInstructions(boolean show) {
+ return animateView(mEditTileInstructionView, show);
+ }
+
+ private Animator showTrash(boolean show) {
+ return animateView(mDropTarget, show);
+ }
+
+ private Animator showToast(boolean show) {
+ return animateView(mToastView, show);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSSettings.java b/packages/SystemUI/src/com/android/systemui/qs/QSSettings.java
new file mode 100644
index 0000000..959a1ee
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSSettings.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2015 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 com.android.systemui.qs;
+
+import android.annotation.Nullable;
+import android.app.AlertDialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.LinearLayout;
+import com.android.systemui.statusbar.phone.QSTileHost;
+import com.android.systemui.statusbar.phone.SystemUIDialog;
+
+import com.android.systemui.R;
+
+public class QSSettings extends LinearLayout {
+ private QSTileHost mHost;
+
+ public QSSettings(Context context) {
+ super(context);
+ }
+
+ public QSSettings(Context context, @Nullable AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+
+ findViewById(R.id.reset_tiles).setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ initiateTileReset();
+ }
+ });
+ }
+
+ private void initiateTileReset() {
+ final AlertDialog d = new AlertDialog.Builder(mContext)
+ .setMessage(R.string.qs_tiles_reset_confirmation)
+ .setNegativeButton(R.string.cancel, null)
+ .setPositiveButton(com.android.internal.R.string.reset,
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ mHost.resetTiles();
+ }
+ }).create();
+ SystemUIDialog.makeSystemUIDialog(d);
+ d.show();
+ }
+
+ public void setHost(QSTileHost host) {
+ mHost = host;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
index e4a37fb..7d7e516 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
@@ -20,7 +20,9 @@ import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.graphics.drawable.Animatable;
+import android.graphics.Bitmap;
import android.graphics.drawable.AnimatedVectorDrawable;
+import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.Looper;
@@ -30,6 +32,7 @@ import android.util.SparseArray;
import android.view.View;
import android.view.ViewGroup;
+import android.widget.RemoteViews;
import com.android.systemui.qs.QSTile.State;
import com.android.systemui.statusbar.policy.BluetoothController;
import com.android.systemui.statusbar.policy.CastController;
@@ -41,6 +44,7 @@ import com.android.systemui.statusbar.policy.LocationController;
import com.android.systemui.statusbar.policy.NetworkController;
import com.android.systemui.statusbar.policy.RotationLockController;
import com.android.systemui.statusbar.policy.ZenModeController;
+import cyanogenmod.app.StatusBarPanelCustomTile;
import java.util.Collection;
import java.util.Objects;
@@ -85,7 +89,7 @@ public abstract class QSTile<TState extends State> implements Listenable {
mHandler = new H(host.getLooper());
}
- public boolean supportsDualTargets() {
+ public boolean hasDualTargetsDetails() {
return false;
}
@@ -106,6 +110,7 @@ public abstract class QSTile<TState extends State> implements Listenable {
Boolean getToggleState();
View createDetailView(Context context, View convertView, ViewGroup parent);
Intent getSettingsIntent();
+ StatusBarPanelCustomTile getCustomTile();
void setToggleState(boolean state);
int getMetricsCategory();
}
@@ -320,10 +325,12 @@ public abstract class QSTile<TState extends State> implements Listenable {
}
public interface Host {
+ void removeCustomTile(StatusBarPanelCustomTile customTile);
void startActivityDismissingKeyguard(Intent intent);
void startActivityDismissingKeyguard(PendingIntent intent);
void warn(String message, Throwable t);
void collapsePanels();
+ RemoteViews.OnClickHandler getOnClickHandler();
Looper getLooper();
Context getContext();
Collection<QSTile<?>> getTiles();
@@ -337,9 +344,16 @@ public abstract class QSTile<TState extends State> implements Listenable {
CastController getCastController();
FlashlightController getFlashlightController();
KeyguardMonitor getKeyguardMonitor();
+ boolean isEditing();
+ void setEditing(boolean editing);
+ void resetTiles();
+ void goToSettingsPage();
public interface Callback {
void onTilesChanged();
+ void setEditing(boolean editing);
+ boolean isEditing();
+ void goToSettingsPage();
}
}
@@ -352,6 +366,42 @@ public abstract class QSTile<TState extends State> implements Listenable {
}
}
+ protected class ExternalIcon extends AnimationIcon {
+ private Context mPackageContext;
+ private String mPkg;
+ private int mResId;
+
+ public ExternalIcon(String pkg, int resId) {
+ super(resId);
+ mPkg = pkg;
+ mResId = resId;
+ }
+
+ @Override
+ public Drawable getDrawable(Context context) {
+ // Get the drawable from the package context
+ Drawable d = null;
+ try {
+ d = super.getDrawable(getPackageContext());
+ } catch (Throwable t) {
+ Log.w(TAG, "Error creating package context" + mPkg + " id=" + mResId, t);
+ }
+ return d;
+ }
+
+ private Context getPackageContext() {
+ if (mPackageContext == null) {
+ try {
+ mPackageContext = mContext.createPackageContext(mPkg, 0);
+ } catch (Throwable t) {
+ Log.w(TAG, "Error creating package context" + mPkg, t);
+ return null;
+ }
+ }
+ return mPackageContext;
+ }
+ }
+
public static class ResourceIcon extends Icon {
private static final SparseArray<Icon> ICONS = new SparseArray<Icon>();
@@ -390,6 +440,21 @@ public abstract class QSTile<TState extends State> implements Listenable {
}
}
+ protected class ExternalBitmapIcon extends Icon {
+ private Bitmap mBitmap;
+
+ public ExternalBitmapIcon(Bitmap bitmap) {
+ mBitmap = bitmap;
+ }
+
+ @Override
+ public Drawable getDrawable(Context context) {
+ // This is gross
+ BitmapDrawable bitmapDrawable = new BitmapDrawable(context.getResources(), mBitmap);
+ return bitmapDrawable;
+ }
+ }
+
protected class AnimationIcon extends ResourceIcon {
private boolean mAllowAnimation;
@@ -404,13 +469,14 @@ public abstract class QSTile<TState extends State> implements Listenable {
@Override
public Drawable getDrawable(Context context) {
// workaround: get a clean state for every new AVD
- final AnimatedVectorDrawable d = (AnimatedVectorDrawable) context.getDrawable(mResId)
- .getConstantState().newDrawable();
- d.start();
- if (mAllowAnimation) {
- mAllowAnimation = false;
- } else {
- d.stop(); // skip directly to end state
+ final Drawable d = super.getDrawable(context).getConstantState().newDrawable();
+ if (d instanceof AnimatedVectorDrawable) {
+ ((AnimatedVectorDrawable)d).start();
+ if (mAllowAnimation) {
+ mAllowAnimation = false;
+ } else {
+ ((AnimatedVectorDrawable)d).stop(); // skip directly to end state
+ }
}
return d;
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java
index 6d26a3b..667bd30 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2014 The Android Open Source Project
+ * Copyright (C) 2015 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.
@@ -16,6 +17,7 @@
package com.android.systemui.qs;
+import android.annotation.Nullable;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
@@ -27,6 +29,7 @@ import android.graphics.drawable.RippleDrawable;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
+import android.util.Log;
import android.util.MathUtils;
import android.util.TypedValue;
import android.view.Gravity;
@@ -48,6 +51,8 @@ public class QSTileView extends ViewGroup {
private static final Typeface CONDENSED = Typeface.create("sans-serif-condensed",
Typeface.NORMAL);
+ private static final String TAG = "QSTileView";
+
protected final Context mContext;
private final View mIcon;
private final View mDivider;
@@ -62,6 +67,7 @@ public class QSTileView extends ViewGroup {
private TextView mLabel;
private QSDualTileLabel mDualLabel;
private boolean mDual;
+ private boolean mDualDetails;
private OnClickListener mClickPrimary;
private OnClickListener mClickSecondary;
private OnLongClickListener mLongClick;
@@ -122,6 +128,7 @@ public class QSTileView extends ViewGroup {
}
private void recreateLabel() {
+ Log.d(TAG, "recreateLabel() called with " + "");
CharSequence labelText = null;
CharSequence labelDescription = null;
if (mLabel != null) {
@@ -131,7 +138,7 @@ public class QSTileView extends ViewGroup {
}
if (mDualLabel != null) {
labelText = mDualLabel.getText();
- labelDescription = mLabel.getContentDescription();
+ labelDescription = mDualLabel.getContentDescription();
removeView(mDualLabel);
mDualLabel = null;
}
@@ -140,15 +147,18 @@ public class QSTileView extends ViewGroup {
mDualLabel = new QSDualTileLabel(mContext);
mDualLabel.setId(View.generateViewId());
mDualLabel.setBackgroundResource(R.drawable.btn_borderless_rect);
- mDualLabel.setFirstLineCaret(mContext.getDrawable(R.drawable.qs_dual_tile_caret));
+ if (mDualDetails) {
+ mDualLabel.setFirstLineCaret(mContext.getDrawable(R.drawable.qs_dual_tile_caret));
+ }
mDualLabel.setTextColor(mContext.getColor(R.color.qs_tile_text));
mDualLabel.setPadding(0, mDualTileVerticalPaddingPx, 0, mDualTileVerticalPaddingPx);
mDualLabel.setTypeface(CONDENSED);
mDualLabel.setTextSize(TypedValue.COMPLEX_UNIT_PX,
res.getDimensionPixelSize(R.dimen.qs_tile_text_size));
mDualLabel.setClickable(true);
- mDualLabel.setOnClickListener(mClickSecondary);
mDualLabel.setFocusable(true);
+ mDualLabel.setOnClickListener(mDualDetails ? mClickSecondary : mClickPrimary);
+ mDualLabel.setOnLongClickListener(mLongClick);
if (labelText != null) {
mDualLabel.setText(labelText);
}
@@ -167,6 +177,7 @@ public class QSTileView extends ViewGroup {
mLabel.setTextSize(TypedValue.COMPLEX_UNIT_PX,
res.getDimensionPixelSize(R.dimen.qs_tile_text_size));
mLabel.setClickable(false);
+ mLabel.setFocusable(false);
if (labelText != null) {
mLabel.setText(labelText);
}
@@ -174,39 +185,55 @@ public class QSTileView extends ViewGroup {
}
}
- public boolean setDual(boolean dual) {
+ public boolean isDual() {
+ return mDual;
+ }
+
+ public boolean setDual(boolean dual, boolean hasDetails) {
final boolean changed = dual != mDual;
mDual = dual;
+ mDualDetails = hasDetails;
if (changed) {
recreateLabel();
}
- if (mTileBackground instanceof RippleDrawable) {
- setRipple((RippleDrawable) mTileBackground);
- }
+
if (dual) {
mTopBackgroundView.setOnClickListener(mClickPrimary);
+ mTopBackgroundView.setOnLongClickListener(mLongClick);
setOnClickListener(null);
- setClickable(false);
+ setOnLongClickListener(null);
setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
- mTopBackgroundView.setBackground(mTileBackground);
} else {
mTopBackgroundView.setOnClickListener(null);
- mTopBackgroundView.setClickable(false);
+ mTopBackgroundView.setOnLongClickListener(null);
setOnClickListener(mClickPrimary);
setOnLongClickListener(mLongClick);
setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
- setBackground(mTileBackground);
}
+ setTileBackground();
+ mTopBackgroundView.setClickable(dual);
mTopBackgroundView.setFocusable(dual);
+ setClickable(!dual);
setFocusable(!dual);
mDivider.setVisibility(dual ? VISIBLE : GONE);
+ mTopBackgroundView.setVisibility(dual ? VISIBLE : GONE);
postInvalidate();
return changed;
}
+ protected void setTileBackground() {
+ if (mTileBackground instanceof RippleDrawable) {
+ setRipple((RippleDrawable) mTileBackground);
+ } else {
+ setRipple(null);
+ }
+ mTopBackgroundView.setBackground(mDual ? mTileBackground : null);
+ setBackground(!mDual ? mTileBackground : null);
+ }
+
private void setRipple(RippleDrawable tileBackground) {
mRipple = tileBackground;
- if (getWidth() != 0) {
+ if (getWidth() != 0 && mRipple != null) {
updateRippleSize(getWidth(), getHeight());
}
}
@@ -225,7 +252,7 @@ public class QSTileView extends ViewGroup {
return icon;
}
- private Drawable newTileBackground() {
+ public Drawable newTileBackground() {
final int[] attrs = new int[] { android.R.attr.selectableItemBackgroundBorderless };
final TypedArray ta = mContext.obtainStyledAttributes(attrs);
final Drawable d = ta.getDrawable(0);
@@ -285,7 +312,7 @@ public class QSTileView extends ViewGroup {
private void updateRippleSize(int width, int height) {
// center the touch feedback on the center of the icon, and dial it down a bit
final int cx = width / 2;
- final int cy = mDual ? mIcon.getTop() + mIcon.getHeight() / 2 : height / 2;
+ final int cy = mDual ? mIcon.getTop() + mIcon.getHeight() : height / 2;
final int rad = (int)(mIcon.getHeight() * 1.25f);
mRipple.setHotspotBounds(cx - rad, cy - rad, cx + rad, cy + rad);
}
@@ -349,6 +376,26 @@ public class QSTileView extends ViewGroup {
return lastView;
}
+ public void setEditing(boolean editing) {
+ if (mDual) {
+ if (mTopBackgroundView != null) {
+ mTopBackgroundView.setFocusable(!editing);
+ mTopBackgroundView.setClickable(!editing);
+ }
+ if (mDualLabel != null) {
+ mDualLabel.setFocusable(!editing);
+ mDualLabel.setClickable(!editing);
+ }
+ setClickable(editing);
+ setFocusable(editing);
+ } else {
+ if (mLabel != null) {
+ mLabel.setFocusable(!editing);
+ }
+ mRipple.setVisible(!editing, false);
+ }
+ }
+
private class H extends Handler {
private static final int STATE_CHANGED = 1;
public H() {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSViewPager.java b/packages/SystemUI/src/com/android/systemui/qs/QSViewPager.java
new file mode 100644
index 0000000..01c48b1
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSViewPager.java
@@ -0,0 +1,132 @@
+package com.android.systemui.qs;
+
+import android.animation.Animator;
+import android.animation.ValueAnimator;
+import android.content.Context;
+import android.support.v4.view.ViewPager;
+import android.util.Log;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.animation.AccelerateInterpolator;
+
+public class QSViewPager extends ViewPager {
+
+ private static final String TAG = "QSViewPager";
+
+ protected static final float SCROLL_PERCENT = .10f;
+ private boolean mPagingEnabled;
+ QSDragPanel mDragPanel;
+
+ public QSViewPager(Context context) {
+ super(context);
+ }
+
+ public void setDragPanel(QSDragPanel p) {
+ mDragPanel = p;
+ }
+
+ @Override
+ public boolean hasOverlappingRendering() {
+ return mDragPanel.isEditing();
+ }
+
+ @Override
+ public boolean canScrollHorizontally(int direction) {
+ if (direction < 0
+ && mDragPanel.isDragging()
+ && mPagingEnabled
+ && getCurrentItem() == 1) {
+ // can't scroll left while not editing, OR dragging on the first page
+ return false;
+ }
+ return super.canScrollHorizontally(direction);
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ int height = 0;
+ for (int i = 0; i < getChildCount(); i++) {
+ View child = getChildAt(i);
+ child.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
+ int h = child.getMeasuredHeight();
+ if (h > height) height = h;
+ }
+ heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ }
+
+ public void animatePagerTransition(final boolean forward) {
+ ValueAnimator animator = ValueAnimator.ofInt(0, getWidth());
+ animator.addListener(new Animator.AnimatorListener() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ if (isFakeDragging()) {
+ endFakeDrag();
+ }
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ if (isFakeDragging()) {
+ endFakeDrag();
+ }
+ }
+
+ @Override
+ public void onAnimationRepeat(Animator animation) {
+ }
+ });
+
+ animator.setInterpolator(new AccelerateInterpolator());
+ animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+
+ private int oldDragPosition = 0;
+
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ if (isFakeDragging()) {
+ int dragPosition = (Integer) animation.getAnimatedValue();
+ int dragOffset = dragPosition - oldDragPosition;
+ oldDragPosition = dragPosition;
+ fakeDragBy(dragOffset * (forward ? -1 : 1));
+ }
+ }
+ });
+ if (beginFakeDrag()) {
+ animator.setDuration(500);
+ animator.start();
+ } else {
+ Log.e(TAG, "can't start fake drag?");
+ }
+ }
+
+ @Override
+ public boolean onInterceptTouchEvent(MotionEvent event) {
+ if (mPagingEnabled) {
+ return super.onInterceptTouchEvent(event);
+ }
+ return false;
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ if (mPagingEnabled) {
+ return super.onTouchEvent(event);
+ }
+ return false;
+ }
+
+ public void setPagingEnabled(boolean enabled) {
+ if (mPagingEnabled == enabled) return;
+ mPagingEnabled = enabled;
+ //Log.i(TAG, "setPagingEnabled() called with " + "enabled = [" + enabled + "]");
+ if (getCurrentItem() > 0 && !mPagingEnabled) {
+ //Log.w(TAG, "resetting to item 0 because paging is disabled.");
+ setCurrentItem(0, true);
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
index 49f8d1c..bf28dbf 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2014 The Android Open Source Project
+ * Copyright (C) 2015 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.
@@ -21,6 +22,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.ConnectivityManager;
+import android.provider.Settings;
import android.provider.Settings.Global;
import com.android.internal.logging.MetricsLogger;
@@ -30,6 +32,9 @@ import com.android.systemui.qs.QSTile;
/** Quick settings tile: Airplane mode **/
public class AirplaneModeTile extends QSTile<QSTile.BooleanState> {
+
+ private static final Intent WIRELESS_SETTINGS = new Intent(Settings.ACTION_WIRELESS_SETTINGS);
+
private final AnimationIcon mEnable =
new AnimationIcon(R.drawable.ic_signal_airplane_enable_animation);
private final AnimationIcon mDisable =
@@ -62,6 +67,11 @@ public class AirplaneModeTile extends QSTile<QSTile.BooleanState> {
mDisable.setAllowAnimation(true);
}
+ @Override
+ public void handleLongClick() {
+ mHost.startActivityDismissingKeyguard(WIRELESS_SETTINGS);
+ }
+
private void setEnabled(boolean enabled) {
final ConnectivityManager mgr =
(ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
index abce31f..a798e4e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2014 The Android Open Source Project
+ * Copyright (C) 2015 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.
@@ -24,17 +25,25 @@ import android.provider.Settings;
import android.text.TextUtils;
import android.view.View;
import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.ListView;
import com.android.internal.logging.MetricsLogger;
+
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
+
import com.android.systemui.R;
import com.android.systemui.qs.QSDetailItems;
import com.android.systemui.qs.QSDetailItems.Item;
+import com.android.systemui.qs.QSDetailItemsList;
import com.android.systemui.qs.QSTile;
import com.android.systemui.statusbar.policy.BluetoothController;
+import cyanogenmod.app.StatusBarPanelCustomTile;
+
+import java.util.ArrayList;
import java.util.Collection;
-import java.util.Set;
+import java.util.List;
/** Quick settings tile: Bluetooth **/
public class BluetoothTile extends QSTile<QSTile.BooleanState> {
@@ -50,7 +59,7 @@ public class BluetoothTile extends QSTile<QSTile.BooleanState> {
}
@Override
- public boolean supportsDualTargets() {
+ public boolean hasDualTargetsDetails() {
return true;
}
@@ -90,6 +99,11 @@ public class BluetoothTile extends QSTile<QSTile.BooleanState> {
}
@Override
+ protected void handleLongClick() {
+ mHost.startActivityDismissingKeyguard(BLUETOOTH_SETTINGS);
+ }
+
+ @Override
protected void handleUpdateState(BooleanState state, Object arg) {
final boolean supported = mController.isBluetoothSupported();
final boolean enabled = mController.isBluetoothEnabled();
@@ -165,8 +179,11 @@ public class BluetoothTile extends QSTile<QSTile.BooleanState> {
}
};
- private final class BluetoothDetailAdapter implements DetailAdapter, QSDetailItems.Callback {
- private QSDetailItems mItems;
+ private final class BluetoothDetailAdapter implements DetailAdapter,
+ QSDetailItems.Callback, AdapterView.OnItemClickListener {
+ private QSDetailItemsList mItemsList;
+ private QSDetailItemsList.QSDetailListAdapter mAdapter;
+ private List<Item> mBluetoothItems = new ArrayList<>();
@Override
public int getTitle() {
@@ -184,6 +201,11 @@ public class BluetoothTile extends QSTile<QSTile.BooleanState> {
}
@Override
+ public StatusBarPanelCustomTile getCustomTile() {
+ return null;
+ }
+
+ @Override
public void setToggleState(boolean state) {
MetricsLogger.action(mContext, MetricsLogger.QS_BLUETOOTH_TOGGLE, state);
mController.setBluetoothEnabled(state);
@@ -197,29 +219,34 @@ public class BluetoothTile extends QSTile<QSTile.BooleanState> {
@Override
public View createDetailView(Context context, View convertView, ViewGroup parent) {
- mItems = QSDetailItems.convertOrInflate(context, convertView, parent);
- mItems.setTagSuffix("Bluetooth");
- mItems.setEmptyState(R.drawable.ic_qs_bluetooth_detail_empty,
+ mItemsList = QSDetailItemsList.convertOrInflate(context, convertView, parent);
+ ListView listView = mItemsList.getListView();
+ listView.setDivider(null);
+ listView.setOnItemClickListener(this);
+ listView.setAdapter(mAdapter =
+ new QSDetailItemsList.QSDetailListAdapter(context, mBluetoothItems));
+ mItemsList.setEmptyState(R.drawable.ic_qs_bluetooth_detail_empty,
R.string.quick_settings_bluetooth_detail_empty_text);
- mItems.setCallback(this);
- mItems.setMinHeightInItems(0);
+
updateItems();
- setItemsVisible(mState.value);
- return mItems;
+ return mItemsList;
}
public void setItemsVisible(boolean visible) {
- if (mItems == null) return;
- mItems.setItemsVisible(visible);
+ if (mAdapter == null) return;
+ if (visible) {
+ updateItems();
+ } else {
+ mBluetoothItems.clear();
+ }
+ mAdapter.notifyDataSetChanged();
}
private void updateItems() {
- if (mItems == null) return;
- Item[] items = null;
- final Collection<CachedBluetoothDevice> devices = mController.getDevices();
+ if (mAdapter == null) return;
+ final Collection<CachedBluetoothDevice> devices = mController.getDevices();
if (devices != null) {
- items = new Item[getBondedCount(devices)];
- int i = 0;
+ mBluetoothItems.clear();
for (CachedBluetoothDevice device : devices) {
if (device.getBondState() == BluetoothDevice.BOND_NONE) continue;
final Item item = new Item();
@@ -235,10 +262,10 @@ public class BluetoothTile extends QSTile<QSTile.BooleanState> {
item.line2 = mContext.getString(R.string.quick_settings_connecting);
}
item.tag = device;
- items[i++] = item;
+ mBluetoothItems.add(item);
}
}
- mItems.setItems(items);
+ mAdapter.notifyDataSetChanged();
}
private int getBondedCount(Collection<CachedBluetoothDevice> devices) {
@@ -253,12 +280,7 @@ public class BluetoothTile extends QSTile<QSTile.BooleanState> {
@Override
public void onDetailItemClick(Item item) {
- if (item == null || item.tag == null) return;
- final CachedBluetoothDevice device = (CachedBluetoothDevice) item.tag;
- if (device != null && device.getMaxConnectionState()
- == BluetoothProfile.STATE_DISCONNECTED) {
- mController.connect(device);
- }
+ // noop
}
@Override
@@ -269,5 +291,16 @@ public class BluetoothTile extends QSTile<QSTile.BooleanState> {
mController.disconnect(device);
}
}
+
+ @Override
+ public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+ Item item = (Item) parent.getItemAtPosition(position);
+ if (item == null || item.tag == null) return;
+ final CachedBluetoothDevice device = (CachedBluetoothDevice) item.tag;
+ if (device != null && device.getMaxConnectionState()
+ == BluetoothProfile.STATE_DISCONNECTED) {
+ mController.connect(device);
+ }
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
index 61695b2..f83bbf4 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2014 The Android Open Source Project
+ * Copyright (C) 2015 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.
@@ -32,6 +33,7 @@ import com.android.systemui.qs.QSTile;
import com.android.systemui.statusbar.policy.CastController;
import com.android.systemui.statusbar.policy.CastController.CastDevice;
import com.android.systemui.statusbar.policy.KeyguardMonitor;
+import cyanogenmod.app.StatusBarPanelCustomTile;
import java.util.LinkedHashMap;
import java.util.Set;
@@ -91,6 +93,16 @@ public class CastTile extends QSTile<QSTile.BooleanState> {
}
@Override
+ protected void handleSecondaryClick() {
+ handleClick();
+ }
+
+ @Override
+ protected void handleLongClick() {
+ mHost.startActivityDismissingKeyguard(CAST_SETTINGS);
+ }
+
+ @Override
protected void handleUpdateState(BooleanState state, Object arg) {
state.visible = !mKeyguard.isSecure() || !mKeyguard.isShowing()
|| mKeyguard.canSkipBouncer();
@@ -129,6 +141,11 @@ public class CastTile extends QSTile<QSTile.BooleanState> {
return null;
}
+ @Override
+ public boolean hasDualTargetsDetails() {
+ return true;
+ }
+
private String getDeviceName(CastDevice device) {
return device.name != null ? device.name
: mContext.getString(R.string.quick_settings_cast_device_default_name);
@@ -167,6 +184,11 @@ public class CastTile extends QSTile<QSTile.BooleanState> {
}
@Override
+ public StatusBarPanelCustomTile getCustomTile() {
+ return null;
+ }
+
+ @Override
public void setToggleState(boolean state) {
// noop
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
index f3ad9d8..426cf4b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2014 The Android Open Source Project
+ * Copyright (C) 2015 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.
@@ -20,6 +21,7 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
+import android.telephony.TelephonyManager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -35,15 +37,26 @@ import com.android.systemui.statusbar.policy.NetworkController.MobileDataControl
import com.android.systemui.statusbar.policy.NetworkController.MobileDataController.DataUsageInfo;
import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
import com.android.systemui.statusbar.policy.SignalCallbackAdapter;
+import cyanogenmod.app.StatusBarPanelCustomTile;
/** Quick settings tile: Cellular **/
public class CellularTile extends QSTile<QSTile.SignalState> {
- private static final Intent CELLULAR_SETTINGS = new Intent().setComponent(new ComponentName(
+
+ private static final Intent DATA_USAGE_SETTINGS = new Intent().setComponent(new ComponentName(
"com.android.settings", "com.android.settings.Settings$DataUsageSummaryActivity"));
+ private static final Intent MOBILE_NETWORK_SETTINGS = new Intent(Intent.ACTION_MAIN)
+ .setComponent(new ComponentName("com.android.phone",
+ "com.android.phone.MobileNetworkSettings"));
+ private static final Intent MOBILE_NETWORK_SETTINGS_MSIM = new Intent(Intent.ACTION_MAIN)
+ .setClassName("com.android.phone", "com.android.phone.msim.SelectSubscription")
+ .putExtra("PACKAGE", "com.android.phone")
+ .putExtra("TARGET_CLASS", "com.android.phone.MobileNetworkSettings")
+ .putExtra("TARGET_THEME", "Theme.Material.Settings");
private final NetworkController mController;
private final MobileDataController mDataController;
private final CellularDetailAdapter mDetailAdapter;
+ private final TelephonyManager mTelephonyManager;
private final CellSignalCallback mSignalCallback = new CellSignalCallback();
@@ -52,6 +65,7 @@ public class CellularTile extends QSTile<QSTile.SignalState> {
mController = host.getNetworkController();
mDataController = mController.getMobileDataController();
mDetailAdapter = new CellularDetailAdapter();
+ mTelephonyManager = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
}
@Override
@@ -84,7 +98,21 @@ public class CellularTile extends QSTile<QSTile.SignalState> {
if (mDataController.isMobileDataSupported()) {
showDetail(true);
} else {
- mHost.startActivityDismissingKeyguard(CELLULAR_SETTINGS);
+ mHost.startActivityDismissingKeyguard(DATA_USAGE_SETTINGS);
+ }
+ }
+
+ @Override
+ protected void handleSecondaryClick() {
+ handleClick();
+ }
+
+ @Override
+ protected void handleLongClick() {
+ if (mTelephonyManager.getDefault().getPhoneCount() > 1) {
+ mHost.startActivityDismissingKeyguard(MOBILE_NETWORK_SETTINGS_MSIM);
+ } else {
+ mHost.startActivityDismissingKeyguard(MOBILE_NETWORK_SETTINGS);
}
}
@@ -131,6 +159,11 @@ public class CellularTile extends QSTile<QSTile.SignalState> {
return MetricsLogger.QS_CELLULAR;
}
+ @Override
+ public boolean hasDualTargetsDetails() {
+ return true;
+ }
+
// Remove the period from the network name
public static String removeTrailingPeriod(String string) {
if (string == null) return null;
@@ -167,8 +200,9 @@ public class CellularTile extends QSTile<QSTile.SignalState> {
@Override
public void setMobileDataIndicators(IconState statusIcon, IconState qsIcon, int statusType,
- int qsType, boolean activityIn, boolean activityOut, String typeContentDescription,
- String description, boolean isWide, int subId) {
+ int qsType, boolean activityIn, boolean activityOut, int dataActivityId,
+ int mobileActivityId, int stackedDataIcon, int stackedVoiceIcon,
+ String typeContentDescription, String description, boolean isWide, int subId) {
if (qsIcon == null) {
// Not data sim, don't display.
return;
@@ -214,6 +248,10 @@ public class CellularTile extends QSTile<QSTile.SignalState> {
};
private final class CellularDetailAdapter implements DetailAdapter {
+ @Override
+ public StatusBarPanelCustomTile getCustomTile() {
+ return null;
+ }
@Override
public int getTitle() {
@@ -229,7 +267,7 @@ public class CellularTile extends QSTile<QSTile.SignalState> {
@Override
public Intent getSettingsIntent() {
- return CELLULAR_SETTINGS;
+ return DATA_USAGE_SETTINGS;
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
index c6fc6ff..04cc5dc 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2014 The Android Open Source Project
+ * Copyright (C) 2015 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.
@@ -16,6 +17,8 @@
package com.android.systemui.qs.tiles;
+import android.content.Intent;
+import android.provider.Settings;
import android.provider.Settings.Secure;
import com.android.internal.logging.MetricsLogger;
@@ -28,6 +31,9 @@ import com.android.systemui.qs.UsageTracker;
/** Quick settings tile: Invert colors **/
public class ColorInversionTile extends QSTile<QSTile.BooleanState> {
+ private static final Intent ACCESSIBILITY_SETTINGS = new Intent(
+ Settings.ACTION_ACCESSIBILITY_SETTINGS);
+
private final AnimationIcon mEnable
= new AnimationIcon(R.drawable.ic_invert_colors_enable_animation);
private final AnimationIcon mDisable
@@ -95,15 +101,18 @@ public class ColorInversionTile extends QSTile<QSTile.BooleanState> {
@Override
protected void handleLongClick() {
- if (mState.value) return; // don't allow usage reset if inversion is active
- final String title = mContext.getString(R.string.quick_settings_reset_confirmation_title,
- mState.label);
- mUsageTracker.showResetConfirmation(title, new Runnable() {
- @Override
- public void run() {
- refreshState();
- }
- });
+ if (mState.value) {
+ mHost.startActivityDismissingKeyguard(ACCESSIBILITY_SETTINGS);
+ } else {
+ final String title = mContext.getString(
+ R.string.quick_settings_reset_confirmation_title, mState.label);
+ mUsageTracker.showResetConfirmation(title, new Runnable() {
+ @Override
+ public void run() {
+ refreshState();
+ }
+ });
+ }
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CustomQSTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CustomQSTile.java
new file mode 100644
index 0000000..4bc30a4
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CustomQSTile.java
@@ -0,0 +1,269 @@
+/*
+ * Copyright (C) 2015 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 com.android.systemui.qs.tiles;
+
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.Configuration;
+import android.content.res.ThemeConfig;
+import android.net.Uri;
+import android.os.UserHandle;
+import android.text.TextUtils;
+import android.util.Log;
+
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.ListView;
+import android.widget.RemoteViews;
+import android.widget.TextView;
+
+import com.android.internal.logging.MetricsLogger;
+
+import com.android.systemui.qs.QSDetailItemsGrid;
+import com.android.systemui.qs.QSDetailItemsList;
+import cyanogenmod.app.CustomTile;
+import cyanogenmod.app.StatusBarPanelCustomTile;
+
+import com.android.systemui.R;
+import com.android.systemui.qs.QSTile;
+
+import java.util.Arrays;
+
+public class CustomQSTile extends QSTile<QSTile.State> {
+
+ private CustomTile.ExpandedStyle mExpandedStyle;
+ private PendingIntent mOnClick;
+ private Uri mOnClickUri;
+ private int mCurrentUserId;
+ private StatusBarPanelCustomTile mTile;
+ private CustomQSDetailAdapter mDetailAdapter;
+ private boolean mCollapsePanel;
+
+ public CustomQSTile(Host host, StatusBarPanelCustomTile tile) {
+ super(host);
+ refreshState(tile);
+ }
+
+ @Override
+ public DetailAdapter getDetailAdapter() {
+ return mDetailAdapter;
+ }
+
+ @Override
+ public void setListening(boolean listening) {
+ }
+
+ @Override
+ protected State newTileState() {
+ return new State();
+ }
+
+ @Override
+ protected void handleUserSwitch(int newUserId) {
+ super.handleUserSwitch(newUserId);
+ mCurrentUserId = newUserId;
+ }
+
+ public void update(StatusBarPanelCustomTile customTile) {
+ refreshState(customTile);
+ }
+
+ @Override
+ protected void handleLongClick() {
+ if (mExpandedStyle == null) {
+ showDetail(true);
+ }
+ }
+
+ @Override
+ protected void handleClick() {
+ try {
+ if (mExpandedStyle != null &&
+ mExpandedStyle.getStyle() != CustomTile.ExpandedStyle.NO_STYLE) {
+ showDetail(true);
+ return;
+ }
+ if (mCollapsePanel) {
+ mHost.collapsePanels();
+ }
+ if (mOnClick != null) {
+ mOnClick.send();
+ } else if (mOnClickUri != null) {
+ final Intent intent = new Intent().setData(mOnClickUri);
+ mContext.sendBroadcastAsUser(intent, new UserHandle(mCurrentUserId));
+ }
+ } catch (Throwable t) {
+ Log.w(TAG, "Error sending click intent", t);
+ }
+ }
+
+ @Override
+ protected void handleUpdateState(State state, Object arg) {
+ if (arg instanceof StatusBarPanelCustomTile) {
+ mTile = (StatusBarPanelCustomTile) arg;
+ }
+ final CustomTile customTile = mTile.getCustomTile();
+ state.visible = true;
+ state.contentDescription = customTile.contentDescription;
+ state.label = customTile.label;
+ final int iconId = customTile.icon;
+ if (iconId != 0 && (customTile.remoteIcon == null)) {
+ final String iconPackage = mTile.getResPkg();
+ if (!TextUtils.isEmpty(iconPackage)) {
+ state.icon = new ExternalIcon(iconPackage, iconId);
+ }
+ } else {
+ state.icon = new ExternalBitmapIcon(customTile.remoteIcon);
+ }
+ mOnClick = customTile.onClick;
+ mOnClickUri = customTile.onClickUri;
+ mExpandedStyle = customTile.expandedStyle;
+ mCollapsePanel = customTile.collapsePanel;
+ mDetailAdapter = new CustomQSDetailAdapter();
+ }
+
+ @Override
+ public int getMetricsCategory() {
+ return MetricsLogger.DONT_TRACK_ME_BRO;
+ }
+
+ private class CustomQSDetailAdapter implements DetailAdapter, AdapterView.OnItemClickListener,
+ QSDetailItemsGrid.QSDetailItemsGridAdapter.OnPseudoGriditemClickListener {
+ private QSDetailItemsList.QSCustomDetailListAdapter mListAdapter;
+ private QSDetailItemsGrid.QSDetailItemsGridAdapter mGridAdapter;
+
+ public int getTitle() {
+ return R.string.quick_settings_custom_tile_detail_title;
+ }
+
+ @Override
+ public Boolean getToggleState() {
+ return null;
+ }
+
+
+ @Override
+ public Intent getSettingsIntent() {
+ return mTile.getCustomTile().onSettingsClick;
+ }
+
+ @Override
+ public StatusBarPanelCustomTile getCustomTile() {
+ return mTile;
+ }
+
+ @Override
+ public void setToggleState(boolean state) {
+ // noop
+ }
+
+ @Override
+ public int getMetricsCategory() {
+ return MetricsLogger.DONT_TRACK_ME_BRO;
+ }
+
+ @Override
+ public View createDetailView(Context context, View convertView, ViewGroup parent) {
+ View rootView = null;
+ if (mExpandedStyle == null) {
+ rootView = (LinearLayout) LayoutInflater.from(context)
+ .inflate(R.layout.qs_custom_detail, parent, false);
+ ImageView imageView = (ImageView)
+ rootView.findViewById(R.id.custom_qs_tile_icon);
+ TextView customTileTitle = (TextView)
+ rootView.findViewById(R.id.custom_qs_tile_title);
+ TextView customTilePkg = (TextView) rootView
+ .findViewById(R.id.custom_qs_tile_package);
+ TextView customTileContentDesc = (TextView) rootView
+ .findViewById(R.id.custom_qs_tile_content_description);
+ // icon is cached in state, fetch it
+ imageView.setImageDrawable(getState().icon.getDrawable(mContext));
+ customTileTitle.setText(mTile.getCustomTile().label);
+ customTilePkg.setText(mTile.getPackage());
+ customTileContentDesc.setText(mTile.getCustomTile().contentDescription);
+ } else {
+ switch (mExpandedStyle.getStyle()) {
+ case CustomTile.ExpandedStyle.GRID_STYLE:
+ rootView = QSDetailItemsGrid.inflate(context, parent, false);
+ mGridAdapter = ((QSDetailItemsGrid) rootView)
+ .createAndSetAdapter(mTile.getPackage(),
+ mExpandedStyle.getExpandedItems());
+ mGridAdapter.setOnPseudoGridItemClickListener(this);
+ break;
+ case CustomTile.ExpandedStyle.REMOTE_STYLE:
+ rootView = (LinearLayout) LayoutInflater.from(context)
+ .inflate(R.layout.qs_custom_detail_remote, parent, false);
+ RemoteViews remoteViews = mExpandedStyle.getContentViews();
+ if (remoteViews != null) {
+ View localView = mTile.getCustomTile().expandedStyle.getContentViews()
+ .apply(context, (ViewGroup) rootView,
+ mHost.getOnClickHandler(), getThemePackageName());
+ ((LinearLayout) rootView).addView(localView);
+ } else {
+ Log.d(TAG, "Unable to add null remoteview for " + mTile.getOpPkg());
+ }
+ break;
+ case CustomTile.ExpandedStyle.LIST_STYLE:
+ default:
+ rootView = QSDetailItemsList.convertOrInflate(context, convertView, parent);
+ ListView listView = ((QSDetailItemsList) rootView).getListView();
+ listView.setDivider(null);
+ listView.setOnItemClickListener(this);
+ listView.setAdapter(mListAdapter =
+ new QSDetailItemsList.QSCustomDetailListAdapter(mTile.getPackage(),
+ context, Arrays.asList(mExpandedStyle.getExpandedItems())));
+ break;
+ }
+ }
+ return rootView;
+ }
+
+ @Override
+ public void onItemClick(AdapterView<?> adapterView, View view, int position, long l) {
+ CustomTile.ExpandedItem item = mListAdapter.getItem(position);
+ sendEvent(item.onClickPendingIntent);
+ }
+
+ @Override
+ public void onPsuedoGridItemClick(View view, CustomTile.ExpandedItem item) {
+ sendEvent(item.onClickPendingIntent);
+ }
+
+ private void sendEvent(PendingIntent intent) {
+ try {
+ if (intent.isActivity()) {
+ mHost.collapsePanels();
+ }
+ intent.send();
+ } catch (PendingIntent.CanceledException e) {
+ //
+ }
+ }
+
+ private String getThemePackageName() {
+ final Configuration config = mContext.getResources().getConfiguration();
+ final ThemeConfig themeConfig = config != null ? config.themeConfig : null;
+ return themeConfig != null ? themeConfig.getOverlayForStatusBar() : null;
+ }
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
index 781ab1c..6c40486 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2015 The Android Open Source Project
+ * Copyright (C) 2015 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.
@@ -37,6 +38,7 @@ import com.android.systemui.SysUIToast;
import com.android.systemui.qs.QSTile;
import com.android.systemui.statusbar.policy.ZenModeController;
import com.android.systemui.volume.ZenModePanel;
+import cyanogenmod.app.StatusBarPanelCustomTile;
/** Quick settings tile: Do not disturb **/
public class DndTile extends QSTile<QSTile.BooleanState> {
@@ -121,6 +123,16 @@ public class DndTile extends QSTile<QSTile.BooleanState> {
}
@Override
+ protected void handleSecondaryClick() {
+ handleClick();
+ }
+
+ @Override
+ public void handleLongClick() {
+ mHost.startActivityDismissingKeyguard(ZEN_SETTINGS);
+ }
+
+ @Override
protected void handleUpdateState(BooleanState state, Object arg) {
final int zen = arg instanceof Integer ? (Integer) arg : mController.getZen();
final boolean newValue = zen != Global.ZEN_MODE_OFF;
@@ -188,6 +200,11 @@ public class DndTile extends QSTile<QSTile.BooleanState> {
}
}
+ @Override
+ public boolean hasDualTargetsDetails() {
+ return true;
+ }
+
private final OnSharedPreferenceChangeListener mPrefListener
= new OnSharedPreferenceChangeListener() {
@Override
@@ -233,6 +250,11 @@ public class DndTile extends QSTile<QSTile.BooleanState> {
}
@Override
+ public StatusBarPanelCustomTile getCustomTile() {
+ return null;
+ }
+
+ @Override
public void setToggleState(boolean state) {
MetricsLogger.action(mContext, MetricsLogger.QS_DND_TOGGLE, state);
if (!state) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/EditTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/EditTile.java
new file mode 100644
index 0000000..eaa5ff5
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/EditTile.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2015 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 com.android.systemui.qs.tiles;
+
+import com.android.internal.logging.MetricsLogger;
+import com.android.systemui.R;
+import com.android.systemui.qs.QSTile;
+
+public class EditTile extends QSTile<QSTile.BooleanState> {
+
+ private boolean mListening;
+
+ public EditTile(Host host) {
+ super(host);
+ refreshState();
+ }
+
+ @Override
+ protected void handleDestroy() {
+ super.handleDestroy();
+ }
+
+ @Override
+ protected BooleanState newTileState() {
+ return new BooleanState();
+ }
+
+ @Override
+ protected void handleClick() {
+ getHost().setEditing(!mState.value);
+ refreshState(!mState.value);
+ }
+
+ @Override
+ protected void handleLongClick() {
+ getHost().goToSettingsPage();
+ refreshState(true);
+ }
+
+ @Override
+ protected void handleUpdateState(BooleanState state, Object arg) {
+ state.visible = !getHost().getKeyguardMonitor().isShowing();
+ state.label = mContext.getString(R.string.quick_settings_edit_label);
+
+ if (arg instanceof Boolean) {
+ state.value = (boolean) arg;
+ } else {
+ state.value = getHost().isEditing();
+ }
+ state.icon = ResourceIcon.get(R.drawable.ic_qs_edit_tiles);
+ }
+
+ @Override
+ public int getMetricsCategory() {
+ return MetricsLogger.DONT_TRACK_ME_BRO;
+ }
+
+ @Override
+ protected String composeChangeAnnouncement() {
+ // TODO
+ return null;
+ }
+
+ @Override
+ public void setListening(boolean listening) {
+ if (mListening == listening) return;
+ mListening = listening;
+ refreshState();
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
index 7b83e6a..4173efc 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2014 The Android Open Source Project
+ * Copyright (C) 2015 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.
@@ -17,6 +18,7 @@
package com.android.systemui.qs.tiles;
import android.content.BroadcastReceiver;
+import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -29,6 +31,10 @@ import com.android.systemui.statusbar.policy.HotspotController;
/** Quick settings tile: Hotspot **/
public class HotspotTile extends QSTile<QSTile.BooleanState> {
+
+ private static final Intent TETHER_SETTINGS = new Intent().setComponent(new ComponentName(
+ "com.android.settings", "com.android.settings.TetherSettings"));
+
private final AnimationIcon mEnable =
new AnimationIcon(R.drawable.ic_hotspot_enable_animation);
private final AnimationIcon mDisable =
@@ -75,15 +81,18 @@ public class HotspotTile extends QSTile<QSTile.BooleanState> {
@Override
protected void handleLongClick() {
- if (mState.value) return; // don't allow usage reset if hotspot is active
- final String title = mContext.getString(R.string.quick_settings_reset_confirmation_title,
- mState.label);
- mUsageTracker.showResetConfirmation(title, new Runnable() {
- @Override
- public void run() {
- refreshState();
- }
- });
+ if (mState.value) {
+ mHost.startActivityDismissingKeyguard(TETHER_SETTINGS);
+ } else {
+ final String title = mContext.getString(
+ R.string.quick_settings_reset_confirmation_title, mState.label);
+ mUsageTracker.showResetConfirmation(title, new Runnable() {
+ @Override
+ public void run() {
+ refreshState();
+ }
+ });
+ }
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
index e6fade4..347d079 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2014 The Android Open Source Project
+ * Copyright (C) 2015 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.
@@ -17,6 +18,9 @@
package com.android.systemui.qs.tiles;
import com.android.internal.logging.MetricsLogger;
+import android.content.Intent;
+import android.provider.Settings;
+
import com.android.systemui.R;
import com.android.systemui.qs.QSTile;
import com.android.systemui.statusbar.policy.KeyguardMonitor;
@@ -26,6 +30,9 @@ import com.android.systemui.statusbar.policy.LocationController.LocationSettings
/** Quick settings tile: Location **/
public class LocationTile extends QSTile<QSTile.BooleanState> {
+ private static final Intent LOCATION_SETTINGS = new Intent(
+ Settings.ACTION_LOCATION_SOURCE_SETTINGS);
+
private final AnimationIcon mEnable =
new AnimationIcon(R.drawable.ic_signal_location_enable_animation);
private final AnimationIcon mDisable =
@@ -67,6 +74,11 @@ public class LocationTile extends QSTile<QSTile.BooleanState> {
}
@Override
+ protected void handleLongClick() {
+ mHost.startActivityDismissingKeyguard(LOCATION_SETTINGS);
+ }
+
+ @Override
protected void handleUpdateState(BooleanState state, Object arg) {
final boolean locationEnabled = mController.isLocationEnabled();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
index 1a26a4d..f074d9d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2014 The Android Open Source Project
+ * Copyright (C) 2015 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.
@@ -16,6 +17,7 @@
package com.android.systemui.qs.tiles;
+import android.content.Intent;
import android.content.res.Configuration;
import com.android.internal.logging.MetricsLogger;
@@ -26,6 +28,10 @@ import com.android.systemui.statusbar.policy.RotationLockController.RotationLock
/** Quick settings tile: Rotation **/
public class RotationLockTile extends QSTile<QSTile.BooleanState> {
+
+ private static final Intent DISPLAY_ROTATION_SETTINGS =
+ new Intent("android.settings.DISPLAY_ROTATION_SETTINGS");
+
private final AnimationIcon mPortraitToAuto
= new AnimationIcon(R.drawable.ic_portrait_to_auto_rotate_animation);
private final AnimationIcon mAutoToPortrait
@@ -67,6 +73,11 @@ public class RotationLockTile extends QSTile<QSTile.BooleanState> {
}
@Override
+ protected void handleLongClick() {
+ mHost.startActivityDismissingKeyguard(DISPLAY_ROTATION_SETTINGS);
+ }
+
+ @Override
protected void handleUpdateState(BooleanState state, Object arg) {
if (mController == null) return;
final boolean rotationLocked = arg != null ? ((UserBoolean) arg).value
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
index e654efd..b25390e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2014 The Android Open Source Project
+ * Copyright (C) 2015 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.
@@ -23,12 +24,15 @@ import android.provider.Settings;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.ListView;
import com.android.internal.logging.MetricsLogger;
import com.android.settingslib.wifi.AccessPoint;
+
import com.android.systemui.R;
-import com.android.systemui.qs.QSDetailItems;
import com.android.systemui.qs.QSDetailItems.Item;
+import com.android.systemui.qs.QSDetailItemsList;
import com.android.systemui.qs.QSTile;
import com.android.systemui.qs.QSTileView;
import com.android.systemui.qs.SignalTileView;
@@ -37,6 +41,9 @@ import com.android.systemui.statusbar.policy.NetworkController.AccessPointContro
import com.android.systemui.statusbar.policy.NetworkController.IconState;
import com.android.systemui.statusbar.policy.SignalCallbackAdapter;
+import cyanogenmod.app.StatusBarPanelCustomTile;
+
+import java.util.ArrayList;
import java.util.List;
/** Quick settings tile: Wifi **/
@@ -58,7 +65,7 @@ public class WifiTile extends QSTile<QSTile.SignalState> {
}
@Override
- public boolean supportsDualTargets() {
+ public boolean hasDualTargetsDetails() {
return true;
}
@@ -116,6 +123,11 @@ public class WifiTile extends QSTile<QSTile.SignalState> {
}
@Override
+ protected void handleLongClick() {
+ mHost.startActivityDismissingKeyguard(WIFI_SETTINGS);
+ }
+
+ @Override
protected void handleUpdateState(SignalState state, Object arg) {
state.visible = true;
if (DEBUG) Log.d(TAG, "handleUpdateState arg=" + arg);
@@ -235,10 +247,12 @@ public class WifiTile extends QSTile<QSTile.SignalState> {
};
private final class WifiDetailAdapter implements DetailAdapter,
- NetworkController.AccessPointController.AccessPointCallback, QSDetailItems.Callback {
+ AccessPointController.AccessPointCallback, AdapterView.OnItemClickListener {
- private QSDetailItems mItems;
- private AccessPoint[] mAccessPoints;
+ private QSDetailItemsList mItemsList;
+ private List<AccessPoint> mAccessPoints;
+ private List<Item> mDisplayedAccessPoints = new ArrayList<>();
+ private QSDetailItemsList.QSDetailListAdapter mAdapter;
@Override
public int getTitle() {
@@ -250,6 +264,11 @@ public class WifiTile extends QSTile<QSTile.SignalState> {
}
@Override
+ public StatusBarPanelCustomTile getCustomTile() {
+ return null;
+ }
+
+ @Override
public Boolean getToggleState() {
return mState.enabled;
}
@@ -273,19 +292,21 @@ public class WifiTile extends QSTile<QSTile.SignalState> {
mAccessPoints = null;
mWifiController.scanForAccessPoints();
fireScanStateChanged(true);
- mItems = QSDetailItems.convertOrInflate(context, convertView, parent);
- mItems.setTagSuffix("Wifi");
- mItems.setCallback(this);
- mItems.setEmptyState(R.drawable.ic_qs_wifi_detail_empty,
+ mItemsList = QSDetailItemsList.convertOrInflate(context, convertView, parent);
+ ListView listView = mItemsList.getListView();
+ listView.setDivider(null);
+ listView.setOnItemClickListener(this);
+ listView.setAdapter(mAdapter =
+ new QSDetailItemsList.QSDetailListAdapter(context, mDisplayedAccessPoints));
+ mItemsList.setEmptyState(R.drawable.ic_qs_wifi_detail_empty,
R.string.quick_settings_wifi_detail_empty_text);
updateItems();
- setItemsVisible(mState.enabled);
- return mItems;
+ return mItemsList;
}
@Override
public void onAccessPointsChanged(final List<AccessPoint> accessPoints) {
- mAccessPoints = accessPoints.toArray(new AccessPoint[accessPoints.size()]);
+ mAccessPoints = accessPoints;
updateItems();
if (accessPoints != null && accessPoints.size() > 0) {
fireScanStateChanged(false);
@@ -297,35 +318,22 @@ public class WifiTile extends QSTile<QSTile.SignalState> {
mHost.startActivityDismissingKeyguard(settingsIntent);
}
- @Override
- public void onDetailItemClick(Item item) {
- if (item == null || item.tag == null) return;
- final AccessPoint ap = (AccessPoint) item.tag;
- if (!ap.isActive()) {
- if (mWifiController.connect(ap)) {
- mHost.collapsePanels();
- }
- }
- showDetail(false);
- }
-
- @Override
- public void onDetailItemDisconnect(Item item) {
- // noop
- }
-
public void setItemsVisible(boolean visible) {
- if (mItems == null) return;
- mItems.setItemsVisible(visible);
+ if (mAdapter == null) return;
+ if (visible) {
+ updateItems();
+ } else {
+ mDisplayedAccessPoints.clear();
+ }
+ mAdapter.notifyDataSetChanged();
}
private void updateItems() {
- if (mItems == null) return;
- Item[] items = null;
+ if (mAdapter == null) return;
if (mAccessPoints != null) {
- items = new Item[mAccessPoints.length];
- for (int i = 0; i < mAccessPoints.length; i++) {
- final AccessPoint ap = mAccessPoints[i];
+ mDisplayedAccessPoints.clear();
+ for (int i = 0; i < mAccessPoints.size(); i++) {
+ final AccessPoint ap = mAccessPoints.get(i);
final Item item = new Item();
item.tag = ap;
item.icon = mWifiController.getIcon(ap);
@@ -334,10 +342,23 @@ public class WifiTile extends QSTile<QSTile.SignalState> {
item.overlay = ap.getSecurity() != AccessPoint.SECURITY_NONE
? mContext.getDrawable(R.drawable.qs_ic_wifi_lock)
: null;
- items[i] = item;
+ mDisplayedAccessPoints.add(item);
}
}
- mItems.setItems(items);
+ mAdapter.notifyDataSetChanged();
+ }
+
+ @Override
+ public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+ Item item = (Item) parent.getItemAtPosition(position);
+ if (item == null || item.tag == null) return;
+ final AccessPoint ap = (AccessPoint) item.tag;
+ if (!ap.isActive()) {
+ if (mWifiController.connect(ap)) {
+ mHost.collapsePanels();
+ }
+ }
+ showDetail(false);
}
};
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Constants.java b/packages/SystemUI/src/com/android/systemui/recents/Constants.java
index a4acf83..b482a50 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Constants.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Constants.java
@@ -38,7 +38,7 @@ public class Constants {
// Enables the filtering of tasks according to their grouping
public static final boolean EnableTaskFiltering = false;
// Enables dismiss-all
- public static final boolean EnableDismissAll = false;
+ public static final boolean EnableDismissAll = true;
// Enables debug mode
public static final boolean EnableDebugMode = false;
// Enables the search bar layout
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index d0876fa..03869af 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -25,9 +25,11 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.res.Resources;
import android.os.Bundle;
import android.os.SystemClock;
import android.os.UserHandle;
+import android.provider.Settings;
import android.view.KeyEvent;
import android.view.View;
import android.view.ViewStub;
@@ -36,6 +38,7 @@ import android.widget.Toast;
import com.android.internal.logging.MetricsLogger;
import com.android.systemui.Prefs;
import com.android.systemui.R;
+import com.android.systemui.recents.RecentsConfiguration;
import com.android.systemui.recents.misc.Console;
import com.android.systemui.recents.misc.DebugTrigger;
import com.android.systemui.recents.misc.ReferenceCountedTrigger;
@@ -48,6 +51,7 @@ import com.android.systemui.recents.views.DebugOverlayView;
import com.android.systemui.recents.views.RecentsView;
import com.android.systemui.recents.views.SystemBarScrimViews;
import com.android.systemui.recents.views.ViewAnimation;
+import cyanogenmod.providers.CMSettings;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
@@ -129,7 +133,7 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView
/**
* Broadcast receiver to handle messages from AlternateRecentsComponent.
*/
- final BroadcastReceiver mServiceBroadcastReceiver = new BroadcastReceiver() {
+ private final BroadcastReceiver mServiceBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
@@ -159,7 +163,7 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView
/**
* Broadcast receiver to handle messages from the system
*/
- final BroadcastReceiver mSystemBroadcastReceiver = new BroadcastReceiver() {
+ private final BroadcastReceiver mSystemBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
@@ -178,7 +182,7 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView
/**
* A custom debug trigger to listen for a debug key chord.
*/
- final DebugTrigger mDebugTrigger = new DebugTrigger(new Runnable() {
+ private final DebugTrigger mDebugTrigger = new DebugTrigger(new Runnable() {
@Override
public void run() {
onDebugModeTriggered();
@@ -253,10 +257,27 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView
if (mEmptyView != null) {
mEmptyView.setVisibility(View.GONE);
}
+ boolean showSearchBar = CMSettings.System.getInt(getContentResolver(),
+ CMSettings.System.RECENTS_SHOW_SEARCH_BAR, 1) == 1;
+
if (mRecentsView.hasValidSearchBar()) {
- mRecentsView.setSearchBarVisibility(View.VISIBLE);
+ if (showSearchBar) {
+ mRecentsView.setSearchBarVisibility(View.VISIBLE);
+ } else {
+ mRecentsView.setSearchBarVisibility(View.GONE);
+ }
} else {
- refreshSearchWidgetView();
+ if (showSearchBar) {
+ refreshSearchWidgetView();
+ }
+ }
+
+ // Update search bar space height
+ if (showSearchBar) {
+ mConfig.searchBarSpaceHeightPx = getResources().getDimensionPixelSize(
+ R.dimen.recents_search_bar_space_height);
+ } else {
+ mConfig.searchBarSpaceHeightPx = 0;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
index dfe7e96..41d52b8 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
@@ -175,6 +175,14 @@ public class RecentsConfiguration {
return sInstance;
}
+ /** Returns the current recents configuration or creates and populates it if required */
+ public static RecentsConfiguration getInstance(Context context, SystemServicesProxy ssp) {
+ if (sInstance == null) {
+ sInstance = reinitialize(context, ssp);
+ }
+ return sInstance;
+ }
+
/** Updates the state, given the specified context */
void update(Context context) {
Resources res = context.getResources();
diff --git a/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java b/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java
index cbf5c05..b1413c9 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java
@@ -30,9 +30,11 @@ import android.graphics.drawable.ColorDrawable;
import android.os.RemoteException;
import android.util.DisplayMetrics;
import android.view.Gravity;
+import android.view.IWindowManager;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
+import android.view.WindowManagerGlobal;
import android.view.accessibility.AccessibilityManager;
import android.view.animation.DecelerateInterpolator;
import android.widget.Button;
@@ -49,6 +51,7 @@ public class ScreenPinningRequest implements View.OnClickListener {
private final AccessibilityManager mAccessibilityService;
private final WindowManager mWindowManager;
+ private final IWindowManager mWindowManagerService;
private RequestWindowView mRequestWindow;
@@ -58,6 +61,7 @@ public class ScreenPinningRequest implements View.OnClickListener {
mContext.getSystemService(Context.ACCESSIBILITY_SERVICE);
mWindowManager = (WindowManager)
mContext.getSystemService(Context.WINDOW_SERVICE);
+ mWindowManagerService = WindowManagerGlobal.getWindowManagerService();
}
public void clearPrompt() {
@@ -215,19 +219,33 @@ public class ScreenPinningRequest implements View.OnClickListener {
.setVisibility(View.INVISIBLE);
}
- final int description = mAccessibilityService.isEnabled()
+ final int description;
+ if (hasNavigationBar()) {
+ description = mAccessibilityService.isEnabled()
? R.string.screen_pinning_description_accessible
: R.string.screen_pinning_description;
+ final int backBgVis =
+ mAccessibilityService.isEnabled() ? View.INVISIBLE : View.VISIBLE;
+ mLayout.findViewById(R.id.screen_pinning_back_bg).setVisibility(backBgVis);
+ mLayout.findViewById(R.id.screen_pinning_back_bg_light).setVisibility(backBgVis);
+ } else {
+ description = R.string.screen_pinning_description_no_navbar;
+ ((ViewGroup) buttons.getParent()).removeView(buttons);
+ }
((TextView) mLayout.findViewById(R.id.screen_pinning_description))
.setText(description);
- final int backBgVisibility =
- mAccessibilityService.isEnabled() ? View.INVISIBLE : View.VISIBLE;
- mLayout.findViewById(R.id.screen_pinning_back_bg).setVisibility(backBgVisibility);
- mLayout.findViewById(R.id.screen_pinning_back_bg_light).setVisibility(backBgVisibility);
-
+
addView(mLayout, getRequestLayoutParams(isLandscape));
}
+ private boolean hasNavigationBar() {
+ try {
+ return mWindowManagerService.hasNavigationBar();
+ } catch (RemoteException e) {
+ //ignore
+ }
+ return false;
+ }
private void swapChildrenIfRtlAndVertical(View group) {
if (mContext.getResources().getConfiguration().getLayoutDirection()
!= View.LAYOUT_DIRECTION_RTL) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
index ad25c85..4b3b391 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
@@ -458,7 +458,7 @@ public class RecentsTaskLoader {
/** Creates a new plan for loading the recent tasks. */
public RecentsTaskLoadPlan createLoadPlan(Context context) {
- RecentsConfiguration config = RecentsConfiguration.getInstance();
+ RecentsConfiguration config = RecentsConfiguration.getInstance(context, mSystemServicesProxy);
RecentsTaskLoadPlan plan = new RecentsTaskLoadPlan(context, config, mSystemServicesProxy);
return plan;
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
index 0068f84..43b9a3e 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -17,18 +17,27 @@
package com.android.systemui.recents.views;
import android.animation.ValueAnimator;
+import android.app.ActivityManager;
+import android.app.admin.DevicePolicyManager;
import android.content.ComponentName;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.os.Bundle;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.IPackageDataObserver;
+import android.content.pm.PackageManager;
+import android.net.Uri;
import android.view.LayoutInflater;
+import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.FrameLayout;
+import android.widget.PopupMenu;
import com.android.internal.logging.MetricsLogger;
import com.android.systemui.R;
@@ -85,6 +94,9 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
boolean mDismissAllButtonAnimating;
int mFocusedTaskIndex = -1;
int mPrevAccessibilityFocusedIndex = -1;
+
+ private PopupMenu mPopup;
+
// Optimizations
int mStackViewsAnimationDuration;
boolean mStackViewsDirty = true;
@@ -1372,6 +1384,85 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
}
@Override
+ public void onTaskViewLongClicked(final TaskView tv) {
+ final PopupMenu popup = new PopupMenu(getContext(), tv.mHeaderView.mApplicationIcon);
+ mPopup = popup;
+ popup.getMenuInflater().inflate(R.menu.recent_popup_menu, popup.getMenu());
+
+ final Task task = tv.getTask();
+ final String packageName = task.key.baseIntent.getComponent().getPackageName();
+
+ try {
+ PackageManager pm = (PackageManager) getContext().getPackageManager();
+ ApplicationInfo appInfo = pm.getApplicationInfo(packageName, 0);
+ DevicePolicyManager dpm = (DevicePolicyManager) getContext()
+ .getSystemService(Context.DEVICE_POLICY_SERVICE);
+
+ boolean hasActiveAdmins = dpm.packageHasActiveAdmins(packageName);
+ boolean isClearable = (appInfo.flags &
+ (ApplicationInfo.FLAG_ALLOW_CLEAR_USER_DATA | ApplicationInfo.FLAG_SYSTEM)) !=
+ ApplicationInfo.FLAG_SYSTEM;
+ if (!isClearable || hasActiveAdmins) {
+ popup.getMenu().findItem(R.id.recent_wipe_app).setEnabled(false);
+ popup.getMenu().findItem(R.id.recent_uninstall).setEnabled(false);
+ }
+ } catch (PackageManager.NameNotFoundException ex) {
+ }
+ popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
+ @Override
+ public boolean onMenuItemClick(MenuItem item) {
+ switch (item.getItemId()) {
+ case R.id.recent_remove_item:
+ onTaskViewDismissed(tv);
+ break;
+ case R.id.recent_inspect_item:
+ onTaskViewAppInfoClicked(tv);
+ break;
+ case R.id.recent_force_stop:
+ {
+ ActivityManager am = (ActivityManager) getContext()
+ .getSystemService(Context.ACTIVITY_SERVICE);
+ am.forceStopPackage(packageName);
+ onTaskViewDismissed(tv);
+ break;
+ }
+ case R.id.recent_wipe_app:
+ {
+ ActivityManager am = (ActivityManager) getContext()
+ .getSystemService(Context.ACTIVITY_SERVICE);
+ am.clearApplicationUserData(packageName, new IPackageDataObserver.Stub() {
+ @Override
+ public void onRemoveCompleted(String packageName, boolean succeeded) {}
+ });
+ onTaskViewDismissed(tv);
+ break;
+ }
+ case R.id.recent_uninstall:
+ {
+ Uri packageUri = Uri.parse("package:" + packageName);
+ Intent uninstallIntent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE, packageUri);
+ uninstallIntent.putExtra(Intent.EXTRA_UNINSTALL_ALL_USERS, true);
+ getContext().startActivity(uninstallIntent);
+ onTaskViewDismissed(tv);
+ break;
+ }
+ default:
+ return false;
+ }
+ return true;
+ }
+ });
+ popup.setOnDismissListener(new PopupMenu.OnDismissListener() {
+ @Override
+ public void onDismiss(PopupMenu menu) {
+ mPopup = null;
+ }
+ });
+ popup.show();
+ }
+
+
+ @Override
public void onTaskViewClicked(TaskView tv, Task task, boolean lockToTask) {
// Cancel any doze triggers
mUIDozeTrigger.stopDozing();
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
index cbfe842..b7e46f4 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
@@ -34,6 +34,7 @@ import com.android.systemui.recents.RecentsConfiguration;
import com.android.systemui.recents.misc.Utilities;
import com.android.systemui.recents.model.Task;
import com.android.systemui.statusbar.phone.PhoneStatusBar;
+import cyanogenmod.providers.CMSettings;
/* A task view */
public class TaskView extends FrameLayout implements Task.TaskCallbacks,
@@ -43,6 +44,7 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks,
interface TaskViewCallbacks {
public void onTaskViewAppIconClicked(TaskView tv);
public void onTaskViewAppInfoClicked(TaskView tv);
+ public void onTaskViewLongClicked(TaskView tv);
public void onTaskViewClicked(TaskView tv, Task task, boolean lockToTask);
public void onTaskViewDismissed(TaskView tv);
public void onTaskViewClipStateChanged(TaskView tv);
@@ -769,7 +771,14 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks,
public boolean onLongClick(View v) {
if (v == mHeaderView.mApplicationIcon) {
if (mCb != null) {
- mCb.onTaskViewAppInfoClicked(this);
+ boolean showDevShortcuts =
+ CMSettings.Secure.getInt(v.getContext().getContentResolver(),
+ CMSettings.Secure.DEVELOPMENT_SHORTCUT, 0) != 0;
+ if (showDevShortcuts) {
+ mCb.onTaskViewLongClicked(this);
+ } else {
+ mCb.onTaskViewAppInfoClicked(this);
+ }
return true;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
index 9e3cf37..260f625 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
@@ -430,6 +430,7 @@ class GlobalScreenshot {
private MediaActionSound mCameraSound;
+ private final int mSfHwRotation;
/**
* @param context everything needs a context :(
@@ -496,6 +497,9 @@ class GlobalScreenshot {
// Setup the Camera shutter sound
mCameraSound = new MediaActionSound();
mCameraSound.load(MediaActionSound.SHUTTER_CLICK);
+
+ // Load hardware rotation from prop
+ mSfHwRotation = android.os.SystemProperties.getInt("ro.sf.hwrotation",0) / 90;
}
/**
@@ -539,7 +543,10 @@ class GlobalScreenshot {
// only in the natural orientation of the device :!)
mDisplay.getRealMetrics(mDisplayMetrics);
float[] dims = {mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels};
- float degrees = getDegreesForRotation(mDisplay.getRotation());
+ int rot = mDisplay.getRotation();
+ // Allow for abnormal hardware orientation
+ rot = (rot + mSfHwRotation) % 4;
+ float degrees = getDegreesForRotation(rot);
boolean requiresRotation = (degrees > 0);
if (requiresRotation) {
// Get the dimensions of the device in its native orientation
diff --git a/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java b/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java
index 77c27fa..e74edd0 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java
@@ -42,7 +42,7 @@ public class BrightnessController implements ToggleSlider.Listener {
* {@link android.provider.Settings.System#SCREEN_AUTO_BRIGHTNESS_ADJ} uses the range [-1, 1].
* Using this factor, it is converted to [0, BRIGHTNESS_ADJ_RESOLUTION] for the SeekBar.
*/
- private static final float BRIGHTNESS_ADJ_RESOLUTION = 2048;
+ public static final float BRIGHTNESS_ADJ_RESOLUTION = 2048;
private final int mMinimumBacklight;
private final int mMaximumBacklight;
diff --git a/packages/SystemUI/src/com/android/systemui/settings/NotificationBrightnessController.java b/packages/SystemUI/src/com/android/systemui/settings/NotificationBrightnessController.java
new file mode 100644
index 0000000..617ef8f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/settings/NotificationBrightnessController.java
@@ -0,0 +1,247 @@
+/*
+ * Copyright (C) 2012-2015 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 com.android.systemui.settings;
+
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.os.UserHandle;
+import android.provider.Settings;
+
+import com.android.systemui.R;
+
+import java.lang.Exception;
+import java.util.ArrayList;
+
+import cyanogenmod.providers.CMSettings;
+
+public class NotificationBrightnessController implements ToggleSlider.Listener {
+ private static final String TAG = "StatusBar.NotificationBrightnessController";
+
+ public static final int LIGHT_BRIGHTNESS_MINIMUM = 1;
+ public static final int LIGHT_BRIGHTNESS_MAXIMUM = 255;
+
+ // Minimum delay between LED notification updates
+ private final static long LED_UPDATE_DELAY_MS = 250;
+
+ private int mCurrentBrightness;
+ private final int mMinimumBrightness;
+ private final int mMaximumBrightness;
+
+ private final Context mContext;
+ private final ToggleSlider mControl;
+ private final CurrentUserTracker mUserTracker;
+ private final Handler mHandler;
+ private final NotificationBrightnessObserver mBrightnessObserver;
+
+ private ArrayList<BrightnessStateChangeCallback> mChangeCallbacks =
+ new ArrayList<BrightnessStateChangeCallback>();
+
+ private boolean mListening;
+ private boolean mExternalChange;
+
+ private boolean mNotificationAllow;
+ private final Bundle mNotificationBundle;
+ private final Notification.Builder mNotificationBuilder;
+ private NotificationManager mNotificationManager;
+
+ public interface BrightnessStateChangeCallback {
+ public void onBrightnessLevelChanged();
+ }
+
+ /** ContentObserver to watch brightness **/
+ private class NotificationBrightnessObserver extends ContentObserver {
+
+ private final Uri NOTIFICATION_LIGHT_BRIGHTNESS_LEVEL_URI =
+ CMSettings.System.getUriFor(CMSettings.System.NOTIFICATION_LIGHT_BRIGHTNESS_LEVEL);
+
+ public NotificationBrightnessObserver(Handler handler) {
+ super(handler);
+ }
+
+ @Override
+ public void onChange(boolean selfChange) {
+ onChange(selfChange, null);
+ }
+
+ @Override
+ public void onChange(boolean selfChange, Uri uri) {
+ if (selfChange) return;
+ try {
+ mExternalChange = true;
+ updateSlider();
+ for (BrightnessStateChangeCallback cb : mChangeCallbacks) {
+ cb.onBrightnessLevelChanged();
+ }
+ } finally {
+ mExternalChange = false;
+ }
+ }
+
+ public void startObserving() {
+ final ContentResolver cr = mContext.getContentResolver();
+ cr.unregisterContentObserver(this);
+ cr.registerContentObserver(
+ NOTIFICATION_LIGHT_BRIGHTNESS_LEVEL_URI,
+ false, this, UserHandle.USER_ALL);
+ }
+
+ public void stopObserving() {
+ final ContentResolver cr = mContext.getContentResolver();
+ cr.unregisterContentObserver(this);
+ }
+
+ }
+
+ public NotificationBrightnessController(Context context, ToggleSlider control) {
+ mContext = context;
+ mControl = control;
+ mHandler = new Handler();
+ mUserTracker = new CurrentUserTracker(mContext) {
+ @Override
+ public void onUserSwitched(int newUserId) {
+ updateSlider();
+ }
+ };
+ mBrightnessObserver = new NotificationBrightnessObserver(mHandler);
+
+ mMinimumBrightness = LIGHT_BRIGHTNESS_MINIMUM;
+ mMaximumBrightness = LIGHT_BRIGHTNESS_MAXIMUM;
+ mCurrentBrightness = LIGHT_BRIGHTNESS_MAXIMUM;
+
+ mNotificationManager =
+ (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
+
+ mNotificationBundle = new Bundle();
+ mNotificationBuilder = new Notification.Builder(mContext);
+
+ mNotificationBundle.putBoolean(Notification.EXTRA_FORCE_SHOW_LIGHTS, true);
+ mNotificationBuilder.setExtras(mNotificationBundle)
+ .setContentTitle(mContext.getString(R.string.led_notification_title))
+ .setContentText(mContext.getString(R.string.led_notification_text))
+ .setSmallIcon(R.drawable.ic_settings)
+ .setOngoing(true);
+ }
+
+ private Handler mLedHandler = new Handler() {
+ public void handleMessage(Message msg) {
+ updateNotification();
+ }
+ };
+
+ public void addStateChangedCallback(BrightnessStateChangeCallback cb) {
+ mChangeCallbacks.add(cb);
+ }
+
+ public boolean removeStateChangedCallback(BrightnessStateChangeCallback cb) {
+ return mChangeCallbacks.remove(cb);
+ }
+
+ @Override
+ public void onInit(ToggleSlider control) {
+ // Do nothing
+ }
+
+ public void registerCallbacks() {
+ if (mListening) {
+ return;
+ }
+
+ // Update the slider and mode before attaching the listener so we don't
+ // receive the onChanged notifications for the initial values.
+ mNotificationAllow = true;
+ updateSlider();
+
+ mBrightnessObserver.startObserving();
+ mUserTracker.startTracking();
+
+ mControl.setOnChangedListener(this);
+ mListening = true;
+ }
+
+ /** Unregister all call backs, both to and from the controller */
+ public void unregisterCallbacks() {
+ if (!mListening) {
+ return;
+ }
+
+ mNotificationAllow = false;
+ mBrightnessObserver.stopObserving();
+ mUserTracker.stopTracking();
+ mControl.setOnChangedListener(null);
+ mNotificationManager.cancel(1);
+ mListening = false;
+
+ CMSettings.System.putIntForUser(mContext.getContentResolver(),
+ CMSettings.System.NOTIFICATION_LIGHT_BRIGHTNESS_LEVEL,
+ mCurrentBrightness, UserHandle.USER_CURRENT);
+ }
+
+ @Override
+ public void onChanged(ToggleSlider view, boolean tracking, boolean automatic, int value,
+ boolean stopTracking) {
+ if (mExternalChange) return;
+
+ mCurrentBrightness = value + mMinimumBrightness;
+ updateNotification();
+
+ for (BrightnessStateChangeCallback cb : mChangeCallbacks) {
+ cb.onBrightnessLevelChanged();
+ }
+ }
+
+ /** Fetch the brightness from the system settings and update the slider */
+ private void updateSlider() {
+ mCurrentBrightness = CMSettings.System.getIntForUser(mContext.getContentResolver(),
+ CMSettings.System.NOTIFICATION_LIGHT_BRIGHTNESS_LEVEL,
+ mMaximumBrightness, UserHandle.USER_CURRENT);
+
+ CMSettings.System.putIntForUser(mContext.getContentResolver(),
+ CMSettings.System.NOTIFICATION_LIGHT_BRIGHTNESS_LEVEL,
+ mMaximumBrightness, UserHandle.USER_CURRENT);
+
+ mControl.setMax(mMaximumBrightness - mMinimumBrightness);
+ mControl.setValue(mCurrentBrightness - mMinimumBrightness);
+ updateNotification();
+ }
+
+ /** Fetch the brightness from the system settings and update the slider */
+ private void updateNotification() {
+ // Dampen rate of consecutive LED changes
+ if (mLedHandler.hasMessages(0)) {
+ return;
+ }
+
+ if (mNotificationAllow) {
+ mLedHandler.sendEmptyMessageDelayed(0, LED_UPDATE_DELAY_MS);
+
+ // Instead of canceling the notification, force it to update with the color.
+ // Use a white light for a better preview of the brightness.
+ int notificationColor = 0xFFFFFF | (mCurrentBrightness << 24);
+ mNotificationBuilder.setLights(notificationColor, 1, 0);
+ mNotificationManager.notify(1, mNotificationBuilder.build());
+ }
+ }
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/settings/NotificationBrightnessDialog.java b/packages/SystemUI/src/com/android/systemui/settings/NotificationBrightnessDialog.java
new file mode 100644
index 0000000..82c1b3c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/settings/NotificationBrightnessDialog.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2012-2015 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 com.android.systemui.settings;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.Gravity;
+import android.view.KeyEvent;
+import android.view.Window;
+import android.view.WindowManager;
+
+import com.android.systemui.R;
+
+/** A dialog that provides controls for adjusting the notifications brightness. */
+public class NotificationBrightnessDialog extends Activity {
+
+ private NotificationBrightnessController mNotificationBrightnessController;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ final Window window = getWindow();
+
+ window.setGravity(Gravity.TOP);
+ window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
+ window.requestFeature(Window.FEATURE_NO_TITLE);
+
+ setContentView(R.layout.quick_settings_notification_brightness_dialog);
+
+ final ToggleSlider slider = (ToggleSlider) findViewById(R.id.notification_brightness_slider);
+ mNotificationBrightnessController = new NotificationBrightnessController(this, slider);
+ }
+
+ @Override
+ protected void onStart() {
+ super.onStart();
+ mNotificationBrightnessController.registerCallbacks();
+ }
+
+ @Override
+ protected void onStop() {
+ super.onStop();
+ mNotificationBrightnessController.unregisterCallbacks();
+ }
+
+ @Override
+ public boolean onKeyDown(int keyCode, KeyEvent event) {
+ if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN
+ || keyCode == KeyEvent.KEYCODE_VOLUME_UP
+ || keyCode == KeyEvent.KEYCODE_VOLUME_MUTE) {
+ finish();
+ }
+
+ return super.onKeyDown(keyCode, event);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
index 7f17885..dba74de 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
@@ -34,6 +34,7 @@ import android.view.animation.LinearInterpolator;
import android.view.animation.PathInterpolator;
import com.android.systemui.R;
+import com.android.systemui.ViewInvertHelper;
/**
* Base class for both {@link ExpandableNotificationRow} and {@link NotificationOverflowContainer}
@@ -128,6 +129,8 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
private final int mNormalColor;
private final int mLowPriorityColor;
private boolean mIsBelowSpeedBump;
+ private ViewInvertHelper mBackgroundNormalInvertHelper;
+ private ViewInvertHelper mBackgroundDimmedInvertHelper;
public ActivatableNotificationView(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -145,6 +148,9 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
mNormalColor = context.getColor(R.color.notification_material_background_color);
mLowPriorityColor = context.getColor(
R.color.notification_material_background_low_priority_color);
+ int roundedRectCornerRadius = getResources().getDimensionPixelSize(
+ R.dimen.notification_material_rounded_rect_radius);
+ setRoundCornerRadius(roundedRectCornerRadius); // Themes: For drop-shadow rounded corners
mTintedRippleColor = context.getColor(
R.color.notification_ripple_tinted_color);
mLowPriorityRippleColor = context.getColor(
@@ -160,6 +166,10 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
mBackgroundDimmed = (NotificationBackgroundView) findViewById(R.id.backgroundDimmed);
mBackgroundNormal.setCustomBackground(R.drawable.notification_material_bg);
mBackgroundDimmed.setCustomBackground(R.drawable.notification_material_bg_dim);
+ mBackgroundNormalInvertHelper =
+ new ViewInvertHelper(mBackgroundNormal, DARK_ANIMATION_LENGTH);
+ mBackgroundDimmedInvertHelper =
+ new ViewInvertHelper(mBackgroundDimmed, DARK_ANIMATION_LENGTH);
updateBackground();
updateBackgroundTint();
}
@@ -393,15 +403,15 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
*/
private void fadeInFromDark(long delay) {
final View background = mDimmed ? mBackgroundDimmed : mBackgroundNormal;
- background.setAlpha(0f);
- background.setPivotX(mBackgroundDimmed.getWidth() / 2f);
- background.setPivotY(getActualHeight() / 2f);
- background.setScaleX(DARK_EXIT_SCALE_START);
- background.setScaleY(DARK_EXIT_SCALE_START);
+ if (mDimmed) {
+ mBackgroundDimmedInvertHelper.fade(false, delay);
+ mBackgroundNormalInvertHelper.update(false);
+ } else {
+ mBackgroundDimmedInvertHelper.update(false);
+ mBackgroundNormalInvertHelper.fade(false, delay);
+ }
background.animate()
.alpha(1f)
- .scaleX(1f)
- .scaleY(1f)
.setDuration(DARK_ANIMATION_LENGTH)
.setStartDelay(delay)
.setInterpolator(mLinearOutSlowInInterpolator)
@@ -409,8 +419,6 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
@Override
public void onAnimationCancel(Animator animation) {
// Jump state if we are cancelled
- background.setScaleX(1f);
- background.setScaleY(1f);
background.setAlpha(1f);
}
})
@@ -463,9 +471,11 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
private void updateBackground() {
cancelFadeAnimations();
+ mBackgroundNormalInvertHelper.update(mDark);
+ mBackgroundDimmedInvertHelper.update(mDark);
if (mDark) {
mBackgroundDimmed.setVisibility(View.INVISIBLE);
- mBackgroundNormal.setVisibility(View.INVISIBLE);
+ mBackgroundNormal.setVisibility(View.VISIBLE);
} else if (mDimmed) {
mBackgroundDimmed.setVisibility(View.VISIBLE);
mBackgroundNormal.setVisibility(View.INVISIBLE);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 9ff86eb..5213857 100644..100755
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -29,6 +29,8 @@ import android.app.admin.DevicePolicyManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
+import android.content.ContentResolver;
+import android.content.ContentValues;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
@@ -38,10 +40,12 @@ import android.content.pm.ResolveInfo;
import android.content.pm.UserInfo;
import android.content.res.Configuration;
import android.content.res.Resources;
+import android.content.res.ThemeConfig;
import android.database.ContentObserver;
import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
+import android.net.Uri;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
@@ -87,6 +91,9 @@ import com.android.internal.logging.MetricsLogger;
import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.statusbar.StatusBarIcon;
import com.android.internal.statusbar.StatusBarIconList;
+import com.android.internal.util.cm.SpamFilter;
+import com.android.internal.util.cm.SpamFilter.SpamContract.NotificationTable;
+import com.android.internal.util.cm.SpamFilter.SpamContract.PackageTable;
import com.android.internal.util.NotificationColorUtil;
import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.KeyguardUpdateMonitor;
@@ -97,6 +104,7 @@ import com.android.systemui.SwipeHelper;
import com.android.systemui.SystemUI;
import com.android.systemui.assist.AssistManager;
import com.android.systemui.recents.Recents;
+import com.android.systemui.cm.SpamMessageProvider;
import com.android.systemui.statusbar.NotificationData.Entry;
import com.android.systemui.statusbar.phone.NavigationBarView;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
@@ -146,6 +154,12 @@ public abstract class BaseStatusBar extends SystemUI implements
private static final String BANNER_ACTION_SETUP =
"com.android.systemui.statusbar.banner_action_setup";
+ private static final Uri SPAM_MESSAGE_URI = new Uri.Builder()
+ .scheme(ContentResolver.SCHEME_CONTENT)
+ .authority(SpamMessageProvider.AUTHORITY)
+ .appendPath("messages")
+ .build();
+
protected CommandQueue mCommandQueue;
protected IStatusBarService mBarService;
protected H mHandler = createHandler();
@@ -270,6 +284,10 @@ public abstract class BaseStatusBar extends SystemUI implements
}
};
+ public RemoteViews.OnClickHandler getOnClickHandler() {
+ return mOnClickHandler;
+ }
+
private RemoteViews.OnClickHandler mOnClickHandler = new RemoteViews.OnClickHandler() {
@Override
public boolean onClickHandler(
@@ -915,6 +933,7 @@ public abstract class BaseStatusBar extends SystemUI implements
final View settingsButton = guts.findViewById(R.id.notification_inspect_item);
final View appSettingsButton
= guts.findViewById(R.id.notification_inspect_app_provided_settings);
+ final View filterButton = guts.findViewById(R.id.notification_inspect_filter_notification);
if (appUid >= 0) {
final int appUidF = appUid;
settingsButton.setOnClickListener(new View.OnClickListener() {
@@ -924,6 +943,24 @@ public abstract class BaseStatusBar extends SystemUI implements
}
});
+ filterButton.setVisibility(View.VISIBLE);
+ filterButton.setOnClickListener(new View.OnClickListener() {
+ public void onClick(View v) {
+ AsyncTask.execute(new Runnable() {
+ @Override
+ public void run() {
+ ContentValues values = new ContentValues();
+ String message = SpamFilter.getNotificationContent(
+ sbn.getNotification());
+ values.put(NotificationTable.MESSAGE_TEXT, message);
+ values.put(PackageTable.PACKAGE_NAME, pkg);
+ mContext.getContentResolver().insert(SPAM_MESSAGE_URI, values);
+ }
+ });
+ removeNotification(sbn.getKey(), null);
+ }
+ });
+
final Intent appSettingsQueryIntent
= new Intent(Intent.ACTION_MAIN)
.addCategory(Notification.INTENT_CATEGORY_NOTIFICATION_PREFERENCES)
@@ -953,6 +990,7 @@ public abstract class BaseStatusBar extends SystemUI implements
} else {
settingsButton.setVisibility(View.GONE);
appSettingsButton.setVisibility(View.GONE);
+ filterButton.setVisibility(View.GONE);
}
}
@@ -1092,26 +1130,6 @@ public abstract class BaseStatusBar extends SystemUI implements
protected abstract View getStatusBarView();
- protected View.OnTouchListener mRecentsPreloadOnTouchListener = new View.OnTouchListener() {
- // additional optimization when we have software system buttons - start loading the recent
- // tasks on touch down
- @Override
- public boolean onTouch(View v, MotionEvent event) {
- int action = event.getAction() & MotionEvent.ACTION_MASK;
- if (action == MotionEvent.ACTION_DOWN) {
- preloadRecents();
- } else if (action == MotionEvent.ACTION_CANCEL) {
- cancelPreloadingRecents();
- } else if (action == MotionEvent.ACTION_UP) {
- if (!v.isPressed()) {
- cancelPreloadingRecents();
- }
-
- }
- return false;
- }
- };
-
/** Proxy for RecentsComponent */
protected void showRecents(boolean triggeredFromAltTab) {
@@ -1323,22 +1341,28 @@ public abstract class BaseStatusBar extends SystemUI implements
View contentViewLocal = null;
View bigContentViewLocal = null;
View headsUpContentViewLocal = null;
+ final ThemeConfig themeConfig = mContext.getResources().getConfiguration().themeConfig;
+ String themePackageName = themeConfig != null ?
+ themeConfig.getOverlayPkgNameForApp(mContext.getPackageName()) : null;
try {
contentViewLocal = contentView.apply(
sbn.getPackageContext(mContext),
contentContainer,
- mOnClickHandler);
+ mOnClickHandler,
+ themePackageName);
if (bigContentView != null) {
bigContentViewLocal = bigContentView.apply(
sbn.getPackageContext(mContext),
contentContainer,
- mOnClickHandler);
+ mOnClickHandler,
+ themePackageName);
}
if (headsUpContentView != null) {
headsUpContentViewLocal = headsUpContentView.apply(
sbn.getPackageContext(mContext),
contentContainer,
- mOnClickHandler);
+ mOnClickHandler,
+ themePackageName);
}
}
catch (RuntimeException e) {
@@ -2071,6 +2095,7 @@ public abstract class BaseStatusBar extends SystemUI implements
// update the contentIntent
mNotificationClicker.register(entry.row, notification);
+ applyColorsAndBackgrounds(notification, entry);
entry.row.setStatusBarNotification(notification);
entry.row.notifyContentUpdated();
entry.row.resetHeight();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index 897f5e5..83b2fb5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -78,6 +78,7 @@ public class CommandQueue extends IStatusBar.Stub {
private StatusBarIconList mList;
private Callbacks mCallbacks;
private Handler mHandler = new H();
+ private boolean mPaused = false;
/**
* These methods are called back on the main thread.
@@ -295,6 +296,14 @@ public class CommandQueue extends IStatusBar.Stub {
}
}
+ public void pause() {
+ mPaused = true;
+ }
+
+ public void resume() {
+ mPaused = false;
+ }
+
@Override
public void onCameraLaunchGestureDetected(int source) {
synchronized (mList) {
@@ -305,6 +314,10 @@ public class CommandQueue extends IStatusBar.Stub {
private final class H extends Handler {
public void handleMessage(Message msg) {
+ if (mPaused) {
+ this.sendMessageAtFrontOfQueue(Message.obtain(msg));
+ return;
+ }
final int what = msg.what & MSG_MASK;
switch (what) {
case MSG_ICON: {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CustomTileData.java b/packages/SystemUI/src/com/android/systemui/statusbar/CustomTileData.java
new file mode 100644
index 0000000..5db1f98
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CustomTileData.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2015 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 com.android.systemui.statusbar;
+
+import cyanogenmod.app.StatusBarPanelCustomTile;
+
+import android.util.ArrayMap;
+
+/**
+ * Custom tile data to keep track of created 3rd party tiles
+ */
+public class CustomTileData {
+ public static final class Entry {
+ public String key;
+ public StatusBarPanelCustomTile statusBarPanelCustomTile;
+
+ public Entry(StatusBarPanelCustomTile sbc) {
+ this.key = sbc.getKey();
+ }
+ }
+
+ private final ArrayMap<String, Entry> mEntries = new ArrayMap<>();
+
+ public ArrayMap<String, Entry> getEntries() {
+ return mEntries;
+ }
+
+ public void add(Entry entry) {
+ mEntries.put(entry.key, entry);
+ }
+
+ public Entry remove(String key) {
+ Entry removed = mEntries.remove(key);
+ if (removed == null) return null;
+ return removed;
+ }
+
+ public Entry get(String key) {
+ return mEntries.get(key);
+ }
+
+ public Entry get(int i) {
+ return mEntries.valueAt(i);
+ }
+
+ public void clear() {
+ mEntries.clear();
+ }
+
+ public int size() {
+ return mEntries.size();
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index 56e9af5..c964ca7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -531,6 +531,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
public void setExpandable(boolean expandable) {
mExpandable = expandable;
+ setClipToOutline(expandable);
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java
index a6fc4bb..cc50e49 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java
@@ -34,6 +34,7 @@ public abstract class ExpandableOutlineView extends ExpandableView {
private final Rect mOutlineRect = new Rect();
protected final int mRoundedRectCornerRadius;
private boolean mCustomOutline;
+ private float mRoundCornerRadius = 0;
private float mOutlineAlpha = 1f;
public ExpandableOutlineView(Context context, AttributeSet attrs) {
@@ -44,12 +45,12 @@ public abstract class ExpandableOutlineView extends ExpandableView {
@Override
public void getOutline(View view, Outline outline) {
if (!mCustomOutline) {
- outline.setRect(0,
+ outline.setRoundRect(0,
mClipTopAmount,
getWidth(),
- Math.max(getActualHeight(), mClipTopAmount));
+ Math.max(getActualHeight(), mClipTopAmount), mRoundCornerRadius);
} else {
- outline.setRoundRect(mOutlineRect, mRoundedRectCornerRadius);
+ outline.setRoundRect(mOutlineRect, mRoundCornerRadius);
}
outline.setAlpha(mOutlineAlpha);
}
@@ -96,4 +97,7 @@ public abstract class ExpandableOutlineView extends ExpandableView {
invalidateOutline();
}
+ protected void setRoundCornerRadius(float roundRadius) {
+ mRoundCornerRadius = roundRadius;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java
index 8058933..26b9c8e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java
@@ -25,9 +25,13 @@ import android.content.Context;
import android.graphics.Canvas;
import android.graphics.CanvasProperty;
import android.graphics.Color;
+import android.graphics.ColorFilter;
import android.graphics.Paint;
import android.graphics.PorterDuff;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
+import android.support.v7.graphics.Palette;
import android.util.AttributeSet;
import android.view.DisplayListCanvas;
import android.view.RenderNodeAnimator;
@@ -45,7 +49,7 @@ import com.android.systemui.statusbar.phone.PhoneStatusBar;
* An ImageView which does not have overlapping renderings commands and therefore does not need a
* layer when alpha is changed.
*/
-public class KeyguardAffordanceView extends ImageView {
+public class KeyguardAffordanceView extends ImageView implements Palette.PaletteAsyncListener {
private static final long CIRCLE_APPEAR_DURATION = 80;
private static final long CIRCLE_DISAPPEAR_MAX_DURATION = 200;
@@ -81,6 +85,7 @@ public class KeyguardAffordanceView extends ImageView {
private boolean mSupportHardware;
private boolean mFinishing;
private boolean mLaunchingAffordance;
+ private ColorFilter mDefaultFilter;
private CanvasProperty<Float> mHwCircleRadius;
private CanvasProperty<Float> mHwCenterX;
@@ -162,21 +167,66 @@ public class KeyguardAffordanceView extends ImageView {
canvas.restore();
}
+
+ @Override
+ public void setImageDrawable(Drawable drawable) {
+ super.setImageDrawable(drawable);
+ doPaletteIfNecessary();
+ }
+
+ private void doPaletteIfNecessary() {
+ if (mDefaultFilter != null && getDrawable() instanceof BitmapDrawable) {
+ Palette.generateAsync(((BitmapDrawable) getDrawable()).getBitmap(), this);
+ }
+ }
+
+
public void setPreviewView(View v) {
View oldPreviewView = mPreviewView;
mPreviewView = v;
if (mPreviewView != null) {
mPreviewView.setVisibility(mLaunchingAffordance
? oldPreviewView.getVisibility() : INVISIBLE);
+ mPreviewView.setVisibility(INVISIBLE);
+ addOverlay();
}
}
+ private void addOverlay() {
+ if (mPreviewView != null) {
+ mPreviewView.getOverlay().clear();
+ if (mDefaultFilter != null) {
+ ColorDrawable d = new ColorDrawable(mCircleColor);
+ d.setBounds(0, 0, mPreviewView.getWidth(), mPreviewView.getHeight());
+ mPreviewView.getOverlay().add(d);
+ }
+ }
+ }
+
+ public void setDefaultFilter(ColorFilter filter) {
+ mDefaultFilter = filter;
+ mCircleColor = Color.WHITE;
+ addOverlay();
+ updateIconColor();
+ }
+
private void updateIconColor() {
+ if (getDrawable() == null) {
+ return;
+ }
Drawable drawable = getDrawable().mutate();
float alpha = mCircleRadius / mMinBackgroundRadius;
alpha = Math.min(1.0f, alpha);
int color = (int) mColorInterpolator.evaluate(alpha, mNormalColor, mInverseColor);
- drawable.setColorFilter(color, PorterDuff.Mode.SRC_ATOP);
+ if (mDefaultFilter != null) {
+ if (alpha == 0) {
+ drawable.setColorFilter(mDefaultFilter);
+ } else {
+ drawable.setColorFilter(color, PorterDuff.Mode.DST_IN);
+ }
+ } else {
+ drawable.setColorFilter(color, PorterDuff.Mode.SRC_ATOP);
+ }
}
private void drawBackgroundCircle(Canvas canvas) {
@@ -551,4 +601,10 @@ public class KeyguardAffordanceView extends ImageView {
public void setLaunchingAffordance(boolean launchingAffordance) {
mLaunchingAffordance = launchingAffordance;
}
+
+ @Override
+ public void onGenerated(Palette palette) {
+ mCircleColor = palette.getDarkVibrantColor(Color.WHITE);
+ addOverlay();
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
index aedae52..c8c318b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
@@ -191,6 +191,14 @@ public class NotificationData {
return mEntries.get(key);
}
+ public Entry get(int i) {
+ return mEntries.valueAt(i);
+ }
+
+ public RankingMap getRankingMap() {
+ return mRankingMap;
+ }
+
public void add(Entry entry, RankingMap ranking) {
mEntries.put(entry.notification.getKey(), entry);
updateRankingAndSort(ranking);
@@ -288,6 +296,14 @@ public class NotificationData {
return false;
}
+ public void clear() {
+ mEntries.clear();
+ }
+
+ public int size() {
+ return mEntries.size();
+ }
+
// Q: What kinds of notifications should show during setup?
// A: Almost none! Only things coming from the system (package is "android") that also
// have special "kind" tags marking them as relevant for setup (see below).
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
index cc30882..e22b94c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
@@ -18,6 +18,7 @@ package com.android.systemui.statusbar;
import android.content.Context;
import android.content.res.ColorStateList;
+import android.content.res.Resources;
import android.graphics.Color;
import android.graphics.PorterDuff;
import android.graphics.drawable.Animatable;
@@ -67,8 +68,8 @@ public class SignalClusterView
private int mEthernetIconId = 0;
private int mLastEthernetIconId = -1;
private boolean mWifiVisible = false;
- private int mWifiStrengthId = 0;
- private int mLastWifiStrengthId = -1;
+ private int mWifiStrengthId = 0, mWifiActivityId = 0;
+ private int mLastWifiStrengthId = -1, mLastWifiActivityId = -1;
private boolean mIsAirplaneMode = false;
private int mAirplaneIconId = 0;
private int mLastAirplaneIconId = -1;
@@ -78,18 +79,18 @@ public class SignalClusterView
private ArrayList<PhoneState> mPhoneStates = new ArrayList<PhoneState>();
private int mIconTint = Color.WHITE;
private float mDarkIntensity;
+ private int mNoSimsIcon;
ViewGroup mEthernetGroup, mWifiGroup;
View mNoSimsCombo;
ImageView mVpn, mEthernet, mWifi, mAirplane, mNoSims, mEthernetDark, mWifiDark, mNoSimsDark;
+ ImageView mWifiActivity;
View mWifiAirplaneSpacer;
View mWifiSignalSpacer;
LinearLayout mMobileSignalGroup;
private int mWideTypeIconStartPadding;
private int mSecondaryTelephonyPadding;
- private int mEndPadding;
- private int mEndPaddingNothingVisible;
private boolean mBlockAirplane;
private boolean mBlockMobile;
@@ -150,10 +151,6 @@ public class SignalClusterView
R.dimen.wide_type_icon_start_padding);
mSecondaryTelephonyPadding = getContext().getResources().getDimensionPixelSize(
R.dimen.secondary_telephony_padding);
- mEndPadding = getContext().getResources().getDimensionPixelSize(
- R.dimen.signal_cluster_battery_padding);
- mEndPaddingNothingVisible = getContext().getResources().getDimensionPixelSize(
- R.dimen.no_signal_cluster_battery_padding);
}
@Override
@@ -167,6 +164,7 @@ public class SignalClusterView
mWifiGroup = (ViewGroup) findViewById(R.id.wifi_combo);
mWifi = (ImageView) findViewById(R.id.wifi_signal);
mWifiDark = (ImageView) findViewById(R.id.wifi_signal_dark);
+ mWifiActivity = (ImageView) findViewById(R.id.wifi_inout);
mAirplane = (ImageView) findViewById(R.id.airplane);
mNoSims = (ImageView) findViewById(R.id.no_sims);
mNoSimsDark = (ImageView) findViewById(R.id.no_sims_dark);
@@ -190,6 +188,7 @@ public class SignalClusterView
mEthernet = null;
mWifiGroup = null;
mWifi = null;
+ mWifiActivity = null;
mAirplane = null;
mMobileSignalGroup.removeAllViews();
mMobileSignalGroup = null;
@@ -215,6 +214,7 @@ public class SignalClusterView
boolean activityIn, boolean activityOut, String description) {
mWifiVisible = statusIcon.visible && !mBlockWifi;
mWifiStrengthId = statusIcon.icon;
+ mWifiActivityId = getWifiActivityId(activityIn, activityOut);
mWifiDescription = statusIcon.contentDescription;
apply();
@@ -222,8 +222,9 @@ public class SignalClusterView
@Override
public void setMobileDataIndicators(IconState statusIcon, IconState qsIcon, int statusType,
- int qsType, boolean activityIn, boolean activityOut, String typeContentDescription,
- String description, boolean isWide, int subId) {
+ int qsType, boolean activityIn, boolean activityOut, int dataActivityId,
+ int mobileActivityId, int stackedDataId, int stackedVoiceId,
+ String typeContentDescription, String description, boolean isWide, int subId) {
PhoneState state = getState(subId);
if (state == null) {
return;
@@ -234,6 +235,10 @@ public class SignalClusterView
state.mMobileDescription = statusIcon.contentDescription;
state.mMobileTypeDescription = typeContentDescription;
state.mIsMobileTypeIconWide = statusType != 0 && isWide;
+ state.mDataActivityId = dataActivityId;
+ state.mMobileActivityId = mobileActivityId;
+ state.mStackedDataId = stackedDataId;
+ state.mStackedVoiceId = stackedVoiceId;
apply();
}
@@ -295,6 +300,43 @@ public class SignalClusterView
return null;
}
+
+ private int getWifiActivityId(boolean activityIn, boolean activityOut) {
+ if (!getContext().getResources().getBoolean(R.bool.config_showWifiActivity)) {
+ return 0;
+ }
+ int activityId = 0;
+ if (activityIn && activityOut) {
+ activityId = R.drawable.stat_sys_wifi_inout;
+ } else if (activityIn) {
+ activityId = R.drawable.stat_sys_wifi_in;
+ } else if (activityOut) {
+ activityId = R.drawable.stat_sys_wifi_out;
+ }
+ return activityId;
+ }
+
+ private int getNoSimIcon() {
+ int resId = 0;
+ final String[] noSimArray;
+ Resources res = getContext().getResources();
+
+ if (!res.getBoolean(R.bool.config_read_icons_from_xml)) return resId;
+
+ try {
+ noSimArray = res.getStringArray(R.array.multi_no_sim);
+ } catch (android.content.res.Resources.NotFoundException e) {
+ return resId;
+ }
+
+ if (noSimArray == null) return resId;
+
+ String resName = noSimArray[0];
+ resId = res.getIdentifier(resName, null, getContext().getPackageName());
+ if (DEBUG) Log.d(TAG, "getNoSimIcon resId = " + resId + " resName = " + resName);
+ return resId;
+ }
+
private PhoneState inflatePhoneState(int subId) {
PhoneState state = new PhoneState(subId, mContext);
if (mMobileSignalGroup != null) {
@@ -349,6 +391,11 @@ public class SignalClusterView
mLastWifiStrengthId = -1;
}
+ if (mWifiActivity != null) {
+ mWifiActivity.setImageDrawable(null);
+ mLastWifiActivityId = -1;
+ }
+
for (PhoneState state : mPhoneStates) {
if (state.mMobile != null) {
state.mMobile.setImageDrawable(null);
@@ -401,6 +448,10 @@ public class SignalClusterView
mWifiDark.setImageResource(mWifiStrengthId);
mLastWifiStrengthId = mWifiStrengthId;
}
+ if (mWifiActivityId != mLastWifiActivityId) {
+ mWifiActivity.setImageResource(mWifiActivityId);
+ mLastWifiActivityId = mWifiActivityId;
+ }
mWifiGroup.setContentDescription(mWifiDescription);
mWifiGroup.setVisibility(View.VISIBLE);
} else {
@@ -408,9 +459,9 @@ public class SignalClusterView
}
if (DEBUG) Log.d(TAG,
- String.format("wifi: %s sig=%d",
+ String.format("wifi: %s sig=%d act=%d",
(mWifiVisible ? "VISIBLE" : "GONE"),
- mWifiStrengthId));
+ mWifiStrengthId, mWifiActivityId));
boolean anyMobileVisible = false;
int firstMobileTypeId = 0;
@@ -446,11 +497,14 @@ public class SignalClusterView
mWifiSignalSpacer.setVisibility(View.GONE);
}
+ if (mNoSimsVisible && mNoSims != null && mNoSimsDark != null) {
+ if (mNoSimsIcon == 0) mNoSimsIcon = getNoSimIcon();
+ if (mNoSimsIcon != 0) {
+ mNoSims.setImageResource(mNoSimsIcon);
+ mNoSimsDark.setImageResource(mNoSimsIcon);
+ }
+ }
mNoSimsCombo.setVisibility(mNoSimsVisible ? View.VISIBLE : View.GONE);
-
- boolean anythingVisible = mNoSimsVisible || mWifiVisible || mIsAirplaneMode
- || anyMobileVisible || mVpnVisible || mEthernetVisible;
- setPaddingRelative(0, 0, anythingVisible ? mEndPadding : mEndPaddingNothingVisible, 0);
}
public void setIconTint(int tint, float darkIntensity) {
@@ -492,6 +546,11 @@ public class SignalClusterView
private ViewGroup mMobileGroup;
private ImageView mMobile, mMobileDark, mMobileType;
+ private int mDataActivityId = 0, mMobileActivityId = 0;
+ private int mStackedDataId = 0, mStackedVoiceId = 0;
+ private ImageView mDataActivity, mMobileActivity, mStackedData, mStackedVoice;
+ private ViewGroup mMobileSingleGroup, mMobileStackedGroup;
+
public PhoneState(int subId, Context context) {
ViewGroup root = (ViewGroup) LayoutInflater.from(context)
.inflate(R.layout.mobile_signal_group, null);
@@ -504,6 +563,14 @@ public class SignalClusterView
mMobile = (ImageView) root.findViewById(R.id.mobile_signal);
mMobileDark = (ImageView) root.findViewById(R.id.mobile_signal_dark);
mMobileType = (ImageView) root.findViewById(R.id.mobile_type);
+ mMobileActivity = (ImageView) root.findViewById(R.id.mobile_inout);
+
+ mDataActivity = (ImageView) root.findViewById(R.id.data_inout);
+ mStackedData = (ImageView) root.findViewById(R.id.mobile_signal_data);
+ mStackedVoice = (ImageView) root.findViewById(R.id.mobile_signal_voice);
+
+ mMobileSingleGroup = (ViewGroup) root.findViewById(R.id.mobile_signal_single);
+ mMobileStackedGroup = (ViewGroup) root.findViewById(R.id.mobile_signal_stacked);
}
public boolean apply(boolean isSecondaryIcon) {
@@ -527,6 +594,37 @@ public class SignalClusterView
}
mMobileType.setImageResource(mMobileTypeId);
+
+ mDataActivity.setImageResource(mDataActivityId);
+ Drawable dataActivityDrawable = mDataActivity.getDrawable();
+ if (dataActivityDrawable instanceof Animatable) {
+ Animatable ad = (Animatable) dataActivityDrawable;
+ if (!ad.isRunning()) {
+ ad.start();
+ }
+ }
+
+ mMobileActivity.setImageResource(mMobileActivityId);
+ Drawable mobileActivityDrawable = mMobileActivity.getDrawable();
+ if (mobileActivityDrawable instanceof Animatable) {
+ Animatable ad = (Animatable) mobileActivityDrawable;
+ if (!ad.isRunning()) {
+ ad.start();
+ }
+ }
+
+ if (mStackedDataId != 0 && mStackedVoiceId != 0) {
+ mStackedData.setImageResource(mStackedDataId);
+ mStackedVoice.setImageResource(mStackedVoiceId);
+ mMobileSingleGroup.setVisibility(View.GONE);
+ mMobileStackedGroup.setVisibility(View.VISIBLE);
+ } else {
+ mStackedData.setImageResource(0);
+ mStackedVoice.setImageResource(0);
+ mMobileSingleGroup.setVisibility(View.VISIBLE);
+ mMobileStackedGroup.setVisibility(View.GONE);
+ }
+
mMobileGroup.setContentDescription(mMobileTypeDescription
+ " " + mMobileDescription);
mMobileGroup.setVisibility(View.VISIBLE);
@@ -546,6 +644,8 @@ public class SignalClusterView
(mMobileVisible ? "VISIBLE" : "GONE"), mMobileStrengthId, mMobileTypeId));
mMobileType.setVisibility(mMobileTypeId != 0 ? View.VISIBLE : View.GONE);
+ mDataActivity.setVisibility(mDataActivityId != 0 ? View.VISIBLE : View.GONE);
+ mMobileActivity.setVisibility(mMobileActivityId != 0 ? View.VISIBLE : View.GONE);
return mMobileVisible;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StackScrollerDecorView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StackScrollerDecorView.java
index 2f66c41..9103525 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StackScrollerDecorView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StackScrollerDecorView.java
@@ -87,6 +87,7 @@ public abstract class StackScrollerDecorView extends ExpandableView {
mAnimating = true;
mContent.animate()
.alpha(endValue)
+ .withLayer()
.setInterpolator(interpolator)
.setDuration(260)
.withEndAction(new Runnable() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
index baac8ac..4371cce 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
@@ -19,12 +19,16 @@ package com.android.systemui.statusbar;
import android.app.Notification;
import android.content.Context;
import android.content.res.Resources;
+import android.content.res.ThemeConfig;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
+import android.graphics.Typeface;
+import android.os.Handler;
import android.os.UserHandle;
+import android.provider.Settings;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.Log;
@@ -34,8 +38,12 @@ import android.widget.ImageView;
import com.android.internal.statusbar.StatusBarIcon;
import com.android.systemui.R;
+import com.android.systemui.cm.UserContentObserver;
import java.text.NumberFormat;
+import java.util.ArrayList;
+
+import cyanogenmod.providers.CMSettings;
public class StatusBarIconView extends AnimatedImageView {
private static final String TAG = "StatusBarIconView";
@@ -43,12 +51,14 @@ public class StatusBarIconView extends AnimatedImageView {
private StatusBarIcon mIcon;
@ViewDebug.ExportedProperty private String mSlot;
private Drawable mNumberBackground;
- private Paint mNumberPain;
+ private Paint mNumberPaint;
private int mNumberX;
private int mNumberY;
private String mNumberText;
private Notification mNotification;
private final boolean mBlocked;
+ private boolean mShowNotificationCount;
+ private GlobalSettingsObserver mObserver;
public StatusBarIconView(Context context, String slot, Notification notification) {
this(context, slot, notification, false);
@@ -60,12 +70,10 @@ public class StatusBarIconView extends AnimatedImageView {
final Resources res = context.getResources();
mBlocked = blocked;
mSlot = slot;
- mNumberPain = new Paint();
- mNumberPain.setTextAlign(Paint.Align.CENTER);
- mNumberPain.setColor(context.getColor(R.drawable.notification_number_text_color));
- mNumberPain.setAntiAlias(true);
setNotification(notification);
+ mObserver = GlobalSettingsObserver.getInstance(context);
+
// We do not resize and scale system icons (on the right), only notification icons (on the
// left).
if (notification != null) {
@@ -81,6 +89,8 @@ public class StatusBarIconView extends AnimatedImageView {
public void setNotification(Notification notification) {
mNotification = notification;
+ mShowNotificationCount = CMSettings.System.getIntForUser(mContext.getContentResolver(),
+ CMSettings.System.STATUS_BAR_NOTIF_COUNT, 0, UserHandle.USER_CURRENT) == 1;
setContentDescription(notification);
}
@@ -124,6 +134,10 @@ public class StatusBarIconView extends AnimatedImageView {
* Returns whether the set succeeded.
*/
public boolean set(StatusBarIcon icon) {
+ return set(icon, false);
+ }
+
+ private boolean set(StatusBarIcon icon, boolean force) {
final boolean iconEquals = mIcon != null && equalIcons(mIcon.icon, icon.icon);
final boolean levelEquals = iconEquals
&& mIcon.iconLevel == icon.iconLevel;
@@ -133,17 +147,25 @@ public class StatusBarIconView extends AnimatedImageView {
&& mIcon.number == icon.number;
mIcon = icon.clone();
setContentDescription(icon.contentDescription);
- if (!iconEquals) {
+ if (!iconEquals || force) {
if (!updateDrawable(false /* no clear */)) return false;
}
- if (!levelEquals) {
+ if (!levelEquals || force) {
setImageLevel(icon.iconLevel);
}
- if (!numberEquals) {
- if (icon.number > 0 && getContext().getResources().getBoolean(
- R.bool.config_statusBarShowNumber)) {
+ if (!numberEquals || force) {
+ if (icon.number > 1 && mShowNotificationCount) {
if (mNumberBackground == null) {
+ final Resources res = mContext.getResources();
+ final float densityMultiplier = res.getDisplayMetrics().density;
+ final float scaledPx = 8 * densityMultiplier;
+ mNumberPaint = new Paint();
+ mNumberPaint.setTextAlign(Paint.Align.CENTER);
+ mNumberPaint.setColor(res.getColor(R.drawable.notification_number_text_color));
+ mNumberPaint.setAntiAlias(true);
+ mNumberPaint.setTypeface(Typeface.DEFAULT_BOLD);
+ mNumberPaint.setTextSize(scaledPx);
mNumberBackground = getContext().getResources().getDrawable(
R.drawable.ic_notification_overlay);
}
@@ -151,10 +173,11 @@ public class StatusBarIconView extends AnimatedImageView {
} else {
mNumberBackground = null;
mNumberText = null;
+ mNumberPaint = null;
}
invalidate();
}
- if (!visibilityEquals) {
+ if (!visibilityEquals || force) {
setVisibility(icon.visible && !mBlocked ? VISIBLE : GONE);
}
return true;
@@ -211,6 +234,10 @@ public class StatusBarIconView extends AnimatedImageView {
}
}
+ public String getStatusBarSlot() {
+ return mSlot;
+ }
+
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
@@ -231,7 +258,25 @@ public class StatusBarIconView extends AnimatedImageView {
if (mNumberBackground != null) {
mNumberBackground.draw(canvas);
- canvas.drawText(mNumberText, mNumberX, mNumberY, mNumberPain);
+ canvas.drawText(mNumberText, mNumberX, mNumberY, mNumberPaint);
+ }
+ }
+
+ @Override
+ public void onAttachedToWindow() {
+ super.onAttachedToWindow();
+
+ if (mObserver != null) {
+ mObserver.attach(this);
+ }
+ }
+
+ @Override
+ public void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+
+ if (mObserver != null) {
+ mObserver.detach(this);
}
}
@@ -248,7 +293,7 @@ public class StatusBarIconView extends AnimatedImageView {
android.R.integer.status_bar_notification_info_maxnum);
if (mIcon.number > tooBig) {
str = getContext().getResources().getString(
- android.R.string.status_bar_notification_info_overflow);
+ R.string.status_bar_notification_info_overflow);
} else {
NumberFormat f = NumberFormat.getIntegerInstance();
str = f.format(mIcon.number);
@@ -258,7 +303,7 @@ public class StatusBarIconView extends AnimatedImageView {
final int w = getWidth();
final int h = getHeight();
final Rect r = new Rect();
- mNumberPain.getTextBounds(str, 0, str.length(), r);
+ mNumberPaint.getTextBounds(str, 0, str.length(), r);
final int tw = r.right - r.left;
final int th = r.bottom - r.top;
mNumberBackground.getPadding(r);
@@ -292,4 +337,63 @@ public class StatusBarIconView extends AnimatedImageView {
public String getSlot() {
return mSlot;
}
+
+ static class GlobalSettingsObserver extends UserContentObserver {
+ private static GlobalSettingsObserver sInstance;
+ private ArrayList<StatusBarIconView> mIconViews = new ArrayList<StatusBarIconView>();
+ private Context mContext;
+
+ GlobalSettingsObserver(Handler handler, Context context) {
+ super(handler);
+ mContext = context.getApplicationContext();
+ }
+
+ static GlobalSettingsObserver getInstance(Context context) {
+ if (sInstance == null) {
+ sInstance = new GlobalSettingsObserver(new Handler(), context);
+ }
+ return sInstance;
+ }
+
+ void attach(StatusBarIconView sbiv) {
+ if (mIconViews.isEmpty()) {
+ observe();
+ }
+ mIconViews.add(sbiv);
+ }
+
+ void detach(StatusBarIconView sbiv) {
+ mIconViews.remove(sbiv);
+ if (mIconViews.isEmpty()) {
+ unobserve();
+ }
+ }
+
+ @Override
+ protected void observe() {
+ super.observe();
+
+ mContext.getContentResolver().registerContentObserver(
+ CMSettings.System.getUriFor(CMSettings.System.STATUS_BAR_NOTIF_COUNT),
+ false, this);
+ }
+
+ @Override
+ protected void unobserve() {
+ super.unobserve();
+
+ mContext.getContentResolver().unregisterContentObserver(this);
+ }
+
+ @Override
+ public void update() {
+ boolean showIconCount = CMSettings.System.getIntForUser(mContext.getContentResolver(),
+ CMSettings.System.STATUS_BAR_NOTIF_COUNT, 0, UserHandle.USER_CURRENT) == 1;
+ for (StatusBarIconView sbiv : mIconViews) {
+ sbiv.mShowNotificationCount = showIconCount;
+ sbiv.set(sbiv.mIcon, true);
+ }
+ }
+ }
}
+
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BackButtonDrawable.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BackButtonDrawable.java
new file mode 100644
index 0000000..c76b5d3
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BackButtonDrawable.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2014 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 com.android.systemui.statusbar.phone;
+
+import android.animation.Animator;
+import android.animation.ObjectAnimator;
+import android.annotation.NonNull;
+import android.app.ActivityManager;
+import android.graphics.Canvas;
+import android.graphics.ColorFilter;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.util.FloatProperty;
+import android.util.Property;
+
+public class BackButtonDrawable extends Drawable {
+ private final Drawable mWrappedDrawable;
+ private float mRotation;
+ private Animator mCurrentAnimator;
+
+ private static final int ANIMATION_DURATION = 200;
+ public static final Property<BackButtonDrawable, Float> ROTATION
+ = new FloatProperty<BackButtonDrawable>("rotation") {
+ @Override
+ public void setValue(BackButtonDrawable object, float value) {
+ object.setRotation(value);
+ }
+
+ @Override
+ public Float get(BackButtonDrawable object) {
+ return object.getRotation();
+ }
+ };
+
+ public BackButtonDrawable(Drawable wrappedDrawable) {
+ mWrappedDrawable = wrappedDrawable;
+ }
+
+ @Override
+ public void draw(Canvas canvas) {
+ final Rect bounds = mWrappedDrawable.getBounds();
+ final int boundsCenterX = bounds.width() / 2;
+ final int boundsCenterY = bounds.height() / 2;
+
+ canvas.translate(boundsCenterX, boundsCenterY);
+ canvas.rotate(mRotation);
+ canvas.translate(- boundsCenterX, - boundsCenterY);
+
+ mWrappedDrawable.draw(canvas);
+ }
+
+ @Override
+ public void setBounds(Rect bounds) {
+ mWrappedDrawable.setBounds(bounds);
+ }
+
+ @Override
+ public void setBounds(int left, int top, int right, int bottom) {
+ mWrappedDrawable.setBounds(left, top, right, bottom);
+ }
+
+ @Override
+ protected void onBoundsChange(Rect bounds) {
+ mWrappedDrawable.setBounds(bounds);
+ }
+
+ @Override
+ public void setAlpha(int alpha) {
+ mWrappedDrawable.setAlpha(alpha);
+ if (mCurrentAnimator != null) {
+ mCurrentAnimator.end();
+ }
+ }
+
+ @Override
+ public int getAlpha() {
+ return mWrappedDrawable.getAlpha();
+ }
+
+ @Override
+ public void setColorFilter(ColorFilter cf) {
+ }
+
+ @Override
+ public int getOpacity() {
+ return mWrappedDrawable.getOpacity();
+ }
+
+ @Override
+ public int getIntrinsicWidth() {
+ return mWrappedDrawable.getIntrinsicWidth();
+ }
+
+ @Override
+ public int getIntrinsicHeight() {
+ return mWrappedDrawable.getIntrinsicHeight();
+ }
+
+ public void setRotation(float rotation) {
+ mRotation = rotation;
+ invalidateSelf();
+ }
+
+ public float getRotation() {
+ return mRotation;
+ }
+
+ public void setImeVisible(boolean ime) {
+ if (mCurrentAnimator != null) {
+ mCurrentAnimator.cancel();
+ }
+
+ final float nextRotation = ime ? - 90 : 0;
+ if (mRotation == nextRotation) {
+ return;
+ }
+
+ if (isVisible() && ActivityManager.isHighEndGfx()) {
+ mCurrentAnimator = ObjectAnimator.ofFloat(this, ROTATION, nextRotation)
+ .setDuration(ANIMATION_DURATION);
+ mCurrentAnimator.start();
+ } else {
+ setRotation(nextRotation);
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java
index 1601b83..093d18c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java
@@ -57,15 +57,28 @@ public class BarTransitions {
private int mMode;
- public BarTransitions(View view, int gradientResourceId) {
+ public BarTransitions(View view, int gradientResourceId, int opaqueColorResourceId,
+ int semiTransparentColorResourceId, int transparentColorResourceId,
+ int warningColorResourceId) {
mTag = "BarTransitions." + view.getClass().getSimpleName();
mView = view;
- mBarBackground = new BarBackgroundDrawable(mView.getContext(), gradientResourceId);
+ mBarBackground = new BarBackgroundDrawable(mView.getContext(), gradientResourceId,
+ opaqueColorResourceId, semiTransparentColorResourceId,
+ transparentColorResourceId, warningColorResourceId);
if (HIGH_END) {
mView.setBackground(mBarBackground);
}
}
+ protected void setGradientResourceId(int gradientResourceId) {
+ mBarBackground.setGradientResourceId(mView.getContext().getResources(),
+ gradientResourceId);
+ }
+
+ public void updateResources(Resources res) {
+ mBarBackground.updateResources(res);
+ }
+
public int getMode() {
return mMode;
}
@@ -119,11 +132,11 @@ public class BarTransitions {
}
private static class BarBackgroundDrawable extends Drawable {
- private final int mOpaque;
- private final int mSemiTransparent;
- private final int mTransparent;
- private final int mWarning;
- private final Drawable mGradient;
+ private int mOpaque;
+ private int mSemiTransparent;
+ private int mTransparent;
+ private int mWarning;
+ private Drawable mGradient;
private final TimeInterpolator mInterpolator;
private int mMode = -1;
@@ -137,7 +150,15 @@ public class BarTransitions {
private int mGradientAlphaStart;
private int mColorStart;
- public BarBackgroundDrawable(Context context, int gradientResourceId) {
+ private int mGradientResourceId;
+ private final int mOpaqueColorResourceId;
+ private final int mSemiTransparentColorResourceId;
+ private final int mTransparentColorResourceId;
+ private final int mWarningColorResourceId;
+
+ public BarBackgroundDrawable(Context context, int gradientResourceId,
+ int opaqueColorResourceId, int semiTransparentColorResourceId,
+ int transparentColorResourceId, int warningColorResourceId) {
final Resources res = context.getResources();
if (DEBUG_COLORS) {
mOpaque = 0xff0000ff;
@@ -145,13 +166,36 @@ public class BarTransitions {
mTransparent = 0x2f0000ff;
mWarning = 0xffff0000;
} else {
- mOpaque = context.getColor(R.color.system_bar_background_opaque);
- mSemiTransparent = context.getColor(R.color.system_bar_background_semi_transparent);
- mTransparent = context.getColor(R.color.system_bar_background_transparent);
- mWarning = context.getColor(com.android.internal.R.color.battery_saver_mode_color);
+ mOpaque = res.getColor(R.color.system_bar_background_opaque);
+ mSemiTransparent = res.getColor(R.color.system_bar_background_semi_transparent);
+ mTransparent = res.getColor(transparentColorResourceId);
+ mWarning = res.getColor(warningColorResourceId);
}
mGradient = context.getDrawable(gradientResourceId);
mInterpolator = new LinearInterpolator();
+ mGradientResourceId = gradientResourceId;
+ mOpaqueColorResourceId = opaqueColorResourceId;
+ mSemiTransparentColorResourceId = semiTransparentColorResourceId;
+ mTransparentColorResourceId = transparentColorResourceId;
+ mWarningColorResourceId = warningColorResourceId;
+ }
+
+ public void setGradientResourceId(Resources res, int gradientResourceId) {
+ mGradient = res.getDrawable(gradientResourceId);
+ mGradientResourceId = gradientResourceId;
+ }
+
+ public void updateResources(Resources res) {
+ mOpaque = res.getColor(mOpaqueColorResourceId);
+ mSemiTransparent = res.getColor(mSemiTransparentColorResourceId);
+ mTransparent = res.getColor(mTransparentColorResourceId);
+ mWarning = res.getColor(mWarningColorResourceId);
+ // Retrieve the current bounds for mGradient so they can be set to
+ // the new drawable being loaded, otherwise the bounds will be (0, 0, 0, 0)
+ // and the gradient will not be drawn.
+ Rect bounds = mGradient.getBounds();
+ mGradient = res.getDrawable(mGradientResourceId);
+ mGradient.setBounds(bounds);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BlurLayer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BlurLayer.java
new file mode 100644
index 0000000..a966409
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BlurLayer.java
@@ -0,0 +1,196 @@
+/*
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.android.systemui.statusbar.phone;
+
+import android.graphics.PixelFormat;
+import android.util.Slog;
+import android.view.SurfaceControl;
+import android.view.SurfaceSession;
+
+import java.io.PrintWriter;
+
+public class BlurLayer {
+ private static final String TAG = "BlurLayer";
+ private static final boolean DEBUG = true;
+ private SurfaceControl mBlurSurface;
+ private int mLayer = -1;
+ private float mAlpha = 0;
+ private float mBlur = 0;
+ private int mX, mY;
+ private int mW, mH;
+ private boolean mIsShow;
+
+ public BlurLayer(SurfaceSession mFxSession, int w, int h, String tag) {
+ this(mFxSession, 0, 0, w, h, tag);
+ }
+
+ public BlurLayer(SurfaceSession mFxSession, int x, int y, int w, int h, String tag) {
+ mX = x;
+ mY = y;
+ mW = w;
+ mH = h;
+ mIsShow = false;
+
+ SurfaceControl.openTransaction();
+ try {
+ mBlurSurface = new SurfaceControl(mFxSession, TAG+"_"+tag, 16, 16, PixelFormat.OPAQUE,
+ SurfaceControl.FX_SURFACE_BLUR | SurfaceControl.HIDDEN);
+ mBlurSurface.setLayerStack(0);
+ mBlurSurface.setPosition(mX, mY);
+ mBlurSurface.setSize(mW, mH);
+ } catch (Exception e) {
+ Slog.e(TAG, "Exception creating BlurLayer surface", e);
+ } finally {
+ SurfaceControl.closeTransaction();
+ }
+ }
+
+ public void setSize(int w, int h) {
+ if (mBlurSurface != null && (mW != w || mH != h) ) {
+ SurfaceControl.openTransaction();
+ try {
+ mBlurSurface.setSize(w, h);
+ mW = w;
+ mH = h;
+ } catch (RuntimeException e) {
+ Slog.w(TAG, "Failure setting setSize immediately", e);
+ } catch (Exception e) {
+ Slog.e(TAG, "Exception setSize", e);
+ } finally {
+ SurfaceControl.closeTransaction();
+ }
+ }
+ }
+
+ public void setPosition(int x, int y) {
+ if (mBlurSurface != null && (mX != x || mY != y) ) {
+ SurfaceControl.openTransaction();
+ try {
+ mBlurSurface.setPosition(x, y);
+ mX = x;
+ mY = y;
+ } catch (RuntimeException e) {
+ Slog.w(TAG, "Failure setting setPosition immediately", e);
+ } catch (Exception e) {
+ Slog.e(TAG, "Exception setPosition", e);
+ } finally {
+ SurfaceControl.closeTransaction();
+ }
+ }
+ }
+
+ public void setLayer(int layer) {
+ if (mBlurSurface != null && mLayer != layer) {
+ SurfaceControl.openTransaction();
+ try {
+ mBlurSurface.setLayer(layer);
+ mLayer = layer;
+ } catch (RuntimeException e) {
+ Slog.w(TAG, "Failure setting setLayer immediately", e);
+ } catch (Exception e) {
+ Slog.e(TAG, "Exception setLayer", e);
+ } finally {
+ SurfaceControl.closeTransaction();
+ }
+ }
+ }
+
+ public void setAlpha(float alpha){
+ if(mBlurSurface != null && mAlpha != alpha){
+ SurfaceControl.openTransaction();
+ try {
+ mBlurSurface.setAlpha(alpha);
+ mAlpha = alpha;
+ } catch (RuntimeException e) {
+ Slog.w(TAG, "Failure setting alpha immediately", e);
+ } catch (Exception e) {
+ Slog.e(TAG, "Exception setAlpha", e);
+ } finally {
+ SurfaceControl.closeTransaction();
+ }
+ }
+ }
+
+ public void setBlur(float blur){
+ if(mBlurSurface != null && mBlur != blur ){
+ SurfaceControl.openTransaction();
+ try {
+ mBlurSurface.setBlur(blur);
+ mBlur = blur;
+ } catch (RuntimeException e) {
+ Slog.w(TAG, "Failure setting blur immediately", e);
+ } catch (Exception e) {
+ Slog.e(TAG, "Exception setBlur", e);
+ } finally {
+ SurfaceControl.closeTransaction();
+ }
+ }
+ }
+
+ public void show() {
+ if(mBlurSurface != null && !mIsShow ){
+ try {
+ mBlurSurface.show();
+ mIsShow = true;
+ } catch (RuntimeException e) {
+ Slog.w(TAG, "Failure show()", e);
+ } catch (Exception e) {
+ Slog.e(TAG, "Exception show()", e);
+ } finally {
+ SurfaceControl.closeTransaction();
+ }
+ }
+ }
+
+ public void hide(){
+ if(mBlurSurface != null && mIsShow ){
+ try {
+ mBlurSurface.hide();
+ mIsShow = false;
+ } catch (RuntimeException e) {
+ Slog.w(TAG, "Failure hide()", e);
+ } catch (Exception e) {
+ Slog.e(TAG, "Exception hide()", e);
+ } finally {
+ SurfaceControl.closeTransaction();
+ }
+ }
+ }
+
+ public void destroySurface() {
+ if (DEBUG) Slog.v(TAG, "destroySurface.");
+ if (mBlurSurface != null) {
+ mBlurSurface.destroy();
+ mBlurSurface = null;
+ }
+ }
+
+}
+
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ClockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ClockController.java
new file mode 100644
index 0000000..47b3463
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ClockController.java
@@ -0,0 +1,145 @@
+package com.android.systemui.statusbar.phone;
+
+import com.android.systemui.FontSizeUtils;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.database.ContentObserver;
+import android.graphics.Color;
+import android.os.Handler;
+import android.os.UserHandle;
+import android.view.View;
+import com.android.systemui.R;
+import com.android.systemui.cm.UserContentObserver;
+import com.android.systemui.statusbar.policy.Clock;
+
+import cyanogenmod.providers.CMSettings;
+
+/**
+ * To control your...clock
+ */
+public class ClockController {
+
+ public static final int STYLE_HIDE_CLOCK = 0;
+ public static final int STYLE_CLOCK_RIGHT = 1;
+ public static final int STYLE_CLOCK_CENTER = 2;
+ public static final int STYLE_CLOCK_LEFT = 3;
+
+ private final IconMerger mNotificationIcons;
+ private final Context mContext;
+ private final SettingsObserver mSettingsObserver;
+ private Clock mRightClock, mCenterClock, mLeftClock, mActiveClock;
+
+ private int mClockLocation;
+ private int mAmPmStyle;
+ private int mIconTint = Color.WHITE;
+
+ class SettingsObserver extends UserContentObserver {
+ SettingsObserver(Handler handler) {
+ super(handler);
+ }
+
+ @Override
+ protected void observe() {
+ super.observe();
+ ContentResolver resolver = mContext.getContentResolver();
+ resolver.registerContentObserver(CMSettings.System.getUriFor(
+ CMSettings.System.STATUS_BAR_AM_PM), false, this, UserHandle.USER_ALL);
+ resolver.registerContentObserver(CMSettings.System.getUriFor(
+ CMSettings.System.STATUS_BAR_CLOCK), false, this, UserHandle.USER_ALL);
+ updateSettings();
+ }
+
+ @Override
+ protected void unobserve() {
+ super.unobserve();
+ mContext.getContentResolver().unregisterContentObserver(this);
+ }
+
+ @Override
+ public void update() {
+ updateSettings();
+ }
+ }
+
+ public ClockController(View statusBar, IconMerger notificationIcons, Handler handler) {
+ mRightClock = (Clock) statusBar.findViewById(R.id.clock);
+ mCenterClock = (Clock) statusBar.findViewById(R.id.center_clock);
+ mLeftClock = (Clock) statusBar.findViewById(R.id.left_clock);
+ mNotificationIcons = notificationIcons;
+ mContext = statusBar.getContext();
+
+ mActiveClock = mRightClock;
+ mSettingsObserver = new SettingsObserver(handler);
+ mSettingsObserver.observe();
+ }
+
+ private Clock getClockForCurrentLocation() {
+ Clock clockForAlignment;
+ switch (mClockLocation) {
+ case STYLE_CLOCK_CENTER:
+ clockForAlignment = mCenterClock;
+ break;
+ case STYLE_CLOCK_LEFT:
+ clockForAlignment = mLeftClock;
+ break;
+ case STYLE_CLOCK_RIGHT:
+ case STYLE_HIDE_CLOCK:
+ default:
+ clockForAlignment = mRightClock;
+ break;
+ }
+ return clockForAlignment;
+ }
+
+ private void updateActiveClock() {
+ mActiveClock.setVisibility(View.GONE);
+ if (mClockLocation == STYLE_HIDE_CLOCK) {
+ return;
+ }
+
+ mActiveClock = getClockForCurrentLocation();
+ mActiveClock.setVisibility(View.VISIBLE);
+ mActiveClock.setAmPmStyle(mAmPmStyle);
+
+ setClockAndDateStatus();
+ setTextColor(mIconTint);
+ updateFontSize();
+ }
+
+ private void updateSettings() {
+ ContentResolver resolver = mContext.getContentResolver();
+ mAmPmStyle = CMSettings.System.getIntForUser(resolver,
+ CMSettings.System.STATUS_BAR_AM_PM, Clock.AM_PM_STYLE_GONE,
+ UserHandle.USER_CURRENT);
+ mClockLocation = CMSettings.System.getIntForUser(
+ resolver, CMSettings.System.STATUS_BAR_CLOCK, STYLE_CLOCK_RIGHT,
+ UserHandle.USER_CURRENT);
+ updateActiveClock();
+ }
+
+ private void setClockAndDateStatus() {
+ if (mNotificationIcons != null) {
+ mNotificationIcons.setClockAndDateStatus(mClockLocation);
+ }
+ }
+
+ public void setVisibility(boolean visible) {
+ if (mActiveClock != null) {
+ mActiveClock.setVisibility(visible ? View.VISIBLE : View.GONE);
+ }
+ }
+
+ public void setTextColor(int iconTint) {
+ mIconTint = iconTint;
+ if (mActiveClock != null) {
+ mActiveClock.setTextColor(iconTint);
+ }
+ }
+
+ public void updateFontSize() {
+ if (mActiveClock != null) {
+ FontSizeUtils.updateFontSize(mActiveClock, R.dimen.status_bar_clock_size);
+ }
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
index 1d890d0..9897098 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
@@ -22,6 +22,7 @@ import android.text.TextUtils;
import android.util.Log;
import android.util.MathUtils;
+import com.android.systemui.doze.DozeLog;
import com.android.systemui.R;
import java.io.PrintWriter;
@@ -46,17 +47,20 @@ public class DozeParameters {
public void dump(PrintWriter pw) {
pw.println(" DozeParameters:");
pw.print(" getDisplayStateSupported(): "); pw.println(getDisplayStateSupported());
- pw.print(" getPulseDuration(pickup=false): "); pw.println(getPulseDuration(false));
- pw.print(" getPulseDuration(pickup=true): "); pw.println(getPulseDuration(true));
- pw.print(" getPulseInDuration(pickup=false): "); pw.println(getPulseInDuration(false));
- pw.print(" getPulseInDuration(pickup=true): "); pw.println(getPulseInDuration(true));
+ pw.print(" getPulseDuration(notification): "); pw.println(getPulseDuration(DozeLog.PULSE_REASON_NOTIFICATION));
+ pw.print(" getPulseDuration(pickup): "); pw.println(getPulseDuration(DozeLog.PULSE_REASON_SENSOR_PICKUP));
+ pw.print(" getPulseDuration(intent): "); pw.println(getPulseDuration(DozeLog.PULSE_REASON_INTENT));
+ pw.print(" getPulseInDuration(notification): "); pw.println(getPulseInDuration(DozeLog.PULSE_REASON_NOTIFICATION));
+ pw.print(" getPulseInDuration(pickup): "); pw.println(getPulseInDuration(DozeLog.PULSE_REASON_SENSOR_PICKUP));
+ pw.print(" getPulseInDuration(intent): "); pw.println(getPulseInDuration(DozeLog.PULSE_REASON_INTENT));
pw.print(" getPulseInVisibleDuration(): "); pw.println(getPulseVisibleDuration());
pw.print(" getPulseOutDuration(): "); pw.println(getPulseOutDuration());
pw.print(" getPulseOnSigMotion(): "); pw.println(getPulseOnSigMotion());
pw.print(" getVibrateOnSigMotion(): "); pw.println(getVibrateOnSigMotion());
pw.print(" getPulseOnPickup(): "); pw.println(getPulseOnPickup());
pw.print(" getVibrateOnPickup(): "); pw.println(getVibrateOnPickup());
- pw.print(" getProxCheckBeforePulse(): "); pw.println(getProxCheckBeforePulse());
+ pw.print(" getProxCheckBeforePulse(pickup): "); pw.println(getProxCheckBeforePulse(DozeLog.PULSE_REASON_SENSOR_PICKUP));
+ pw.print(" getProxCheckBeforePulse(intent): "); pw.println(getProxCheckBeforePulse(DozeLog.PULSE_REASON_INTENT));
pw.print(" getPulseOnNotifications(): "); pw.println(getPulseOnNotifications());
pw.print(" getPulseSchedule(): "); pw.println(getPulseSchedule());
pw.print(" getPulseScheduleResets(): "); pw.println(getPulseScheduleResets());
@@ -68,14 +72,19 @@ public class DozeParameters {
return getBoolean("doze.display.supported", R.bool.doze_display_state_supported);
}
- public int getPulseDuration(boolean pickup) {
- return getPulseInDuration(pickup) + getPulseVisibleDuration() + getPulseOutDuration();
+ public int getPulseDuration(int reason) {
+ return getPulseInDuration(reason) + getPulseVisibleDuration() + getPulseOutDuration();
}
- public int getPulseInDuration(boolean pickup) {
- return pickup
- ? getInt("doze.pulse.duration.in.pickup", R.integer.doze_pulse_duration_in_pickup)
- : getInt("doze.pulse.duration.in", R.integer.doze_pulse_duration_in);
+ public int getPulseInDuration(int reason) {
+ switch(reason) {
+ case DozeLog.PULSE_REASON_SENSOR_PICKUP:
+ return getInt("doze.pulse.duration.in.pickup", R.integer.doze_pulse_duration_in_pickup);
+ case DozeLog.PULSE_REASON_INTENT:
+ return getInt("doze.pulse.duration.in.intent", R.integer.doze_pulse_duration_in_intent);
+ default:
+ return getInt("doze.pulse.duration.in", R.integer.doze_pulse_duration_in);
+ }
}
public int getPulseVisibleDuration() {
@@ -102,8 +111,15 @@ public class DozeParameters {
return SystemProperties.getBoolean("doze.vibrate.pickup", false);
}
- public boolean getProxCheckBeforePulse() {
- return getBoolean("doze.pulse.proxcheck", R.bool.doze_proximity_check_before_pulse);
+ public boolean getProxCheckBeforePulse(int reason) {
+ switch(reason) {
+ case DozeLog.PULSE_REASON_SENSOR_PICKUP:
+ return getBoolean("doze.pulse.proxcheck.pickup", R.bool.doze_proximity_check_before_pulse);
+ case DozeLog.PULSE_REASON_INTENT:
+ return getBoolean("doze.pulse.proxcheck.intent", R.bool.doze_proximity_check_before_pulse_intent);
+ default:
+ return getBoolean("doze.pulse.proxcheck", R.bool.doze_proximity_check_before_pulse);
+ }
}
public boolean getPickupPerformsProxCheck() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java
index 3ff69c9..b3e0104 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java
@@ -115,7 +115,7 @@ public class DozeScrimController {
if (isPulsing()) {
final boolean pickup = mPulseReason == DozeLog.PULSE_REASON_SENSOR_PICKUP;
startScrimAnimation(true /* inFront */, 0f,
- mDozeParameters.getPulseInDuration(pickup),
+ mDozeParameters.getPulseInDuration(mPulseReason),
pickup ? mPulseInInterpolatorPickup : mPulseInInterpolator,
mPulseInFinished);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/IconMerger.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/IconMerger.java
index 50ead3d..5750372 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/IconMerger.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/IconMerger.java
@@ -22,12 +22,14 @@ import android.view.View;
import android.widget.LinearLayout;
import com.android.systemui.R;
+import com.android.systemui.statusbar.policy.Clock;
public class IconMerger extends LinearLayout {
private static final String TAG = "IconMerger";
private static final boolean DEBUG = false;
private int mIconSize;
+ private int mClockLocation;
private View mMoreView;
public IconMerger(Context context, AttributeSet attrs) {
@@ -50,6 +52,10 @@ public class IconMerger extends LinearLayout {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
// we need to constrain this to an integral multiple of our children
int width = getMeasuredWidth();
+ if (mClockLocation == ClockController.STYLE_CLOCK_CENTER) {
+ int totalWidth = getResources().getDisplayMetrics().widthPixels;
+ width = totalWidth / 2 - mIconSize * 2;
+ }
setMeasuredDimension(width - (width % mIconSize), getMeasuredHeight());
}
@@ -69,7 +75,14 @@ public class IconMerger extends LinearLayout {
}
final boolean overflowShown = (mMoreView.getVisibility() == View.VISIBLE);
// let's assume we have one more slot if the more icon is already showing
- if (overflowShown) visibleChildren --;
+ if (overflowShown) {
+ int totalWidth = getResources().getDisplayMetrics().widthPixels;
+ if ((mClockLocation != ClockController.STYLE_CLOCK_CENTER &&
+ mClockLocation != ClockController.STYLE_CLOCK_LEFT) ||
+ (visibleChildren > (totalWidth / mIconSize / 2 + 1))) {
+ visibleChildren--;
+ }
+ }
final boolean moreRequired = visibleChildren * mIconSize > width;
if (moreRequired != overflowShown) {
post(new Runnable() {
@@ -80,4 +93,9 @@ public class IconMerger extends LinearLayout {
});
}
}
+
+ public void setClockAndDateStatus(int mode) {
+ mClockLocation = mode;
+
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
index 14176a6..f79e051 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
@@ -29,6 +29,14 @@ import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.res.Configuration;
+import android.hardware.fingerprint.FingerprintManager;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.ColorMatrix;
+import android.graphics.ColorMatrixColorFilter;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.hardware.fingerprint.FingerprintManager;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.IBinder;
@@ -49,7 +57,6 @@ import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
import android.widget.FrameLayout;
import android.widget.TextView;
-
import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
@@ -57,6 +64,8 @@ import com.android.systemui.EventLogConstants;
import com.android.systemui.EventLogTags;
import com.android.systemui.R;
import com.android.systemui.assist.AssistManager;
+import com.android.systemui.cm.LockscreenShortcutsHelper;
+import com.android.systemui.cm.LockscreenShortcutsHelper.Shortcuts;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.KeyguardAffordanceView;
import com.android.systemui.statusbar.KeyguardIndicationController;
@@ -72,7 +81,7 @@ import static android.view.accessibility.AccessibilityNodeInfo.AccessibilityActi
* text.
*/
public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickListener,
- UnlockMethodCache.OnUnlockMethodChangedListener,
+ UnlockMethodCache.OnUnlockMethodChangedListener, LockscreenShortcutsHelper.OnChangeListener,
AccessibilityController.AccessibilityStateChangedCallback, View.OnLongClickListener {
final static String TAG = "PhoneStatusBar/KeyguardBottomAreaView";
@@ -110,6 +119,8 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
private KeyguardIndicationController mIndicationController;
private AccessibilityController mAccessibilityController;
private PhoneStatusBar mPhoneStatusBar;
+ private LockscreenShortcutsHelper mShortcutHelper;
+ private final ColorMatrixColorFilter mGrayScaleFilter;
private final Interpolator mLinearOutSlowInInterpolator;
private boolean mUserSetupComplete;
@@ -128,7 +139,6 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
}
};
- private boolean mLeftIsVoiceAssist;
private AssistManager mAssistManager;
public KeyguardBottomAreaView(Context context) {
@@ -148,6 +158,9 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
super(context, attrs, defStyleAttr, defStyleRes);
mLinearOutSlowInInterpolator =
AnimationUtils.loadInterpolator(context, android.R.interpolator.linear_out_slow_in);
+ ColorMatrix cm = new ColorMatrix();
+ cm.setSaturation(0);
+ mGrayScaleFilter = new ColorMatrixColorFilter(cm);
}
private AccessibilityDelegate mAccessibilityDelegate = new AccessibilityDelegate() {
@@ -158,12 +171,20 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
if (host == mLockIcon) {
label = getResources().getString(R.string.unlock_label);
} else if (host == mCameraImageView) {
- label = getResources().getString(R.string.camera_label);
+ if (isTargetCustom(Shortcuts.RIGHT_SHORTCUT)) {
+ label = mShortcutHelper.getFriendlyNameForUri(Shortcuts.RIGHT_SHORTCUT);
+ } else {
+ label = getResources().getString(R.string.camera_label);
+ }
} else if (host == mLeftAffordanceView) {
- if (mLeftIsVoiceAssist) {
- label = getResources().getString(R.string.voice_assist_label);
+ if (isTargetCustom(Shortcuts.LEFT_SHORTCUT)) {
+ label = mShortcutHelper.getFriendlyNameForUri(Shortcuts.LEFT_SHORTCUT);
} else {
- label = getResources().getString(R.string.phone_label);
+ if (isLeftVoiceAssist()) {
+ label = getResources().getString(R.string.voice_assist_label);
+ } else {
+ label = getResources().getString(R.string.phone_label);
+ }
}
}
info.addAction(new AccessibilityAction(ACTION_CLICK, label));
@@ -197,6 +218,7 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
mLeftAffordanceView = (KeyguardAffordanceView) findViewById(R.id.left_button);
mLockIcon = (LockIcon) findViewById(R.id.lock_icon);
mIndicationText = (TextView) findViewById(R.id.keyguard_indication_text);
+ mShortcutHelper = new LockscreenShortcutsHelper(mContext, this);
watchForCameraPolicyChanges();
updateCameraVisibility();
mUnlockMethodCache = UnlockMethodCache.getInstance(getContext());
@@ -205,12 +227,36 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
setClipChildren(false);
setClipToPadding(false);
mPreviewInflater = new PreviewInflater(mContext, new LockPatternUtils(mContext));
- inflateCameraPreview();
mLockIcon.setOnClickListener(this);
mLockIcon.setOnLongClickListener(this);
mCameraImageView.setOnClickListener(this);
mLeftAffordanceView.setOnClickListener(this);
initAccessibility();
+ updateCustomShortcuts();
+ }
+
+ private void updateCustomShortcuts() {
+ updateLeftAffordanceIcon();
+ updateRightAffordanceIcon();
+ inflateCameraPreview();
+ }
+
+ private void updateRightAffordanceIcon() {
+ Drawable drawable;
+ String contentDescription;
+ boolean shouldGrayScale = false;
+ if (isTargetCustom(Shortcuts.RIGHT_SHORTCUT)) {
+ drawable = mShortcutHelper.getDrawableForTarget(Shortcuts.RIGHT_SHORTCUT);
+ shouldGrayScale = true;
+ contentDescription = mShortcutHelper.getFriendlyNameForUri(Shortcuts.RIGHT_SHORTCUT);
+ } else {
+ drawable = mContext.getDrawable(R.drawable.ic_camera_alt_24dp);
+ contentDescription = mContext.getString(R.string.accessibility_camera_button);
+ }
+ mCameraImageView.setImageDrawable(drawable);
+ mCameraImageView.setContentDescription(contentDescription);
+ mCameraImageView.setDefaultFilter(shouldGrayScale ? mGrayScaleFilter : null);
+ updateCameraVisibility();
}
private void initAccessibility() {
@@ -283,33 +329,45 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
// Things are not set up yet; reply hazy, ask again later
return;
}
- ResolveInfo resolved = resolveCameraIntent();
- boolean visible = !isCameraDisabledByDpm() && resolved != null
- && getResources().getBoolean(R.bool.config_keyguardShowCameraAffordance)
- && mUserSetupComplete;
+ boolean visible = mUserSetupComplete;
+ if (visible) {
+ if (isTargetCustom(Shortcuts.RIGHT_SHORTCUT)) {
+ visible = !mShortcutHelper.isTargetEmpty(Shortcuts.RIGHT_SHORTCUT);
+ } else {
+ ResolveInfo resolved = resolveCameraIntent();
+ visible = !isCameraDisabledByDpm() && resolved != null
+ && getResources().getBoolean(R.bool.config_keyguardShowCameraAffordance);
+ }
+ }
mCameraImageView.setVisibility(visible ? View.VISIBLE : View.GONE);
}
private void updateLeftAffordanceIcon() {
- mLeftIsVoiceAssist = canLaunchVoiceAssist();
- int drawableId;
- int contentDescription;
+ Drawable drawable;
+ String contentDescription;
+ boolean shouldGrayScale = false;
boolean visible = mUserSetupComplete;
- if (mLeftIsVoiceAssist) {
- drawableId = R.drawable.ic_mic_26dp;
- contentDescription = R.string.accessibility_voice_assist_button;
+ if (mShortcutHelper.isTargetCustom(Shortcuts.LEFT_SHORTCUT)) {
+ drawable = mShortcutHelper.getDrawableForTarget(Shortcuts.LEFT_SHORTCUT);
+ shouldGrayScale = true;
+ contentDescription = mShortcutHelper.getFriendlyNameForUri(Shortcuts.LEFT_SHORTCUT);
+ visible |= !mShortcutHelper.isTargetEmpty(Shortcuts.LEFT_SHORTCUT);
+ } else if (canLaunchVoiceAssist()) {
+ drawable = mContext.getDrawable(R.drawable.ic_mic_26dp);
+ contentDescription = mContext.getString(R.string.accessibility_voice_assist_button);
} else {
visible &= isPhoneVisible();
- drawableId = R.drawable.ic_phone_24dp;
- contentDescription = R.string.accessibility_phone_button;
+ drawable = mContext.getDrawable(R.drawable.ic_phone_24dp);
+ contentDescription = mContext.getString(R.string.accessibility_phone_button);
}
mLeftAffordanceView.setVisibility(visible ? View.VISIBLE : View.GONE);
- mLeftAffordanceView.setImageDrawable(mContext.getDrawable(drawableId));
- mLeftAffordanceView.setContentDescription(mContext.getString(contentDescription));
+ mLeftAffordanceView.setImageDrawable(drawable);
+ mLeftAffordanceView.setContentDescription(contentDescription);
+ mLeftAffordanceView.setDefaultFilter(shouldGrayScale ? mGrayScaleFilter : null);
}
public boolean isLeftVoiceAssist() {
- return mLeftIsVoiceAssist;
+ return !isTargetCustom(Shortcuts.LEFT_SHORTCUT) && canLaunchVoiceAssist();
}
private boolean isPhoneVisible() {
@@ -425,8 +483,13 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
}
public void launchCamera(String source) {
- final Intent intent = getCameraIntent();
- intent.putExtra(EXTRA_CAMERA_LAUNCH_SOURCE, source);
+ final Intent intent;
+ if (!mShortcutHelper.isTargetCustom(LockscreenShortcutsHelper.Shortcuts.RIGHT_SHORTCUT)) {
+ intent = getCameraIntent();
+ } else {
+ intent = mShortcutHelper.getIntent(LockscreenShortcutsHelper.Shortcuts.RIGHT_SHORTCUT);
+ intent.putExtra(EXTRA_CAMERA_LAUNCH_SOURCE, source);
+ }
boolean wouldLaunchResolverActivity = PreviewInflater.wouldLaunchResolverActivity(
mContext, intent, KeyguardUpdateMonitor.getCurrentUser());
if (intent == SECURE_CAMERA_INTENT && !wouldLaunchResolverActivity) {
@@ -475,7 +538,10 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
}
public void launchLeftAffordance() {
- if (mLeftIsVoiceAssist) {
+ if (mShortcutHelper.isTargetCustom(Shortcuts.LEFT_SHORTCUT)) {
+ Intent intent = mShortcutHelper.getIntent(Shortcuts.LEFT_SHORTCUT);
+ mActivityStarter.startActivity(intent, false /* dismissShade */);
+ } else if (isLeftVoiceAssist()) {
launchVoiceAssist();
} else {
launchPhone();
@@ -499,6 +565,9 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
}
private boolean canLaunchVoiceAssist() {
+ if (mAssistManager == null) {
+ return false;
+ }
return mAssistManager.canVoiceAssistBeLaunchedFromKeyguard();
}
@@ -562,10 +631,14 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
}
private void inflateCameraPreview() {
- mCameraPreview = mPreviewInflater.inflatePreview(getCameraIntent());
- if (mCameraPreview != null) {
- mPreviewContainer.addView(mCameraPreview);
- mCameraPreview.setVisibility(View.INVISIBLE);
+ if (isTargetCustom(Shortcuts.RIGHT_SHORTCUT)) {
+ mPreviewContainer.removeView(mCameraPreview);
+ } else {
+ mCameraPreview = mPreviewInflater.inflatePreview(getCameraIntent());
+ if (mCameraPreview != null) {
+ mPreviewContainer.addView(mCameraPreview);
+ mCameraPreview.setVisibility(View.INVISIBLE);
+ }
}
}
@@ -574,7 +647,11 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
if (previewBefore != null) {
mPreviewContainer.removeView(previewBefore);
}
- if (mLeftIsVoiceAssist) {
+ if (isTargetCustom(Shortcuts.LEFT_SHORTCUT)) {
+ // Custom shortcuts don't support previews
+ return;
+ }
+ if (isLeftVoiceAssist()) {
mLeftPreview = mPreviewInflater.inflatePreviewFromService(
mAssistManager.getVoiceInteractorComponentName());
} else {
@@ -684,4 +761,52 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
updateLeftAffordanceIcon();
updateLeftPreview();
}
+
+ private String getIndexHint(LockscreenShortcutsHelper.Shortcuts shortcut) {
+ if (mShortcutHelper.isTargetCustom(shortcut)) {
+ boolean isRtl = getLayoutDirection() == LAYOUT_DIRECTION_RTL;
+ String label = mShortcutHelper.getFriendlyNameForUri(shortcut);
+ int resId = 0;
+ switch (shortcut) {
+ case LEFT_SHORTCUT:
+ resId = isRtl ? R.string.right_shortcut_hint : R.string.left_shortcut_hint;
+ break;
+ case RIGHT_SHORTCUT:
+ resId = isRtl ? R.string.left_shortcut_hint : R.string.right_shortcut_hint;
+ break;
+ }
+ return mContext.getString(resId, label);
+ } else {
+ return null;
+ }
+ }
+
+ public String getLeftHint() {
+ String label = getIndexHint(LockscreenShortcutsHelper.Shortcuts.LEFT_SHORTCUT);
+ if (label == null) {
+ if (isLeftVoiceAssist()) {
+ label = mContext.getString(R.string.voice_hint);
+ } else {
+ label = mContext.getString(R.string.phone_hint);
+ }
+ }
+ return label;
+ }
+
+ public String getRightHint() {
+ String label = getIndexHint(LockscreenShortcutsHelper.Shortcuts.RIGHT_SHORTCUT);
+ if (label == null) {
+ label = mContext.getString(R.string.camera_hint);
+ }
+ return label;
+ }
+
+ public boolean isTargetCustom(LockscreenShortcutsHelper.Shortcuts shortcut) {
+ return mShortcutHelper.isTargetCustom(shortcut);
+ }
+
+ @Override
+ public void onChange() {
+ updateCustomShortcuts();
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
index 893b352..395f350 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
@@ -195,7 +195,7 @@ public class KeyguardBouncer {
mRoot.setSystemUiVisibility(View.STATUS_BAR_DISABLE_HOME);
}
- private void removeView() {
+ void removeView() {
if (mRoot != null && mRoot.getParent() == mContainer) {
mContainer.removeView(mRoot);
mRoot = null;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
index b93fc76..db378d1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
@@ -29,6 +29,7 @@ import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
+import com.android.systemui.BatteryLevelTextView;
import com.android.systemui.BatteryMeterView;
import com.android.systemui.R;
import com.android.systemui.statusbar.policy.BatteryController;
@@ -36,23 +37,18 @@ import com.android.systemui.statusbar.policy.KeyguardUserSwitcher;
import com.android.systemui.statusbar.policy.UserInfoController;
import com.android.systemui.statusbar.policy.UserSwitcherController;
-import java.text.NumberFormat;
-
/**
* The header group on Keyguard.
*/
-public class KeyguardStatusBarView extends RelativeLayout
- implements BatteryController.BatteryStateChangeCallback {
+public class KeyguardStatusBarView extends RelativeLayout {
- private boolean mBatteryCharging;
private boolean mKeyguardUserSwitcherShowing;
- private boolean mBatteryListening;
private TextView mCarrierLabel;
private View mSystemIconsSuperContainer;
private MultiUserSwitch mMultiUserSwitch;
private ImageView mMultiUserAvatar;
- private TextView mBatteryLevel;
+ private BatteryLevelTextView mBatteryLevel;
private BatteryController mBatteryController;
private KeyguardUserSwitcher mKeyguardUserSwitcher;
@@ -70,12 +66,13 @@ public class KeyguardStatusBarView extends RelativeLayout
mSystemIconsSuperContainer = findViewById(R.id.system_icons_super_container);
mMultiUserSwitch = (MultiUserSwitch) findViewById(R.id.multi_user_switch);
mMultiUserAvatar = (ImageView) findViewById(R.id.multi_user_avatar);
- mBatteryLevel = (TextView) findViewById(R.id.battery_level);
+ mBatteryLevel = (BatteryLevelTextView) findViewById(R.id.battery_level_text);
mCarrierLabel = (TextView) findViewById(R.id.keyguard_carrier_text);
loadDimens();
mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(getContext(),
android.R.interpolator.fast_out_slow_in);
updateUserSwitcher();
+ updateVisibilities();
}
@Override
@@ -86,8 +83,6 @@ public class KeyguardStatusBarView extends RelativeLayout
mCarrierLabel.setTextSize(TypedValue.COMPLEX_UNIT_PX,
getResources().getDimensionPixelSize(
com.android.internal.R.dimen.text_size_small_material));
- mBatteryLevel.setTextSize(TypedValue.COMPLEX_UNIT_PX,
- getResources().getDimensionPixelSize(R.dimen.battery_level_text_size));
}
private void loadDimens() {
@@ -104,7 +99,7 @@ public class KeyguardStatusBarView extends RelativeLayout
} else if (mMultiUserSwitch.getParent() == this && mKeyguardUserSwitcherShowing) {
removeView(mMultiUserSwitch);
}
- mBatteryLevel.setVisibility(mBatteryCharging ? View.VISIBLE : View.GONE);
+ mBatteryLevel.setVisibility(View.VISIBLE);
}
private void updateSystemIconsLayoutParams() {
@@ -117,18 +112,6 @@ public class KeyguardStatusBarView extends RelativeLayout
}
}
- public void setListening(boolean listening) {
- if (listening == mBatteryListening) {
- return;
- }
- mBatteryListening = listening;
- if (mBatteryListening) {
- mBatteryController.addStateChangedCallback(this);
- } else {
- mBatteryController.removeStateChangedCallback(this);
- }
- }
-
private void updateUserSwitcher() {
boolean keyguardSwitcherAvailable = mKeyguardUserSwitcher != null;
mMultiUserSwitch.setClickable(keyguardSwitcherAvailable);
@@ -139,6 +122,7 @@ public class KeyguardStatusBarView extends RelativeLayout
public void setBatteryController(BatteryController batteryController) {
mBatteryController = batteryController;
((BatteryMeterView) findViewById(R.id.battery)).setBatteryController(batteryController);
+ mBatteryLevel.setBatteryController(batteryController);
}
public void setUserSwitcherController(UserSwitcherController controller) {
@@ -154,22 +138,6 @@ public class KeyguardStatusBarView extends RelativeLayout
});
}
- @Override
- public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) {
- String percentage = NumberFormat.getPercentInstance().format((double) level / 100.0);
- mBatteryLevel.setText(percentage);
- boolean changed = mBatteryCharging != charging;
- mBatteryCharging = charging;
- if (changed) {
- updateVisibilities();
- }
- }
-
- @Override
- public void onPowerSaveChanged() {
- // could not care less
- }
-
public void setKeyguardUserSwitcher(KeyguardUserSwitcher keyguardUserSwitcher) {
mKeyguardUserSwitcher = keyguardUserSwitcher;
mMultiUserSwitch.setKeyguardUserSwitcher(keyguardUserSwitcher);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java
index e70d146..3287f8f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java
@@ -43,6 +43,7 @@ public class MultiUserSwitch extends FrameLayout implements View.OnClickListener
private UserSwitcherController.BaseUserAdapter mUserListener;
final UserManager mUserManager;
+ private ActivityStarter mActivityStarter;
private final int[] mTmpInt2 = new int[2];
@@ -101,6 +102,10 @@ public class MultiUserSwitch extends FrameLayout implements View.OnClickListener
}
}
+ public void setActivityStarter(ActivityStarter activityStarter) {
+ mActivityStarter = activityStarter;
+ }
+
@Override
public void onClick(View v) {
if (UserSwitcherController.isUserSwitcherAvailable(mUserManager)) {
@@ -123,7 +128,11 @@ public class MultiUserSwitch extends FrameLayout implements View.OnClickListener
Intent intent = ContactsContract.QuickContact.composeQuickContactsIntent(
getContext(), v, ContactsContract.Profile.CONTENT_URI,
ContactsContract.QuickContact.MODE_LARGE, null);
- getContext().startActivityAsUser(intent, new UserHandle(UserHandle.USER_CURRENT));
+ if (mActivityStarter != null) {
+ mActivityStarter.startActivity(intent, true /* dismissShade */);
+ } else {
+ getContext().startActivityAsUser(intent, new UserHandle(UserHandle.USER_CURRENT));
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavbarEditor.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavbarEditor.java
new file mode 100644
index 0000000..87f0e8c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavbarEditor.java
@@ -0,0 +1,565 @@
+/*
+ * Copyright (C) 2015 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 com.android.systemui.statusbar.phone;
+
+import android.app.AlertDialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffColorFilter;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.util.DisplayMetrics;
+import android.view.DisplayInfo;
+import android.view.HapticFeedbackConstants;
+import android.view.KeyEvent;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewConfiguration;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.widget.ArrayAdapter;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import com.android.internal.util.ArrayUtils;
+import com.android.systemui.R;
+import com.android.systemui.statusbar.policy.KeyButtonView;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import cyanogenmod.providers.CMSettings;
+
+/**
+ * Handles the editing of the navigation bar
+ * @author Danesh M
+ * @hide
+ */
+public class NavbarEditor implements View.OnTouchListener {
+ /**
+ * Holds reference to all assignable button ids
+ */
+ private static final int[] BUTTON_IDS =
+ { R.id.one, R.id.two, R.id.three, R.id.four, R.id.five, R.id.six };
+
+ /**
+ * Subset of BUTTON_IDS, to differentiate small/side buttons
+ * since they can be assigned additional functionality.
+ */
+ private static final int[] SMALL_BUTTON_IDS = { R.id.one, R.id.six };
+
+ // holds the button views in the order they currently appear on screen
+ private final ArrayList<KeyButtonView> mButtonViews;
+ private final boolean mRtl;
+
+ private Context mContext;
+ private static Boolean sIsDevicePhone = null;
+ private boolean mInEditMode = false;
+
+ // Holds reference to the parent/root of the inflated view
+ private View mParent;
+
+ // Button chooser dialog
+ private AlertDialog mDialog;
+
+ // true == we're in landscape mode
+ private boolean mVertical;
+ // true == we're currently checking for long press
+ private boolean mLongPressed;
+ // start point of the current drag operation
+ private float mDragOrigin;
+
+ // just to avoid reallocations
+ private static final int[] sLocation = new int[2];
+
+ /**
+ * Longpress runnable to assign buttons in edit mode
+ */
+ private Runnable mCheckLongPress = new Runnable() {
+ public void run() {
+ if (mInEditMode) {
+ mLongPressed = true;
+ mParent.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY);
+ }
+ }
+ };
+
+ //Available buttons
+ public static final ButtonInfo NAVBAR_EMPTY = new ButtonInfo("empty",
+ R.string.navbar_empty_button, R.string.accessibility_clear_all,
+ 0, R.drawable.ic_sysbar_add,
+ R.drawable.ic_sysbar_add_land, R.drawable.ic_sysbar_add_side);
+ public static final ButtonInfo NAVBAR_HOME = new ButtonInfo("home",
+ R.string.navbar_home_button, R.string.accessibility_home,
+ KeyEvent.KEYCODE_HOME, R.drawable.ic_sysbar_home,
+ R.drawable.ic_sysbar_home, R.drawable.ic_sysbar_home);
+ public static final ButtonInfo NAVBAR_BACK = new ButtonInfo("back",
+ R.string.navbar_back_button, R.string.accessibility_back,
+ KeyEvent.KEYCODE_BACK, R.drawable.ic_sysbar_back,
+ R.drawable.ic_sysbar_back, R.drawable.ic_sysbar_back_side);
+ public static final ButtonInfo NAVBAR_SEARCH = new ButtonInfo("search",
+ R.string.navbar_search_button, R.string.accessibility_back,
+ KeyEvent.KEYCODE_SEARCH, R.drawable.ic_sysbar_search,
+ R.drawable.ic_sysbar_search_land, R.drawable.ic_sysbar_search_side);
+ public static final ButtonInfo NAVBAR_RECENT = new ButtonInfo("recent",
+ R.string.navbar_recent_button, R.string.accessibility_recent,
+ 0, R.drawable.ic_sysbar_recent,
+ R.drawable.ic_sysbar_recent, R.drawable.ic_sysbar_recent_side);
+ public static final ButtonInfo NAVBAR_CONDITIONAL_MENU = new ButtonInfo("menu0",
+ R.string.navbar_menu_conditional_button, R.string.accessibility_menu,
+ KeyEvent.KEYCODE_MENU, R.drawable.ic_sysbar_menu,
+ R.drawable.ic_sysbar_menu, R.drawable.ic_sysbar_menu);
+ public static final ButtonInfo NAVBAR_ALWAYS_MENU = new ButtonInfo("menu1",
+ R.string.navbar_menu_always_button, R.string.accessibility_menu,
+ KeyEvent.KEYCODE_MENU, R.drawable.ic_sysbar_menu,
+ R.drawable.ic_sysbar_menu, R.drawable.ic_sysbar_menu);
+ public static final ButtonInfo NAVBAR_MENU_BIG = new ButtonInfo("menu2",
+ R.string.navbar_menu_big_button, R.string.accessibility_menu,
+ KeyEvent.KEYCODE_MENU, R.drawable.ic_sysbar_menu_big,
+ R.drawable.ic_sysbar_menu_big_land, 0);
+ public static final ButtonInfo NAVBAR_DPAD_LEFT = new ButtonInfo("dpad_left",
+ 0, R.string.accessibility_dpad_left,
+ KeyEvent.KEYCODE_DPAD_LEFT, 0,
+ 0, R.drawable.ic_sysbar_ime_left);
+ public static final ButtonInfo NAVBAR_DPAD_RIGHT = new ButtonInfo("dpad_right",
+ 0, R.string.accessibility_dpad_right,
+ KeyEvent.KEYCODE_DPAD_RIGHT, 0,
+ 0, R.drawable.ic_sysbar_ime_right);
+
+ private static final ButtonInfo[] ALL_BUTTONS = new ButtonInfo[] {
+ NAVBAR_EMPTY, NAVBAR_HOME, NAVBAR_BACK, NAVBAR_SEARCH,
+ NAVBAR_RECENT, NAVBAR_CONDITIONAL_MENU, NAVBAR_ALWAYS_MENU, NAVBAR_MENU_BIG
+ };
+
+ private static final String DEFAULT_SETTING_STRING = "empty|back|home|recent|empty|menu0";
+
+ public NavbarEditor (View parent, boolean orientation, boolean isRtl) {
+ mContext = parent.getContext();
+ mParent = parent;
+ mVertical = orientation;
+ mRtl = isRtl;
+
+ mButtonViews = new ArrayList<KeyButtonView>();
+
+ KeyButtonView dpadLeft = (KeyButtonView) mParent.findViewById(R.id.dpad_left);
+ dpadLeft.setInfo(NAVBAR_DPAD_LEFT, orientation, true);
+ mButtonViews.add(dpadLeft);
+
+ for (int id : BUTTON_IDS) {
+ mButtonViews.add((KeyButtonView) mParent.findViewById(id));
+ }
+
+ KeyButtonView dpadRight = (KeyButtonView) mParent.findViewById(R.id.dpad_right);
+ dpadRight.setInfo(NAVBAR_DPAD_RIGHT, orientation, true);
+ mButtonViews.add(dpadRight);
+ }
+
+ public void setEditMode(boolean editMode) {
+ mInEditMode = editMode;
+ for (Integer id : BUTTON_IDS) {
+ KeyButtonView button = (KeyButtonView) mParent.findViewById(id);
+ if (button != null) {
+ button.setEditMode(editMode);
+ button.setOnTouchListener(editMode ? this : null);
+ }
+ }
+ if (!editMode && mDialog != null && mDialog.isShowing()) {
+ mDialog.dismiss();
+ }
+ }
+
+ public static boolean isDevicePhone(Context context) {
+ if (sIsDevicePhone == null) {
+ WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
+ DisplayInfo outDisplayInfo = new DisplayInfo();
+
+ wm.getDefaultDisplay().getDisplayInfo(outDisplayInfo);
+
+ int shortSize = Math.min(outDisplayInfo.logicalHeight, outDisplayInfo.logicalWidth);
+ int shortSizeDp = shortSize * DisplayMetrics.DENSITY_DEFAULT / outDisplayInfo.logicalDensityDpi;
+
+ // 0-599dp: "phone" UI with a separate status & navigation bar
+ sIsDevicePhone = shortSizeDp < 600;
+ }
+
+ return sIsDevicePhone;
+ }
+
+ /**
+ * Find intersecting view in mButtonViews
+ * @param pos - pointer location
+ * @param v - view being dragged
+ * @return intersecting view or null
+ */
+ private View findInterceptingView(float pos, View v) {
+ for (KeyButtonView otherView : mButtonViews) {
+ if (otherView == v) {
+ continue;
+ }
+
+ if (ArrayUtils.contains(SMALL_BUTTON_IDS, otherView.getId())) {
+ continue;
+ }
+
+ otherView.getLocationOnScreen(sLocation);
+ float otherPos = sLocation[mVertical ? 1 : 0];
+ float otherDimension = mVertical ? v.getHeight() : v.getWidth();
+
+ if (pos > (otherPos + otherDimension / 4) && pos < (otherPos + otherDimension)) {
+ return otherView;
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public boolean onTouch(final View view, MotionEvent event) {
+ if (!mInEditMode || (mDialog != null && mDialog.isShowing())) {
+ return false;
+ }
+
+ if (event.getAction() == MotionEvent.ACTION_DOWN) {
+ view.setPressed(true);
+ view.getLocationOnScreen(sLocation);
+ mDragOrigin = sLocation[mVertical ? 1 : 0];
+ view.postDelayed(mCheckLongPress, ViewConfiguration.getLongPressTimeout());
+ } else if (event.getAction() == MotionEvent.ACTION_MOVE) {
+ view.setPressed(false);
+
+ if (!mLongPressed || ArrayUtils.contains(SMALL_BUTTON_IDS, view.getId())) {
+ return false;
+ }
+
+ ViewGroup viewParent = (ViewGroup) view.getParent();
+ float pos = mVertical ? event.getRawY() : event.getRawX();
+ float buttonSize = mVertical ? view.getHeight() : view.getWidth();
+ float min = mVertical ? viewParent.getTop() : (viewParent.getLeft() - buttonSize / 2);
+ float max = mVertical ? (viewParent.getTop() + viewParent.getHeight())
+ : (viewParent.getLeft() + viewParent.getWidth());
+
+ // Prevents user from dragging view outside of bounds
+ if (pos < min || pos > max) {
+ return false;
+ }
+ if (!mVertical) {
+ view.setX(pos - viewParent.getLeft() - buttonSize / 2);
+ } else {
+ view.setY(pos - viewParent.getTop() - buttonSize / 2);
+ }
+ View affectedView = findInterceptingView(pos, view);
+ if (affectedView == null) {
+ return false;
+ }
+ switchId(affectedView, view);
+ } else if (event.getAction() == MotionEvent.ACTION_UP
+ || event.getAction() == MotionEvent.ACTION_CANCEL) {
+ view.setPressed(false);
+ view.removeCallbacks(mCheckLongPress);
+
+ if (!mLongPressed && !view.getTag().equals(NAVBAR_HOME) &&
+ !view.getTag().equals(NAVBAR_RECENT) && !view.getTag().equals(NAVBAR_BACK)) {
+ final boolean isSmallButton = ArrayUtils.contains(SMALL_BUTTON_IDS, view.getId());
+ final ButtonAdapter list = new ButtonAdapter(mContext, mButtonViews, isSmallButton);
+
+ AlertDialog.Builder builder = new AlertDialog.Builder(mContext)
+ .setTitle(mContext.getString(R.string.navbar_dialog_title))
+ .setAdapter(list, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ KeyButtonView button = (KeyButtonView) view;
+ ButtonInfo info = list.getItem(which);
+
+ button.setInfo(info, mVertical, isSmallButton);
+ }
+ })
+ .setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int id) {
+ dialog.cancel();
+ }
+ });
+
+ mDialog = builder.create();
+ mDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG);
+ mDialog.setCanceledOnTouchOutside(false);
+ mDialog.show();
+ } else {
+ // Reset the dragged view to its original location
+ ViewGroup parent = (ViewGroup) view.getParent();
+
+ if (!mVertical) {
+ view.setX(mDragOrigin - parent.getLeft());
+ } else {
+ view.setY(mDragOrigin - parent.getTop());
+ }
+ }
+ mLongPressed = false;
+ }
+ return true;
+ }
+
+ /**
+ * Switches positions of two views and
+ * updates their mButtonViews entry
+ * @param targetView - view to be replaced
+ * @param view - view being dragged
+ */
+ private void switchId(View targetView, View view) {
+ ViewGroup parent = (ViewGroup) view.getParent();
+
+ targetView.getLocationOnScreen(sLocation);
+ if (!mVertical) {
+ targetView.setX(mDragOrigin - parent.getLeft());
+ mDragOrigin = sLocation[0];
+ } else {
+ targetView.setY(mDragOrigin - parent.getTop());
+ mDragOrigin = sLocation[1];
+ }
+
+ int targetIndex = mButtonViews.indexOf(targetView);
+ int draggedIndex = mButtonViews.indexOf(view);
+ Collections.swap(mButtonViews, draggedIndex, targetIndex);
+ }
+
+ /**
+ * Saves the current key arrangement
+ * to the settings provider
+ */
+ protected void saveKeys() {
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < BUTTON_IDS.length; i++) {
+ int idIndex = mVertical && !mRtl ? BUTTON_IDS.length - (i + 1) : i;
+ ButtonInfo info = (ButtonInfo) mButtonViews.get(idIndex).getTag();
+ if (i != 0) sb.append("|");
+ sb.append(info.key);
+ }
+ CMSettings.System.putStringForUser(mContext.getContentResolver(),
+ CMSettings.System.NAV_BUTTONS, sb.toString(), UserHandle.USER_CURRENT);
+ }
+
+ /**
+ * Updates the buttons according to the
+ * key arrangement stored in settings provider
+ */
+ protected void updateKeys() {
+ String saved = CMSettings.System.getStringForUser(mContext.getContentResolver(),
+ CMSettings.System.NAV_BUTTONS, UserHandle.USER_CURRENT);
+ if (saved == null) {
+ saved = DEFAULT_SETTING_STRING;
+ }
+
+ String[] buttons = saved.split("\\|");
+ if (buttons.length < BUTTON_IDS.length) {
+ buttons = DEFAULT_SETTING_STRING.split("\\|");
+ }
+
+ int visibleCount = 0;
+
+ for (int i = 0; i < BUTTON_IDS.length; i++) {
+ int id = BUTTON_IDS[i];
+ int index = mVertical && !mRtl ? BUTTON_IDS.length - i - 1 : i;
+ String key = index < buttons.length ? buttons[index] : null;
+ KeyButtonView buttonView = (KeyButtonView) mParent.findViewById(id);
+ boolean isSmallButton = ArrayUtils.contains(SMALL_BUTTON_IDS, id);
+ ButtonInfo button = NAVBAR_EMPTY;
+
+ for (ButtonInfo info : ALL_BUTTONS) {
+ if (info.key.equals(key)) {
+ button = info;
+ break;
+ }
+ }
+
+ buttonView.setInfo(button, mVertical, isSmallButton);
+ if (button != NAVBAR_EMPTY && !isSmallButton) {
+ visibleCount++;
+ }
+
+ buttonView.setTranslationX(0);
+ mButtonViews.set(i, buttonView);
+ }
+
+ if (isDevicePhone(mContext)) {
+ adjustPadding(visibleCount);
+ }
+ updateLowLights(visibleCount);
+ }
+
+ /**
+ * Accommodates the padding between keys based on
+ * number of keys in use.
+ */
+ private void adjustPadding(int visibleCount) {
+ ViewGroup viewParent = (ViewGroup) mParent.findViewById(R.id.mid_nav_buttons);
+ int totalViews = viewParent.getChildCount();
+
+ for (int v = 0; v < totalViews; v++) {
+ View currentKey = viewParent.getChildAt(v);
+ if (!(currentKey instanceof KeyButtonView)) {
+ continue;
+ }
+ View nextPadding = viewParent.getChildAt(v + 1);
+ if (nextPadding == null) {
+ continue;
+ }
+
+ View nextKey = viewParent.getChildAt(v + 2);
+ ButtonInfo nextInfo = nextKey == null ? null : (ButtonInfo) nextKey.getTag();
+ ButtonInfo currentInfo = (ButtonInfo) currentKey.getTag();
+
+ if (nextInfo != null && currentInfo != null && currentInfo != NAVBAR_EMPTY) {
+ if (nextInfo != NAVBAR_EMPTY || visibleCount > 1) {
+ nextPadding.setVisibility(View.VISIBLE);
+ } else {
+ nextPadding.setVisibility(View.GONE);
+ }
+ visibleCount--;
+ } else {
+ nextPadding.setVisibility(View.GONE);
+ }
+ }
+ }
+
+ protected void updateLowLights(int visibleCount) {
+ ViewGroup lowLights = (ViewGroup) mParent.findViewById(R.id.lights_out);
+ int totalViews = lowLights.getChildCount();
+
+ for (int v = 0;v < totalViews; v++) {
+ View currentView = lowLights.getChildAt(v);
+ if (!(currentView instanceof ImageView)) {
+ continue;
+ }
+
+ if (visibleCount <= 0) {
+ currentView.setVisibility(View.GONE);
+ } else {
+ currentView.setVisibility(View.VISIBLE);
+ visibleCount--;
+ }
+
+ View blank = lowLights.getChildAt(v + 1);
+ if (blank != null) {
+ blank.setVisibility(visibleCount > 0 ? View.VISIBLE : View.GONE);
+ }
+ }
+ }
+
+ /**
+ * Class to store info about supported buttons
+ */
+ public static final class ButtonInfo {
+ private final String key;
+ public int displayId;
+ public int contentDescription;
+ public int keyCode;
+ public int portResource;
+ public int landResource;
+ public int sideResource;
+ /**
+ * Constructor for new button type
+ * @param key - the internal key of the button
+ * @param rId - resource id of text shown to user in choose dialog
+ * @param cD - accessibility information regarding button
+ * @param mC - keyCode to execute on button press
+ * @param pR - portrait resource used to display button
+ * @param lR - landscape resource used to display button
+ * @param sR - smaller scaled resource for side buttons
+ */
+ ButtonInfo (String key, int rId, int cD, int mC, int pR, int lR, int sR) {
+ this.key = key;
+ displayId = rId;
+ contentDescription = cD;
+ keyCode = mC;
+ portResource = pR;
+ landResource = lR;
+ sideResource = sR;
+ }
+
+ @Override
+ public String toString() {
+ return "ButtonInfo[" + key + "]";
+ }
+ }
+
+ private static class ButtonAdapter extends ArrayAdapter<ButtonInfo> {
+ private ArrayList<ButtonInfo> mTakenItems;
+
+ public ButtonAdapter(Context context,
+ ArrayList<KeyButtonView> buttons, boolean smallButtons) {
+ super(context, R.layout.navigation_bar_edit_menu_item, R.id.key_text,
+ buildItems(smallButtons));
+
+ mTakenItems = new ArrayList<ButtonInfo>();
+ for (KeyButtonView button : buttons) {
+ ButtonInfo info = (ButtonInfo) button.getTag();
+ if (info != null && info != NAVBAR_EMPTY) {
+ mTakenItems.add(info);
+ }
+ }
+ }
+
+ private static List<ButtonInfo> buildItems(boolean smallButtons) {
+ List<ButtonInfo> items = new ArrayList<ButtonInfo>(Arrays.asList(ALL_BUTTONS));
+
+ // Not re-assignable
+ items.remove(NAVBAR_HOME);
+ items.remove(NAVBAR_RECENT);
+ items.remove(NAVBAR_BACK);
+ // menu buttons can only be assigned to side buttons
+ if (!smallButtons) {
+ items.remove(NAVBAR_CONDITIONAL_MENU);
+ items.remove(NAVBAR_ALWAYS_MENU);
+ } else {
+ items.remove(NAVBAR_MENU_BIG);
+ }
+
+ return items;
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ View view = super.getView(position, convertView, parent);
+ ButtonInfo info = getItem(position);
+ boolean enabled = isEnabled(position);
+
+ TextView text = (TextView) view.findViewById(R.id.key_text);
+ text.setText(getContext().getResources().getString(info.displayId));
+ text.setEnabled(enabled);
+
+ ImageView icon = (ImageView) view.findViewById(R.id.key_icon);
+ icon.setImageResource(info.portResource);
+ icon.setColorFilter(new PorterDuffColorFilter(
+ text.getCurrentTextColor(), PorterDuff.Mode.SRC_IN));
+
+ return view;
+ }
+
+ @Override
+ public boolean areAllItemsEnabled() {
+ return true;
+ }
+
+ @Override
+ public boolean isEnabled(int position) {
+ return !mTakenItems.contains(getItem(position));
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java
index 134c579..50656ed 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java
@@ -35,7 +35,10 @@ public final class NavigationBarTransitions extends BarTransitions {
private boolean mLightsOut;
public NavigationBarTransitions(NavigationBarView view) {
- super(view, R.drawable.nav_background);
+ super(view, R.drawable.nav_background, R.color.navigation_bar_background_opaque,
+ R.color.navigation_bar_background_semi_transparent,
+ R.color.navigation_bar_background_transparent,
+ com.android.internal.R.color.battery_saver_mode_color);
mView = view;
mBarService = IStatusBarService.Stub.asInterface(
ServiceManager.getService(Context.STATUS_BAR_SERVICE));
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index 8046eb5..1262f26 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -23,15 +23,22 @@ import android.animation.TimeInterpolator;
import android.animation.ValueAnimator;
import android.app.ActivityManagerNative;
import android.app.StatusBarManager;
+import android.content.BroadcastReceiver;
+import android.content.ContentResolver;
import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
import android.content.res.Configuration;
import android.content.res.Resources;
+import android.database.ContentObserver;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.Message;
import android.os.RemoteException;
+import android.os.UserHandle;
+import android.provider.Settings;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Display;
@@ -48,6 +55,7 @@ import android.widget.ImageView;
import android.widget.LinearLayout;
import com.android.systemui.R;
+import com.android.systemui.cm.UserContentObserver;
import com.android.systemui.statusbar.policy.DeadZone;
import com.android.systemui.statusbar.policy.KeyButtonView;
@@ -55,6 +63,8 @@ import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
+import cyanogenmod.providers.CMSettings;
+
public class NavigationBarView extends LinearLayout {
final static boolean DEBUG = false;
final static String TAG = "PhoneStatusBar/NavigationBarView";
@@ -69,26 +79,56 @@ public class NavigationBarView extends LinearLayout {
int mBarSize;
boolean mVertical;
boolean mScreenOn;
+ boolean mLeftInLandscape;
boolean mShowMenu;
int mDisabledFlags = 0;
int mNavigationIconHints = 0;
- private Drawable mBackIcon, mBackLandIcon, mBackAltIcon, mBackAltLandIcon;
+ private BackButtonDrawable mBackIcon, mBackLandIcon;
private Drawable mRecentIcon;
private Drawable mRecentLandIcon;
+ private Drawable mHomeIcon, mHomeLandIcon;
private NavigationBarViewTaskSwitchHelper mTaskSwitchHelper;
private DeadZone mDeadZone;
private final NavigationBarTransitions mBarTransitions;
+ /**
+ * Tracks the current visibilities of the far left (R.id.one) and right (R.id.six) buttons
+ * while dpad arrow keys are visible.
+ *
+ * We keep track of the orientations separately because they can get in different states,
+ * We can be showing dpad arrow keys on vertical, but on portrait that may not be so.
+ */
+ public int[][] mSideButtonVisibilities = new int[][] {
+ {-1, -1} /* portrait */, {-1, -1} /* vertical */
+ };
+
+
// workaround for LayoutTransitions leaving the nav buttons in a weird state (bug 5549288)
final static boolean WORKAROUND_INVALID_LAYOUT = true;
final static int MSG_CHECK_INVALID_LAYOUT = 8686;
+ final static String NAVBAR_EDIT_ACTION = "android.intent.action.NAVBAR_EDIT";
+
+ private boolean mInEditMode;
+ private NavbarEditor mEditBar;
+ private NavBarReceiver mNavBarReceiver;
+ private OnClickListener mRecentsClickListener;
+ private OnTouchListener mRecentsPreloadListener;
+ private OnTouchListener mHomeSearchActionListener;
+ private OnLongClickListener mRecentsBackListener;
+ private OnLongClickListener mLongPressHomeListener;
+
+ private SettingsObserver mSettingsObserver;
+ private boolean mShowDpadArrowKeys;
+
// performs manual animation in sync with layout transitions
private final NavTransitionListener mTransitionListener = new NavTransitionListener();
+ private Resources mThemedResources;
+
private OnVerticalChangedListener mOnVerticalChangedListener;
private boolean mIsLayoutRtl;
private boolean mLayoutTransitionsEnabled = true;
@@ -104,9 +144,9 @@ public class NavigationBarView extends LinearLayout {
@Override
public void startTransition(LayoutTransition transition, ViewGroup container,
View view, int transitionType) {
- if (view.getId() == R.id.back) {
+ if (NavbarEditor.NAVBAR_BACK.equals(view.getTag())) {
mBackTransitioning = true;
- } else if (view.getId() == R.id.home && transitionType == LayoutTransition.APPEARING) {
+ } else if (NavbarEditor.NAVBAR_HOME.equals(view.getTag()) && transitionType == LayoutTransition.APPEARING) {
mHomeAppearing = true;
mStartDelay = transition.getStartDelay(transitionType);
mDuration = transition.getDuration(transitionType);
@@ -117,9 +157,9 @@ public class NavigationBarView extends LinearLayout {
@Override
public void endTransition(LayoutTransition transition, ViewGroup container,
View view, int transitionType) {
- if (view.getId() == R.id.back) {
+ if (NavbarEditor.NAVBAR_BACK.equals(view.getTag())) {
mBackTransitioning = false;
- } else if (view.getId() == R.id.home && transitionType == LayoutTransition.APPEARING) {
+ } else if (NavbarEditor.NAVBAR_HOME.equals(view.getTag()) && transitionType == LayoutTransition.APPEARING) {
mHomeAppearing = false;
}
}
@@ -185,6 +225,10 @@ public class NavigationBarView extends LinearLayout {
getIcons(res);
mBarTransitions = new NavigationBarTransitions(this);
+
+ mNavBarReceiver = new NavBarReceiver();
+ getContext().registerReceiver(mNavBarReceiver, new IntentFilter(NAVBAR_EDIT_ACTION));
+ mSettingsObserver = new SettingsObserver(new Handler());
}
@Override
@@ -194,6 +238,13 @@ public class NavigationBarView extends LinearLayout {
if (root != null) {
root.setDrawDuringWindowsAnimating(true);
}
+ mSettingsObserver.observe();
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ mSettingsObserver.unobserve();
}
public BarTransitions getBarTransitions() {
@@ -211,7 +262,7 @@ public class NavigationBarView extends LinearLayout {
@Override
public boolean onTouchEvent(MotionEvent event) {
- if (mTaskSwitchHelper.onTouchEvent(event)) {
+ if (!mInEditMode && mTaskSwitchHelper.onTouchEvent(event)) {
return true;
}
if (mDeadZone != null && event.getAction() == MotionEvent.ACTION_OUTSIDE) {
@@ -222,7 +273,7 @@ public class NavigationBarView extends LinearLayout {
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
- return mTaskSwitchHelper.onInterceptTouchEvent(event);
+ return !mInEditMode && mTaskSwitchHelper.onInterceptTouchEvent(event);
}
public void abortCurrentGesture() {
@@ -236,19 +287,19 @@ public class NavigationBarView extends LinearLayout {
}
public View getRecentsButton() {
- return mCurrentView.findViewById(R.id.recent_apps);
+ return mCurrentView.findViewWithTag(NavbarEditor.NAVBAR_RECENT);
}
public View getMenuButton() {
- return mCurrentView.findViewById(R.id.menu);
+ return mCurrentView.findViewWithTag(NavbarEditor.NAVBAR_CONDITIONAL_MENU);
}
public View getBackButton() {
- return mCurrentView.findViewById(R.id.back);
+ return mCurrentView.findViewWithTag(NavbarEditor.NAVBAR_BACK);
}
public KeyButtonView getHomeButton() {
- return (KeyButtonView) mCurrentView.findViewById(R.id.home);
+ return (KeyButtonView) mCurrentView.findViewWithTag(NavbarEditor.NAVBAR_HOME);
}
public View getImeSwitchButton() {
@@ -256,17 +307,48 @@ public class NavigationBarView extends LinearLayout {
}
private void getIcons(Resources res) {
- mBackIcon = res.getDrawable(R.drawable.ic_sysbar_back);
- mBackLandIcon = mBackIcon;
- mBackAltIcon = res.getDrawable(R.drawable.ic_sysbar_back_ime);
- mBackAltLandIcon = mBackAltIcon;
+ mBackIcon = new BackButtonDrawable(res.getDrawable(R.drawable.ic_sysbar_back));
+ mBackLandIcon = mBackIcon;
mRecentIcon = res.getDrawable(R.drawable.ic_sysbar_recent);
mRecentLandIcon = mRecentIcon;
+ mHomeIcon = res.getDrawable(R.drawable.ic_sysbar_home);
+ mHomeLandIcon = mHomeIcon;
+ }
+
+ public void updateResources(Resources res) {
+ mThemedResources = res;
+ getIcons(mThemedResources);
+ mBarTransitions.updateResources(res);
+ for (int i = 0; i < mRotatedViews.length; i++) {
+ ViewGroup container = (ViewGroup) mRotatedViews[i];
+ if (container != null) {
+ updateLightsOutResources(container);
+ }
+ }
+ }
+
+ private void updateLightsOutResources(ViewGroup container) {
+ ViewGroup lightsOut = (ViewGroup) container.findViewById(R.id.lights_out);
+ if (lightsOut != null) {
+ final int nChildren = lightsOut.getChildCount();
+ for (int i = 0; i < nChildren; i++) {
+ final View child = lightsOut.getChildAt(i);
+ if (child instanceof ImageView) {
+ final ImageView iv = (ImageView) child;
+ // clear out the existing drawable, this is required since the
+ // ImageView keeps track of the resource ID and if it is the same
+ // it will not update the drawable.
+ iv.setImageDrawable(null);
+ iv.setImageDrawable(mThemedResources.getDrawable(
+ R.drawable.ic_sysbar_lights_out_dot_large));
+ }
+ }
+ }
}
@Override
public void setLayoutDirection(int layoutDirection) {
- getIcons(getContext().getResources());
+ getIcons(mThemedResources != null ? mThemedResources : getContext().getResources());
super.setLayoutDirection(layoutDirection);
}
@@ -294,19 +376,61 @@ public class NavigationBarView extends LinearLayout {
mNavigationIconHints = hints;
- ((ImageView)getBackButton()).setImageDrawable(backAlt
- ? (mVertical ? mBackAltLandIcon : mBackAltIcon)
- : (mVertical ? mBackLandIcon : mBackIcon));
+ ((ImageView)getBackButton()).setImageDrawable(null);
+ ((ImageView)getBackButton()).setImageDrawable(mVertical ? mBackLandIcon : mBackIcon);
+ mBackLandIcon.setImeVisible(backAlt);
+ mBackIcon.setImeVisible(backAlt);
((ImageView)getRecentsButton()).setImageDrawable(mVertical ? mRecentLandIcon : mRecentIcon);
+ ((ImageView)getHomeButton()).setImageDrawable(mVertical ? mHomeLandIcon : mHomeIcon);
- final boolean showImeButton = ((hints & StatusBarManager.NAVIGATION_HINT_IME_SHOWN) != 0);
+ final boolean showImeButton = ((hints & StatusBarManager.NAVIGATION_HINT_IME_SHOWN) != 0)
+ && !mShowDpadArrowKeys;
getImeSwitchButton().setVisibility(showImeButton ? View.VISIBLE : View.INVISIBLE);
+
+ setDisabledFlags(mDisabledFlags, true);
+
// Update menu button in case the IME state has changed.
setMenuVisibility(mShowMenu, true);
+ if (mShowDpadArrowKeys) { // overrides IME button
+ final boolean showingIme = ((mNavigationIconHints
+ & StatusBarManager.NAVIGATION_HINT_BACK_ALT) != 0);
- setDisabledFlags(mDisabledFlags, true);
+ setVisibleOrGone(getCurrentView().findViewById(R.id.dpad_left), showingIme);
+ setVisibleOrGone(getCurrentView().findViewById(R.id.dpad_right), showingIme);
+
+ View one = getCurrentView().findViewById(mVertical ? R.id.six : R.id.one);
+ View six = getCurrentView().findViewById(mVertical ? R.id.one : R.id.six);
+ if (showingIme) {
+ if (one.getVisibility() != View.GONE) {
+ setSideButtonVisibility(true, one.getVisibility());
+ setVisibleOrGone(one, false);
+ }
+
+ if (six.getVisibility() != View.GONE) {
+ setSideButtonVisibility(false, six.getVisibility());
+ setVisibleOrGone(six, false);
+ }
+ } else {
+ if (getSideButtonVisibility(true) != -1) {
+ one.setVisibility(getSideButtonVisibility(true));
+ setSideButtonVisibility(true, - 1);
+ }
+ if (getSideButtonVisibility(false) != -1) {
+ six.setVisibility(getSideButtonVisibility(false));
+ setSideButtonVisibility(false, -1);
+ }
+ }
+ }
+ }
+
+ private int getSideButtonVisibility(boolean left) {
+ return mSideButtonVisibilities[mVertical ? 1 : 0][left ? 0 : 1];
+ }
+
+ private void setSideButtonVisibility(boolean left, int vis) {
+ mSideButtonVisibilities[mVertical ? 1 : 0][left ? 0 : 1] = vis;
}
public void setDisabledFlags(int disabledFlags) {
@@ -343,9 +467,10 @@ public class NavigationBarView extends LinearLayout {
disableRecent = false;
}
- getBackButton() .setVisibility(disableBack ? View.INVISIBLE : View.VISIBLE);
- getHomeButton() .setVisibility(disableHome ? View.INVISIBLE : View.VISIBLE);
- getRecentsButton().setVisibility(disableRecent ? View.INVISIBLE : View.VISIBLE);
+ setButtonWithTagVisibility(NavbarEditor.NAVBAR_BACK, !disableBack);
+ setButtonWithTagVisibility(NavbarEditor.NAVBAR_HOME, !disableHome);
+ setButtonWithTagVisibility(NavbarEditor.NAVBAR_RECENT, !disableRecent);
+ setButtonWithTagVisibility(NavbarEditor.NAVBAR_SEARCH, !disableSearch);
}
private boolean inLockTask() {
@@ -436,19 +561,18 @@ public class NavigationBarView extends LinearLayout {
// Only show Menu if IME switcher not shown.
final boolean shouldShow = mShowMenu &&
((mNavigationIconHints & StatusBarManager.NAVIGATION_HINT_IME_SHOWN) == 0);
- getMenuButton().setVisibility(shouldShow ? View.VISIBLE : View.INVISIBLE);
+ final boolean shouldShowAlwaysMenu = (mNavigationIconHints &
+ StatusBarManager.NAVIGATION_HINT_IME_SHOWN) == 0;
+ setButtonWithTagVisibility(NavbarEditor.NAVBAR_ALWAYS_MENU, shouldShowAlwaysMenu);
+ setButtonWithTagVisibility(NavbarEditor.NAVBAR_CONDITIONAL_MENU, shouldShow);
+ setButtonWithTagVisibility(NavbarEditor.NAVBAR_SEARCH, shouldShowAlwaysMenu);
}
@Override
public void onFinishInflate() {
- mRotatedViews[Surface.ROTATION_0] =
- mRotatedViews[Surface.ROTATION_180] = findViewById(R.id.rot0);
-
- mRotatedViews[Surface.ROTATION_90] = findViewById(R.id.rot90);
-
- mRotatedViews[Surface.ROTATION_270] = mRotatedViews[Surface.ROTATION_90];
-
- mCurrentView = mRotatedViews[Surface.ROTATION_0];
+ mRotatedViews[Configuration.ORIENTATION_PORTRAIT] = findViewById(R.id.rot0);
+ mRotatedViews[Configuration.ORIENTATION_LANDSCAPE] = findViewById(R.id.rot90);
+ mCurrentView = mRotatedViews[getResources().getConfiguration().orientation];
getImeSwitchButton().setOnClickListener(mImeSwitcherClickListener);
@@ -459,18 +583,33 @@ public class NavigationBarView extends LinearLayout {
return mVertical;
}
+ public void setLeftInLandscape(boolean leftInLandscape) {
+ mLeftInLandscape = leftInLandscape;
+ mDeadZone.setStartFromRight(leftInLandscape);
+ }
+
public void reorient() {
- final int rot = mDisplay.getRotation();
- for (int i=0; i<4; i++) {
- mRotatedViews[i].setVisibility(View.GONE);
- }
- mCurrentView = mRotatedViews[rot];
+ int orientation = getResources().getConfiguration().orientation;
+ mRotatedViews[Configuration.ORIENTATION_PORTRAIT].setVisibility(View.GONE);
+ mRotatedViews[Configuration.ORIENTATION_LANDSCAPE].setVisibility(View.GONE);
+ mCurrentView = mRotatedViews[orientation];
mCurrentView.setVisibility(View.VISIBLE);
+
updateLayoutTransitionsEnabled();
+ if (NavbarEditor.isDevicePhone(getContext())) {
+ int rotation = mDisplay.getRotation();
+ mVertical = rotation == Surface.ROTATION_90 || rotation == Surface.ROTATION_270;
+ } else {
+ mVertical = getWidth() > 0 && getHeight() > getWidth();
+ }
+ mEditBar = new NavbarEditor(mCurrentView, mVertical, mIsLayoutRtl);
+ updateSettings();
+
getImeSwitchButton().setOnClickListener(mImeSwitcherClickListener);
mDeadZone = (DeadZone) mCurrentView.findViewById(R.id.deadzone);
+ mDeadZone.setStartFromRight(mLeftInLandscape);
// force the low profile & disabled states into compliance
mBarTransitions.init();
@@ -529,55 +668,8 @@ public class NavigationBarView extends LinearLayout {
boolean isLayoutRtl = getResources().getConfiguration()
.getLayoutDirection() == LAYOUT_DIRECTION_RTL;
if (mIsLayoutRtl != isLayoutRtl) {
-
- // We swap all children of the 90 and 270 degree layouts, since they are vertical
- View rotation90 = mRotatedViews[Surface.ROTATION_90];
- swapChildrenOrderIfVertical(rotation90.findViewById(R.id.nav_buttons));
- adjustExtraKeyGravity(rotation90, isLayoutRtl);
-
- View rotation270 = mRotatedViews[Surface.ROTATION_270];
- if (rotation90 != rotation270) {
- swapChildrenOrderIfVertical(rotation270.findViewById(R.id.nav_buttons));
- adjustExtraKeyGravity(rotation270, isLayoutRtl);
- }
mIsLayoutRtl = isLayoutRtl;
- }
- }
-
- private void adjustExtraKeyGravity(View navBar, boolean isLayoutRtl) {
- View menu = navBar.findViewById(R.id.menu);
- View imeSwitcher = navBar.findViewById(R.id.ime_switcher);
- if (menu != null) {
- FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) menu.getLayoutParams();
- lp.gravity = isLayoutRtl ? Gravity.BOTTOM : Gravity.TOP;
- menu.setLayoutParams(lp);
- }
- if (imeSwitcher != null) {
- FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) imeSwitcher.getLayoutParams();
- lp.gravity = isLayoutRtl ? Gravity.BOTTOM : Gravity.TOP;
- imeSwitcher.setLayoutParams(lp);
- }
- }
-
- /**
- * Swaps the children order of a LinearLayout if it's orientation is Vertical
- *
- * @param group The LinearLayout to swap the children from.
- */
- private void swapChildrenOrderIfVertical(View group) {
- if (group instanceof LinearLayout) {
- LinearLayout linearLayout = (LinearLayout) group;
- if (linearLayout.getOrientation() == VERTICAL) {
- int childCount = linearLayout.getChildCount();
- ArrayList<View> childList = new ArrayList<>(childCount);
- for (int i = 0; i < childCount; i++) {
- childList.add(linearLayout.getChildAt(i));
- }
- linearLayout.removeAllViews();
- for (int i = childCount - 1; i >= 0; i--) {
- linearLayout.addView(childList.get(i));
- }
- }
+ reorient();
}
}
@@ -671,9 +763,9 @@ public class NavigationBarView extends LinearLayout {
pw.print("null");
} else {
pw.print(PhoneStatusBar.viewInfo(button)
- + " " + visibilityToString(button.getVisibility())
- + " alpha=" + button.getAlpha()
- );
+ + " " + visibilityToString(button.getVisibility())
+ + " alpha=" + button.getAlpha()
+ );
}
pw.println();
}
@@ -681,4 +773,145 @@ public class NavigationBarView extends LinearLayout {
public interface OnVerticalChangedListener {
void onVerticalChanged(boolean isVertical);
}
+
+ void setListeners(OnClickListener recentsClickListener, OnTouchListener recentsPreloadListener,
+ OnLongClickListener recentsBackListener, OnTouchListener homeSearchActionListener,
+ OnLongClickListener longPressHomeListener) {
+ mRecentsClickListener = recentsClickListener;
+ mRecentsPreloadListener = recentsPreloadListener;
+ mHomeSearchActionListener = homeSearchActionListener;
+ mRecentsBackListener = recentsBackListener;
+ mLongPressHomeListener = longPressHomeListener;
+ updateButtonListeners();
+ }
+
+ private void removeButtonListeners() {
+ ViewGroup container = (ViewGroup) mCurrentView.findViewById(R.id.container);
+ int viewCount = container.getChildCount();
+ for (int i = 0; i < viewCount; i++) {
+ View button = container.getChildAt(i);
+ if (button instanceof KeyButtonView) {
+ button.setOnClickListener(null);
+ button.setOnTouchListener(null);
+ button.setLongClickable(false);
+ button.setOnLongClickListener(null);
+ }
+ }
+ }
+
+ protected void updateButtonListeners() {
+ View recentView = mCurrentView.findViewWithTag(NavbarEditor.NAVBAR_RECENT);
+ if (recentView != null) {
+ recentView.setOnClickListener(mRecentsClickListener);
+ recentView.setOnTouchListener(mRecentsPreloadListener);
+ recentView.setLongClickable(true);
+ recentView.setOnLongClickListener(mRecentsBackListener);
+ }
+ View backView = mCurrentView.findViewWithTag(NavbarEditor.NAVBAR_BACK);
+ if (backView != null) {
+ backView.setLongClickable(true);
+ backView.setOnLongClickListener(mRecentsBackListener);
+ }
+ View homeView = mCurrentView.findViewWithTag(NavbarEditor.NAVBAR_HOME);
+ if (homeView != null) {
+ homeView.setOnTouchListener(mHomeSearchActionListener);
+ homeView.setLongClickable(true);
+ homeView.setOnLongClickListener(mLongPressHomeListener);
+ }
+ }
+
+ public boolean isInEditMode() {
+ return mInEditMode;
+ }
+
+ private void setButtonWithTagVisibility(Object tag, boolean visible) {
+ View findView = mCurrentView.findViewWithTag(tag);
+ if (findView == null) {
+ return;
+ }
+ int visibility = visible ? View.VISIBLE : View.INVISIBLE;
+ // if we're showing dpad arrow keys (e.g. the side button visibility where it's shown != -1)
+ // then don't actually update that buttons visibility, but update the stored value
+ if (getSideButtonVisibility(true) != -1
+ && findView.getId() == (mVertical ? R.id.six : R.id.one)) {
+ setSideButtonVisibility(true, visibility);
+ } else if (getSideButtonVisibility(false) != -1
+ && findView.getId() == (mVertical ? R.id.one : R.id.six)) {
+ setSideButtonVisibility(false, visibility);
+ } else {
+ findView.setVisibility(visibility);
+ }
+ }
+
+ // TODO LINK TO THIS ONCE THEMES GOES IN
+ protected void updateResources() {
+ getIcons(mContext.getResources());
+ }
+
+ public class NavBarReceiver extends BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ boolean edit = intent.getBooleanExtra("edit", false);
+ boolean save = intent.getBooleanExtra("save", false);
+ if (edit != mInEditMode) {
+ mInEditMode = edit;
+ if (edit) {
+ removeButtonListeners();
+ mEditBar.setEditMode(true);
+ } else {
+ if (save) {
+ mEditBar.saveKeys();
+ }
+ mEditBar.setEditMode(false);
+ updateSettings();
+ }
+ }
+ }
+ }
+
+ public void updateSettings() {
+ mEditBar.updateKeys();
+ removeButtonListeners();
+ updateButtonListeners();
+ setDisabledFlags(mDisabledFlags, true /* force */);
+ setMenuVisibility(mShowMenu, true);
+ }
+
+ private class SettingsObserver extends UserContentObserver {
+
+ SettingsObserver(Handler handler) {
+ super(handler);
+ }
+
+ @Override
+ public void observe() {
+ super.observe();
+ ContentResolver resolver = getContext().getContentResolver();
+ resolver.registerContentObserver(
+ CMSettings.System.getUriFor(CMSettings.System.NAVIGATION_BAR_MENU_ARROW_KEYS),
+ false, this);
+
+ // intialize mModlockDisabled
+ onChange(false);
+ }
+
+ @Override
+ public void unobserve() {
+ super.unobserve();
+ getContext().getContentResolver().unregisterContentObserver(this);
+ }
+
+ @Override
+ protected void update() {
+ mShowDpadArrowKeys = CMSettings.System.getIntForUser(getContext().getContentResolver(),
+ CMSettings.System.NAVIGATION_BAR_MENU_ARROW_KEYS, 0, UserHandle.USER_CURRENT) != 0;
+ // reset saved side button visibilities
+ for (int i = 0; i < mSideButtonVisibilities.length; i++) {
+ for (int j = 0; j < mSideButtonVisibilities[i].length; j++) {
+ mSideButtonVisibilities[i][j] = -1;
+ }
+ }
+ setNavigationIconHints(mNavigationIconHints, true);
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index bdd2c73..33e3f3c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -21,17 +21,24 @@ import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
import android.animation.ValueAnimator;
+import android.content.ContentResolver;
import android.app.ActivityManager;
import android.app.StatusBarManager;
import android.content.Context;
import android.content.pm.ResolveInfo;
import android.content.res.Configuration;
+import android.database.ContentObserver;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.PowerManager;
+import android.provider.Settings;
import android.util.AttributeSet;
import android.util.MathUtils;
+import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
@@ -63,9 +70,12 @@ import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.statusbar.policy.KeyguardUserSwitcher;
import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
import com.android.systemui.statusbar.stack.StackStateAnimator;
+import cyanogenmod.providers.CMSettings;
import java.util.List;
+import cyanogenmod.providers.CMSettings;
+
public class NotificationPanelView extends PanelView implements
ExpandableView.OnHeightChangedListener, ObservableScrollView.Listener,
View.OnClickListener, NotificationStackScrollLayout.OnOverscrollTopChangedListener,
@@ -217,9 +227,28 @@ public class NotificationPanelView extends PanelView implements
private final Interpolator mTouchResponseInterpolator =
new PathInterpolator(0.3f, 0f, 0.1f, 1f);
+ private Handler mHandler = new Handler();
+ private SettingsObserver mSettingsObserver;
+
+ private boolean mOneFingerQuickSettingsIntercept;
+ private boolean mDoubleTapToSleepEnabled;
+ private int mStatusBarHeaderHeight;
+ private GestureDetector mDoubleTapGesture;
+
public NotificationPanelView(Context context, AttributeSet attrs) {
super(context, attrs);
setWillNotDraw(!DEBUG);
+
+ mSettingsObserver = new SettingsObserver(mHandler);
+ mDoubleTapGesture = new GestureDetector(mContext, new GestureDetector.SimpleOnGestureListener() {
+ @Override
+ public boolean onDoubleTap(MotionEvent e) {
+ PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
+ if(pm != null)
+ pm.goToSleep(e.getEventTime());
+ return true;
+ }
+ });
}
public void setStatusBar(PhoneStatusBar bar) {
@@ -292,6 +321,7 @@ public class NotificationPanelView extends PanelView implements
R.dimen.qs_falsing_threshold);
mPositionMinSideMargin = getResources().getDimensionPixelSize(
R.dimen.notification_panel_min_side_margin);
+ mStatusBarHeaderHeight = getResources().getDimensionPixelSize(R.dimen.status_bar_header_height);
}
public void updateResources() {
@@ -716,6 +746,11 @@ public class NotificationPanelView extends PanelView implements
if (mBlockTouches) {
return false;
}
+ if (mDoubleTapToSleepEnabled
+ && mStatusBarState == StatusBarState.KEYGUARD
+ && event.getY() < mStatusBarHeaderHeight) {
+ mDoubleTapGesture.onTouchEvent(event);
+ }
initDownStates(event);
if (mListenForHeadsUp && !mHeadsUpTouchHelper.isTrackingHeadsUp()
&& mHeadsUpTouchHelper.onInterceptTouchEvent(event)) {
@@ -806,7 +841,14 @@ public class NotificationPanelView extends PanelView implements
&& (event.isButtonPressed(MotionEvent.BUTTON_SECONDARY)
|| event.isButtonPressed(MotionEvent.BUTTON_TERTIARY));
- return twoFingerDrag || stylusButtonClickDrag || mouseButtonClickDrag;
+ final float w = getMeasuredWidth();
+ final float x = event.getX();
+ float region = (w * (1.f/4.f)); // TODO overlay region fraction?
+ final boolean showQsOverride = mOneFingerQuickSettingsIntercept &&
+ isLayoutRtl() ? (x < region) : (w - region < x)
+ && mStatusBarState == StatusBarState.SHADE;
+
+ return twoFingerDrag || showQsOverride || stylusButtonClickDrag || mouseButtonClickDrag;
}
private void handleQsDown(MotionEvent event) {
@@ -1469,6 +1511,7 @@ public class NotificationPanelView extends PanelView implements
View header = mKeyguardShowing ? mKeyguardStatusBar : mHeader;
boolean onHeader = x >= header.getX() && x <= header.getX() + header.getWidth()
&& y >= header.getTop() && y <= header.getBottom();
+
if (mQsExpanded) {
return onHeader || (mScrollView.isScrolledToBottom() && yDiff < 0) && isInQsArea(x, y);
} else {
@@ -1802,7 +1845,6 @@ public class NotificationPanelView extends PanelView implements
private void setListening(boolean listening) {
mHeader.setListening(listening);
- mKeyguardStatusBar.setListening(listening);
mQsPanel.setListening(listening);
}
@@ -2025,13 +2067,9 @@ public class NotificationPanelView extends PanelView implements
});
rightIcon = getLayoutDirection() == LAYOUT_DIRECTION_RTL ? !rightIcon : rightIcon;
if (rightIcon) {
- mStatusBar.onCameraHintStarted();
+ mStatusBar.onCameraHintStarted(mKeyguardBottomArea.getRightHint());
} else {
- if (mKeyguardBottomArea.isLeftVoiceAssist()) {
- mStatusBar.onVoiceAssistHintStarted();
- } else {
- mStatusBar.onPhoneHintStarted();
- }
+ mStatusBar.onLeftHintStarted(mKeyguardBottomArea.getLeftHint());
}
}
@@ -2200,6 +2238,11 @@ public class NotificationPanelView extends PanelView implements
// Hide "No notifications" in QS.
mNotificationStackScroller.updateEmptyShadeView(mShadeEmpty && !mQsExpanded);
+ if (mStatusBarState == StatusBarState.KEYGUARD
+ && (!mQsExpanded || mQsExpandImmediate || mIsExpanding
+ && mQsExpandedWhenExpandingStarted)) {
+ positionClockAndNotifications();
+ }
}
public void setQsScrimEnabled(boolean qsScrimEnabled) {
@@ -2384,6 +2427,44 @@ public class NotificationPanelView extends PanelView implements
return mHeadsUpManager.hasPinnedHeadsUp() || mHeadsUpAnimatingAway;
}
+ class SettingsObserver extends ContentObserver {
+ SettingsObserver(Handler handler) {
+ super(handler);
+ }
+
+ void observe() {
+ ContentResolver resolver = mContext.getContentResolver();
+ resolver.registerContentObserver(CMSettings.System.getUriFor(
+ CMSettings.System.STATUS_BAR_QUICK_QS_PULLDOWN), false, this);
+ resolver.registerContentObserver(CMSettings.System.getUriFor(
+ CMSettings.System.DOUBLE_TAP_SLEEP_GESTURE), false, this);
+ update();
+ }
+
+ void unobserve() {
+ ContentResolver resolver = mContext.getContentResolver();
+ resolver.unregisterContentObserver(this);
+ }
+
+ @Override
+ public void onChange(boolean selfChange) {
+ update();
+ }
+
+ @Override
+ public void onChange(boolean selfChange, Uri uri) {
+ update();
+ }
+
+ public void update() {
+ ContentResolver resolver = mContext.getContentResolver();
+ mOneFingerQuickSettingsIntercept = CMSettings.System.getInt(
+ resolver, CMSettings.System.STATUS_BAR_QUICK_QS_PULLDOWN, 1) == 1;
+ mDoubleTapToSleepEnabled = CMSettings.System.getInt(
+ resolver, CMSettings.System.DOUBLE_TAP_SLEEP_GESTURE, 1) == 1;
+ }
+ }
+
@Override
public boolean hasOverlappingRendering() {
return !mDozing;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
index e03bcfb..9a8fa98 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -40,6 +40,8 @@ import com.android.systemui.statusbar.FlingAnimationUtils;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.policy.HeadsUpManager;
+import cyanogenmod.power.PerformanceManager;
+
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -86,6 +88,8 @@ public abstract class PanelView extends FrameLayout {
private VelocityTrackerInterface mVelocityTracker;
private FlingAnimationUtils mFlingAnimationUtils;
+ private final PerformanceManager mPerf;
+
/**
* Whether an instant expand request is currently pending and we are just waiting for layout.
*/
@@ -122,6 +126,18 @@ public abstract class PanelView extends FrameLayout {
}
};
+ private ViewTreeObserver.OnGlobalLayoutListener mInstantExpandLayoutListener =
+ new ViewTreeObserver.OnGlobalLayoutListener() {
+ @Override
+ public void onGlobalLayout() {
+ if (mStatusBar.getStatusBarWindow().getHeight() != mStatusBar.getStatusBarHeight()) {
+ getViewTreeObserver().removeOnGlobalLayoutListener(this);
+ setExpandedFraction(1f);
+ mInstantExpanding = false;
+ }
+ }
+ };
+
protected void onExpandingFinished() {
mBar.onExpandingFinished();
}
@@ -190,6 +206,8 @@ public abstract class PanelView extends FrameLayout {
mLinearOutSlowInInterpolator =
AnimationUtils.loadInterpolator(context, android.R.interpolator.linear_out_slow_in);
mBounceInterpolator = new BounceInterpolator();
+
+ mPerf = PerformanceManager.getInstance(context);
}
protected void loadDimens() {
@@ -659,6 +677,9 @@ public abstract class PanelView extends FrameLayout {
/ collapseSpeedUpFactor));
}
}
+
+ mPerf.cpuBoost((int)animator.getDuration() * 1000);
+
animator.addListener(new AnimatorListenerAdapter() {
private boolean mCancelled;
@@ -874,18 +895,7 @@ public abstract class PanelView extends FrameLayout {
// Wait for window manager to pickup the change, so we know the maximum height of the panel
// then.
- getViewTreeObserver().addOnGlobalLayoutListener(
- new ViewTreeObserver.OnGlobalLayoutListener() {
- @Override
- public void onGlobalLayout() {
- if (mStatusBar.getStatusBarWindow().getHeight()
- != mStatusBar.getStatusBarHeight()) {
- getViewTreeObserver().removeOnGlobalLayoutListener(this);
- setExpandedFraction(1f);
- mInstantExpanding = false;
- }
- }
- });
+ getViewTreeObserver().addOnGlobalLayoutListener(mInstantExpandLayoutListener);
// Make sure a layout really happens.
requestLayout();
@@ -894,6 +904,7 @@ public abstract class PanelView extends FrameLayout {
public void instantCollapse() {
abortAnimations();
setExpandedFraction(0f);
+ getViewTreeObserver().removeOnGlobalLayoutListener(mInstantExpandLayoutListener);
if (mExpanding) {
notifyExpandingFinished();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 73361bd..6de6348 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -17,22 +17,33 @@
package com.android.systemui.statusbar.phone;
+import static com.android.systemui.settings.BrightnessController.BRIGHTNESS_ADJ_RESOLUTION;
+
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.annotation.NonNull;
import android.app.ActivityManager;
import android.app.ActivityManagerNative;
+import android.app.ActivityOptions;
import android.app.IActivityManager;
import android.app.Notification;
import android.app.PendingIntent;
import android.app.StatusBarManager;
+import android.app.WallpaperManager;
+import android.content.ActivityNotFoundException;
import android.content.BroadcastReceiver;
import android.content.ComponentCallbacks2;
+import android.content.ComponentName;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.IPackageManager;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
import android.content.res.Configuration;
+import android.content.res.ThemeChangeRequest.RequestType;
+import android.content.res.ThemeConfig;
import android.content.res.Resources;
import android.database.ContentObserver;
import android.graphics.Bitmap;
@@ -58,6 +69,7 @@ import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
+import android.os.IPowerManager;
import android.os.Message;
import android.os.PowerManager;
import android.os.Process;
@@ -75,15 +87,22 @@ import android.util.ArraySet;
import android.util.DisplayMetrics;
import android.util.EventLog;
import android.util.Log;
+import android.util.Pair;
import android.view.Display;
import android.view.KeyEvent;
import android.view.LayoutInflater;
+import android.view.HapticFeedbackConstants;
import android.view.MotionEvent;
import android.view.ThreadedRenderer;
import android.view.VelocityTracker;
import android.view.View;
+import android.view.WindowManagerGlobal;
+import android.view.ViewConfiguration;
+import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
+import android.view.ViewGroup.MarginLayoutParams;
import android.view.ViewStub;
+import android.view.ViewTreeObserver;
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
import android.view.accessibility.AccessibilityEvent;
@@ -92,28 +111,34 @@ import android.view.animation.AccelerateInterpolator;
import android.view.animation.Interpolator;
import android.view.animation.LinearInterpolator;
import android.view.animation.PathInterpolator;
+import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.TextView;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.statusbar.NotificationVisibility;
import com.android.internal.statusbar.StatusBarIcon;
+import com.android.internal.util.cm.ActionUtils;
import com.android.keyguard.KeyguardHostView.OnDismissAction;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.keyguard.ViewMediatorCallback;
import com.android.systemui.BatteryMeterView;
+import com.android.systemui.BatteryLevelTextView;
import com.android.systemui.DemoMode;
import com.android.systemui.EventLogConstants;
import com.android.systemui.EventLogTags;
import com.android.systemui.Prefs;
import com.android.systemui.R;
import com.android.systemui.assist.AssistManager;
+import com.android.systemui.cm.UserContentObserver;
import com.android.systemui.doze.DozeHost;
import com.android.systemui.doze.DozeLog;
import com.android.systemui.keyguard.KeyguardViewMediator;
+import com.android.systemui.qs.QSDragPanel;
import com.android.systemui.qs.QSPanel;
import com.android.systemui.recents.ScreenPinningRequest;
+import com.android.systemui.settings.BrightnessController;
import com.android.systemui.statusbar.ActivatableNotificationView;
import com.android.systemui.statusbar.BackDropView;
import com.android.systemui.statusbar.BaseStatusBar;
@@ -145,19 +170,24 @@ import com.android.systemui.statusbar.policy.KeyButtonView;
import com.android.systemui.statusbar.policy.KeyguardMonitor;
import com.android.systemui.statusbar.policy.KeyguardUserSwitcher;
import com.android.systemui.statusbar.policy.LocationControllerImpl;
+import com.android.systemui.statusbar.policy.NetworkController;
import com.android.systemui.statusbar.policy.NetworkControllerImpl;
import com.android.systemui.statusbar.policy.NextAlarmController;
import com.android.systemui.statusbar.policy.PreviewInflater;
import com.android.systemui.statusbar.policy.RotationLockControllerImpl;
import com.android.systemui.statusbar.policy.SecurityControllerImpl;
+import com.android.systemui.statusbar.policy.SuControllerImpl;
import com.android.systemui.statusbar.policy.UserInfoController;
import com.android.systemui.statusbar.policy.UserSwitcherController;
+import com.android.systemui.statusbar.policy.WeatherControllerImpl;
import com.android.systemui.statusbar.policy.ZenModeController;
import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
import com.android.systemui.statusbar.stack.NotificationStackScrollLayout.OnChildLocationsChangedListener;
import com.android.systemui.statusbar.stack.StackStateAnimator;
import com.android.systemui.statusbar.stack.StackViewState;
import com.android.systemui.volume.VolumeComponent;
+import cyanogenmod.app.CustomTileListenerService;
+import cyanogenmod.app.StatusBarPanelCustomTile;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -183,6 +213,8 @@ import static com.android.systemui.statusbar.phone.BarTransitions.MODE_TRANSLUCE
import static com.android.systemui.statusbar.phone.BarTransitions.MODE_TRANSPARENT;
import static com.android.systemui.statusbar.phone.BarTransitions.MODE_WARNING;
+import cyanogenmod.providers.CMSettings;
+
public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
DragDownHelper.DragDownCallback, ActivityStarter, OnUnlockMethodChangedListener,
HeadsUpManager.OnHeadsUpChangedListener {
@@ -207,6 +239,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
private static final int MSG_CLOSE_PANELS = 1001;
private static final int MSG_OPEN_SETTINGS_PANEL = 1002;
private static final int MSG_LAUNCH_TRANSITION_TIMEOUT = 1003;
+ private static final int MSG_UPDATE_NOTIFICATIONS = 1004;
// 1020-1040 reserved for BaseStatusBar
// Time after we abort the launch transition.
@@ -231,6 +264,10 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
.setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
.build();
+ private static final float BRIGHTNESS_CONTROL_PADDING = 0.15f;
+ private static final int BRIGHTNESS_CONTROL_LONG_PRESS_TIMEOUT = 750; // ms
+ private static final int BRIGHTNESS_CONTROL_LINGER_THRESHOLD = 20;
+
public static final int FADE_KEYGUARD_START_DELAY = 100;
public static final int FADE_KEYGUARD_DURATION = 300;
public static final int FADE_KEYGUARD_DURATION_PULSING = 96;
@@ -274,6 +311,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
KeyguardMonitor mKeyguardMonitor;
BrightnessMirrorController mBrightnessMirrorController;
AccessibilityController mAccessibilityController;
+ WeatherControllerImpl mWeatherController;
+ SuControllerImpl mSuController;
FingerprintUnlockController mFingerprintUnlockController;
int mNaturalBarHeight = -1;
@@ -282,6 +321,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
Point mCurrentDisplaySize = new Point();
StatusBarWindowView mStatusBarWindow;
+ FrameLayout mStatusBarWindowContent;
PhoneStatusBarView mStatusBarView;
private int mStatusBarWindowState = WINDOW_STATE_SHOWING;
private StatusBarWindowManager mStatusBarWindowManager;
@@ -290,6 +330,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
private boolean mWakeUpComingFromTouch;
private PointF mWakeUpTouchLocation;
private boolean mScreenTurningOn;
+ private BatteryMeterView mBatteryView;
+ private BatteryLevelTextView mBatteryTextView;
int mPixelFormat;
Object mQueueLock = new Object();
@@ -302,7 +344,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
TextView mNotificationPanelDebugText;
// settings
- private QSPanel mQSPanel;
+ private QSDragPanel mQSPanel;
+ private DevForceNavbarObserver mDevForceNavbarObserver;
// top bar
StatusBarHeaderView mHeader;
@@ -316,15 +359,23 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
private boolean mKeyguardGoingAway;
// Keyguard is actually fading away now.
private boolean mKeyguardFadingAway;
+ private boolean mKeyguardShowingMedia;
private long mKeyguardFadingAwayDelay;
private long mKeyguardFadingAwayDuration;
+ private Bitmap mKeyguardWallpaper;
+
int mKeyguardMaxNotificationCount;
+ // carrier label
+ private TextView mCarrierLabel;
+ private boolean mShowCarrierInPanel = false;
boolean mExpandedVisible;
private int mNavigationBarWindowState = WINDOW_STATE_SHOWING;
+ private int mStatusBarHeaderHeight;
+
// the tracker view
int mTrackingPosition; // the position of the top of the tracking view.
@@ -335,6 +386,21 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
int[] mAbsPos = new int[2];
ArrayList<Runnable> mPostCollapseRunnables = new ArrayList<>();
+ private boolean mAutomaticBrightness;
+ private boolean mBrightnessControl;
+ private boolean mBrightnessChanged;
+ private float mScreenWidth;
+ private int mMinBrightness;
+ private boolean mJustPeeked;
+ int mLinger;
+ int mInitialTouchX;
+ int mInitialTouchY;
+
+ // last theme that was applied in order to detect theme change (as opposed
+ // to some other configuration change).
+ ThemeConfig mCurrentTheme;
+ private boolean mRecreating = false;
+
// for disabling the status bar
int mDisabled1 = 0;
int mDisabled2 = 0;
@@ -357,6 +423,120 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
private int mNavigationIconHints = 0;
private HandlerThread mHandlerThread;
+ Runnable mLongPressBrightnessChange = new Runnable() {
+ @Override
+ public void run() {
+ mStatusBarView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
+ adjustBrightness(mInitialTouchX);
+ mLinger = BRIGHTNESS_CONTROL_LINGER_THRESHOLD + 1;
+ }
+ };
+
+ // Custom Recents Long Press
+ // - Tracks Event state for custom (user-configurable) Long Presses.
+ private boolean mCustomRecentsLongPressed = false;
+ // - The ArrayList is updated when packages are added and removed.
+ private List<ComponentName> mCustomRecentsLongPressHandlerCandidates = new ArrayList<>();
+ // - The custom Recents Long Press, if selected. When null, use default (switch last app).
+ private ComponentName mCustomRecentsLongPressHandler = null;
+
+ class SettingsObserver extends UserContentObserver {
+ SettingsObserver(Handler handler) {
+ super(handler);
+ }
+
+ @Override
+ protected void observe() {
+ super.observe();
+
+ ContentResolver resolver = mContext.getContentResolver();
+ resolver.registerContentObserver(CMSettings.System.getUriFor(
+ CMSettings.System.STATUS_BAR_BRIGHTNESS_CONTROL), false, this,
+ UserHandle.USER_ALL);
+ resolver.registerContentObserver(Settings.System.getUriFor(
+ Settings.System.SCREEN_BRIGHTNESS_MODE), false, this, UserHandle.USER_ALL);
+ resolver.registerContentObserver(CMSettings.System.getUriFor(
+ CMSettings.System.NAVBAR_LEFT_IN_LANDSCAPE), false, this, UserHandle.USER_ALL);
+ resolver.registerContentObserver(CMSettings.System.getUriFor(
+ CMSettings.Secure.RECENTS_LONG_PRESS_ACTIVITY), false, this);
+ update();
+ }
+
+ @Override
+ protected void unobserve() {
+ super.unobserve();
+ ContentResolver resolver = mContext.getContentResolver();
+ resolver.unregisterContentObserver(this);
+ }
+
+ @Override
+ public void update() {
+ ContentResolver resolver = mContext.getContentResolver();
+ int mode = Settings.System.getIntForUser(mContext.getContentResolver(),
+ Settings.System.SCREEN_BRIGHTNESS_MODE,
+ Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL,
+ UserHandle.USER_CURRENT);
+ mAutomaticBrightness = mode != Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL;
+ mBrightnessControl = CMSettings.System.getIntForUser(
+ resolver, CMSettings.System.STATUS_BAR_BRIGHTNESS_CONTROL, 0,
+ UserHandle.USER_CURRENT) == 1;
+
+ if (mNavigationBarView != null) {
+ boolean navLeftInLandscape = CMSettings.System.getIntForUser(resolver,
+ CMSettings.System.NAVBAR_LEFT_IN_LANDSCAPE, 0, UserHandle.USER_CURRENT) == 1;
+ mNavigationBarView.setLeftInLandscape(navLeftInLandscape);
+ }
+
+ // This method reads CMSettings.Secure.RECENTS_LONG_PRESS_ACTIVITY
+ updateCustomRecentsLongPressHandler(false);
+ }
+ }
+
+ class DevForceNavbarObserver extends UserContentObserver {
+ DevForceNavbarObserver(Handler handler) {
+ super(handler);
+ }
+
+ @Override
+ protected void observe() {
+ super.observe();
+ ContentResolver resolver = mContext.getContentResolver();
+ resolver.registerContentObserver(CMSettings.Secure.getUriFor(
+ CMSettings.Secure.DEV_FORCE_SHOW_NAVBAR), false, this, UserHandle.USER_ALL);
+ }
+
+ @Override
+ public void update() {
+ boolean visible = CMSettings.Secure.getIntForUser(mContext.getContentResolver(),
+ CMSettings.Secure.DEV_FORCE_SHOW_NAVBAR, 0, UserHandle.USER_CURRENT) == 1;
+
+ if (visible) {
+ forceAddNavigationBar();
+ } else {
+ removeNavigationBar();
+ }
+
+ // Send a broadcast to Settings to update Key disabling when user changes
+ Intent intent = new Intent("com.cyanogenmod.action.UserChanged");
+ intent.setPackage("com.android.settings");
+ mContext.sendBroadcastAsUser(intent, new UserHandle(UserHandle.USER_CURRENT));
+ }
+ }
+
+ private void forceAddNavigationBar() {
+ // If we have no Navbar view and we should have one, create it
+ if (mNavigationBarView != null) {
+ return;
+ }
+
+ mNavigationBarView =
+ (NavigationBarView) View.inflate(mContext, R.layout.navigation_bar, null);
+
+ mNavigationBarView.setDisabledFlags(mDisabled1);
+ mNavigationBarView.setBar(this);
+ addNavigationBar();
+ }
+
// ensure quick settings is disabled until the current user makes it through the setup wizard
private boolean mUserSetup = false;
private ContentObserver mUserSetupObserver = new ContentObserver(new Handler()) {
@@ -611,6 +791,16 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
mScrimSrcModeEnabled = mContext.getResources().getBoolean(
R.bool.config_status_bar_scrim_behind_use_src);
+ ThemeConfig currentTheme = mContext.getResources().getConfiguration().themeConfig;
+ if (currentTheme != null) {
+ mCurrentTheme = (ThemeConfig)currentTheme.clone();
+ } else {
+ mCurrentTheme = ThemeConfig.getBootTheme(mContext.getContentResolver());
+ }
+
+ mStatusBarWindow = new StatusBarWindowView(mContext, null);
+ mStatusBarWindow.setService(this);
+
super.start(); // calls createAndAddWindows()
mMediaSessionManager
@@ -620,9 +810,23 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
addNavigationBar();
+ // Developer options - Force Navigation bar
+ try {
+ boolean needsNav = mWindowManagerService.needsNavigationBar();
+ if (!needsNav) {
+ mDevForceNavbarObserver = new DevForceNavbarObserver(mHandler);
+ mDevForceNavbarObserver.observe();
+ }
+ } catch (RemoteException ex) {
+ // no window manager? good luck with that
+ }
+
+ SettingsObserver observer = new SettingsObserver(mHandler);
+ observer.observe();
+
// Lastly, call to the icon policy to install/update all the icons.
mIconPolicy = new PhoneStatusBarPolicy(mContext, mCastController, mHotspotController,
- mUserInfoController, mBluetoothController);
+ mUserInfoController, mBluetoothController, mSuController);
mIconPolicy.setCurrentUserSetup(mUserSetup);
mSettingsObserver.onChange(false); // set up
@@ -635,6 +839,11 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
Settings.Global.getUriFor(SETTING_HEADS_UP_TICKER), true,
mHeadsUpObserver);
}
+
+ WallpaperManager wallpaperManager = (WallpaperManager) mContext.getSystemService(
+ Context.WALLPAPER_SERVICE);
+ mKeyguardWallpaper = wallpaperManager.getKeyguardBitmap();
+
mUnlockMethodCache = UnlockMethodCache.getInstance(mContext);
mUnlockMethodCache.addListener(this);
startKeyguard();
@@ -649,6 +858,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
notifyUserAboutHiddenNotifications();
mScreenPinningRequest = new ScreenPinningRequest(mContext);
+
+ updateCustomRecentsLongPressHandler(true);
}
// ================================================================================
@@ -659,13 +870,17 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
Resources res = context.getResources();
+ mScreenWidth = (float) context.getResources().getDisplayMetrics().widthPixels;
+ mMinBrightness = context.getResources().getInteger(
+ com.android.internal.R.integer.config_screenBrightnessDim);
+
updateDisplaySize(); // populates mDisplayMetrics
- updateResources();
+ updateResources(null);
- mStatusBarWindow = (StatusBarWindowView) View.inflate(context,
+ mStatusBarWindowContent = (FrameLayout) View.inflate(context,
R.layout.super_status_bar, null);
mStatusBarWindow.setService(this);
- mStatusBarWindow.setOnTouchListener(new View.OnTouchListener() {
+ mStatusBarWindowContent.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
checkUserAutohide(v, event);
@@ -674,17 +889,17 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
animateCollapsePanels();
}
}
- return mStatusBarWindow.onTouchEvent(event);
+ return mStatusBarWindowContent.onTouchEvent(event);
}
});
- mStatusBarView = (PhoneStatusBarView) mStatusBarWindow.findViewById(R.id.status_bar);
+ mStatusBarView = (PhoneStatusBarView) mStatusBarWindowContent.findViewById(R.id.status_bar);
mStatusBarView.setBar(this);
- PanelHolder holder = (PanelHolder) mStatusBarWindow.findViewById(R.id.panel_holder);
+ PanelHolder holder = (PanelHolder) mStatusBarWindowContent.findViewById(R.id.panel_holder);
mStatusBarView.setPanelHolder(holder);
- mNotificationPanel = (NotificationPanelView) mStatusBarWindow.findViewById(
+ mNotificationPanel = (NotificationPanelView) mStatusBarWindowContent.findViewById(
R.id.notification_panel);
mNotificationPanel.setStatusBar(this);
@@ -710,9 +925,10 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
try {
boolean showNav = mWindowManagerService.hasNavigationBar();
if (DEBUG) Log.v(TAG, "hasNavigationBar=" + showNav);
- if (showNav) {
+ if (showNav && !mRecreating) {
mNavigationBarView =
(NavigationBarView) View.inflate(context, R.layout.navigation_bar, null);
+ mNavigationBarView.updateResources(getNavbarThemedResources());
mNavigationBarView.setDisabledFlags(mDisabled1);
mNavigationBarView.setBar(this);
@@ -738,11 +954,14 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
}
mAssistManager = new AssistManager(this, context);
+ if (mNavigationBarView == null) {
+ mAssistManager.onConfigurationChanged();
+ }
// figure out which pixel-format to use for the status bar.
mPixelFormat = PixelFormat.OPAQUE;
- mStackScroller = (NotificationStackScrollLayout) mStatusBarWindow.findViewById(
+ mStackScroller = (NotificationStackScrollLayout) mStatusBarWindowContent.findViewById(
R.id.notification_stack_scroller);
mStackScroller.setLongPressListener(getNotificationLongClicker());
mStackScroller.setPhoneStatusBar(this);
@@ -775,13 +994,13 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
mStackScroller.setDismissView(mDismissView);
mExpandedContents = mStackScroller;
- mBackdrop = (BackDropView) mStatusBarWindow.findViewById(R.id.backdrop);
+ mBackdrop = (BackDropView) mStatusBarWindowContent.findViewById(R.id.backdrop);
mBackdropFront = (ImageView) mBackdrop.findViewById(R.id.backdrop_front);
mBackdropBack = (ImageView) mBackdrop.findViewById(R.id.backdrop_back);
- ScrimView scrimBehind = (ScrimView) mStatusBarWindow.findViewById(R.id.scrim_behind);
- ScrimView scrimInFront = (ScrimView) mStatusBarWindow.findViewById(R.id.scrim_in_front);
- View headsUpScrim = mStatusBarWindow.findViewById(R.id.heads_up_scrim);
+ ScrimView scrimBehind = (ScrimView) mStatusBarWindowContent.findViewById(R.id.scrim_behind);
+ ScrimView scrimInFront = (ScrimView) mStatusBarWindowContent.findViewById(R.id.scrim_in_front);
+ View headsUpScrim = mStatusBarWindowContent.findViewById(R.id.heads_up_scrim);
mScrimController = new ScrimController(scrimBehind, scrimInFront, headsUpScrim,
mScrimSrcModeEnabled);
mHeadsUpManager.addListener(mScrimController);
@@ -790,17 +1009,17 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
mStatusBarView.setScrimController(mScrimController);
mDozeScrimController = new DozeScrimController(mScrimController, context);
- mHeader = (StatusBarHeaderView) mStatusBarWindow.findViewById(R.id.header);
+ mHeader = (StatusBarHeaderView) mStatusBarWindowContent.findViewById(R.id.header);
mHeader.setActivityStarter(this);
- mKeyguardStatusBar = (KeyguardStatusBarView) mStatusBarWindow.findViewById(R.id.keyguard_header);
- mKeyguardStatusView = mStatusBarWindow.findViewById(R.id.keyguard_status_view);
+ mKeyguardStatusBar = (KeyguardStatusBarView) mStatusBarWindowContent.findViewById(R.id.keyguard_header);
+ mKeyguardStatusView = mStatusBarWindowContent.findViewById(R.id.keyguard_status_view);
mKeyguardBottomArea =
- (KeyguardBottomAreaView) mStatusBarWindow.findViewById(R.id.keyguard_bottom_area);
+ (KeyguardBottomAreaView) mStatusBarWindowContent.findViewById(R.id.keyguard_bottom_area);
mKeyguardBottomArea.setActivityStarter(this);
mKeyguardBottomArea.setAssistManager(mAssistManager);
mKeyguardIndicationController = new KeyguardIndicationController(mContext,
- (KeyguardIndicationTextView) mStatusBarWindow.findViewById(
- R.id.keyguard_indication_text),
+ (KeyguardIndicationTextView) mStatusBarWindowContent.findViewById(
+ R.id.keyguard_indication_text),
mKeyguardBottomArea.getLockIcon());
mKeyguardBottomArea.setKeyguardIndicationController(mKeyguardIndicationController);
@@ -817,7 +1036,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
// Other icons
mLocationController = new LocationControllerImpl(mContext,
mHandlerThread.getLooper()); // will post a notification
- mBatteryController = new BatteryController(mContext);
+ mBatteryController = new BatteryController(mContext, mHandler);
mBatteryController.addStateChangedCallback(new BatteryStateChangeCallback() {
@Override
public void onPowerSaveChanged() {
@@ -830,6 +1049,10 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) {
// noop
}
+ @Override
+ public void onBatteryStyleChanged(int style, int percentMode) {
+ // noop
+ }
});
mNetworkController = new NetworkControllerImpl(mContext, mHandlerThread.getLooper());
mHotspotController = new HotspotControllerImpl(mContext);
@@ -844,6 +1067,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
mZenModeController = mVolumeComponent.getZenController();
}
mCastController = new CastControllerImpl(mContext);
+ mSuController = new SuControllerImpl(mContext);
final SignalClusterView signalCluster =
(SignalClusterView) mStatusBarView.findViewById(R.id.signal_cluster);
final SignalClusterView signalClusterKeyguard =
@@ -864,6 +1088,23 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
mNetworkController.addEmergencyListener(mHeader);
}
+ mCarrierLabel = (TextView)mStatusBarWindow.findViewById(R.id.carrier_label);
+ final boolean showCarrierLabel = mContext.getResources().getBoolean(
+ R.bool.config_showCarrierLabel);
+ mShowCarrierInPanel = showCarrierLabel && (mCarrierLabel != null);
+ if (DEBUG) Log.v(TAG, "carrierlabel=" + mCarrierLabel + " show=" + mShowCarrierInPanel);
+ if (mShowCarrierInPanel) {
+ mCarrierLabel.setVisibility(mShowCarrierInPanel ? View.VISIBLE : View.INVISIBLE);
+ }
+
+ // make sure carrier label is not covered by navigation bar
+ if (mCarrierLabel != null && mNavigationBarView != null) {
+ MarginLayoutParams mlp = (MarginLayoutParams) mCarrierLabel.getLayoutParams();
+ if (mlp != null && mlp.bottomMargin < mNavigationBarView.mBarSize) {
+ mlp.bottomMargin = mNavigationBarView.mBarSize;
+ mCarrierLabel.setLayoutParams(mlp);
+ }
+ }
mFlashlightController = new FlashlightController(mContext);
mKeyguardBottomArea.setFlashlightController(mFlashlightController);
mKeyguardBottomArea.setPhoneStatusBar(this);
@@ -876,13 +1117,15 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
mUserSwitcherController = new UserSwitcherController(mContext, mKeyguardMonitor,
mHandler);
}
+ mWeatherController = new WeatherControllerImpl(mContext);
+
mKeyguardUserSwitcher = new KeyguardUserSwitcher(mContext,
- (ViewStub) mStatusBarWindow.findViewById(R.id.keyguard_user_switcher),
+ (ViewStub) mStatusBarWindowContent.findViewById(R.id.keyguard_user_switcher),
mKeyguardStatusBar, mNotificationPanel, mUserSwitcherController);
// Set up the quick settings tile panel
- mQSPanel = (QSPanel) mStatusBarWindow.findViewById(R.id.quick_settings_panel);
+ mQSPanel = (QSDragPanel) mStatusBarWindowContent.findViewById(R.id.quick_settings_panel);
if (mQSPanel != null) {
final QSTileHost qsh = new QSTileHost(mContext, this,
mBluetoothController, mLocationController, mRotationLockController,
@@ -892,17 +1135,60 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
mSecurityController);
mQSPanel.setHost(qsh);
mQSPanel.setTiles(qsh.getTiles());
- mBrightnessMirrorController = new BrightnessMirrorController(mStatusBarWindow);
+ mBrightnessMirrorController = new BrightnessMirrorController(mStatusBarWindowContent);
mQSPanel.setBrightnessMirror(mBrightnessMirrorController);
mHeader.setQSPanel(mQSPanel);
qsh.setCallback(new QSTileHost.Callback() {
@Override
public void onTilesChanged() {
- mQSPanel.setTiles(qsh.getTiles());
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ mQSPanel.setTiles(qsh.getTiles());
+ }
+ });
+ }
+
+ @Override
+ public void setEditing(final boolean editing) {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ mQSPanel.setEditing(editing);
+ mHeader.setEditing(editing);
+ }
+ });
+ }
+
+ @Override
+ public boolean isEditing() {
+ return mQSPanel.isEditing();
+ }
+
+ @Override
+ public void goToSettingsPage() {
+ setEditing(true);
+ mHandler.postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ mQSPanel.goToSettingsPage();
+ }
+ }, 500);
}
});
}
+ // Set up the initial custom tile listener state.
+ try {
+ mCustomTileListenerService.registerAsSystemService(mContext,
+ new ComponentName(mContext.getPackageName(), getClass().getCanonicalName()),
+ UserHandle.USER_ALL);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Unable to register custom tile listener", e);
+ }
+
+ mQSPanel.getHost().setCustomTileListenerService(mCustomTileListenerService);
+
// User info. Trigger first load.
mHeader.setUserInfoController(mUserInfoController);
mKeyguardStatusBar.setUserInfoController(mUserInfoController);
@@ -910,10 +1196,15 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
mUserInfoController.reloadUserInfo();
mHeader.setBatteryController(mBatteryController);
- ((BatteryMeterView) mStatusBarView.findViewById(R.id.battery)).setBatteryController(
- mBatteryController);
+ BatteryMeterView batteryMeterView =
+ ((BatteryMeterView) mStatusBarView.findViewById(R.id.battery));
+ batteryMeterView.setBatteryController(mBatteryController);
+ batteryMeterView.setAnimationsEnabled(false);
+ ((BatteryLevelTextView) mStatusBarView.findViewById(R.id.battery_level_text))
+ .setBatteryController(mBatteryController);
mKeyguardStatusBar.setBatteryController(mBatteryController);
mHeader.setNextAlarmController(mNextAlarmController);
+ mHeader.setWeatherController(mWeatherController);
PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
mBroadcastReceiver.onReceive(mContext,
@@ -927,6 +1218,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
filter.addAction(Intent.ACTION_SCREEN_OFF);
filter.addAction(Intent.ACTION_SCREEN_ON);
+ filter.addAction(Intent.ACTION_KEYGUARD_WALLPAPER_CHANGED);
context.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, filter, null, null);
IntentFilter demoFilter = new IntentFilter();
@@ -937,6 +1229,15 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
context.registerReceiverAsUser(mDemoReceiver, UserHandle.ALL, demoFilter,
android.Manifest.permission.DUMP, null);
+ // receive broadcasts for packages
+ IntentFilter packageFilter = new IntentFilter();
+ packageFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
+ packageFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
+ packageFilter.addAction(Intent.ACTION_PACKAGE_FULLY_REMOVED);
+ packageFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+ packageFilter.addDataScheme("package");
+ context.registerReceiver(mPackageBroadcastReceiver, packageFilter);
+
// listen for USER_SETUP_COMPLETE setting (per-user)
resetUserSetupObserver();
@@ -1062,6 +1363,41 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
return mNaturalBarHeight;
}
+ private final CustomTileListenerService mCustomTileListenerService =
+ new CustomTileListenerService() {
+ @Override
+ public void onListenerConnected() {
+ //Connected
+ }
+ @Override
+ public void onCustomTilePosted(final StatusBarPanelCustomTile sbc) {
+ if (DEBUG) Log.d(TAG, "onCustomTilePosted: " + sbc.getCustomTile());
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ boolean isUpdate = mQSPanel.getHost().getCustomTileData()
+ .get(sbc.getKey()) != null;
+ if (isUpdate) {
+ mQSPanel.getHost().updateCustomTile(sbc);
+ } else {
+ mQSPanel.getHost().addCustomTile(sbc);
+ }
+ }
+ });
+ }
+
+ @Override
+ public void onCustomTileRemoved(final StatusBarPanelCustomTile sbc) {
+ if (DEBUG) Log.d(TAG, "onCustomTileRemoved: " + sbc.getCustomTile());
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ mQSPanel.getHost().removeCustomTileSysUi(sbc.getKey());
+ }
+ });
+ }
+ };
+
private View.OnClickListener mRecentsClickListener = new View.OnClickListener() {
public void onClick(View v) {
awakenDreams();
@@ -1121,14 +1457,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
private void prepareNavigationBarView() {
mNavigationBarView.reorient();
- mNavigationBarView.getRecentsButton().setOnClickListener(mRecentsClickListener);
- mNavigationBarView.getRecentsButton().setOnTouchListener(mRecentsPreloadOnTouchListener);
- mNavigationBarView.getRecentsButton().setLongClickable(true);
- mNavigationBarView.getRecentsButton().setOnLongClickListener(mLongPressBackRecentsListener);
- mNavigationBarView.getBackButton().setLongClickable(true);
- mNavigationBarView.getBackButton().setOnLongClickListener(mLongPressBackRecentsListener);
- mNavigationBarView.getHomeButton().setOnTouchListener(mHomeActionListener);
- mNavigationBarView.getHomeButton().setOnLongClickListener(mLongPressHomeListener);
+ mNavigationBarView.setListeners(mRecentsClickListener, mRecentsPreloadOnTouchListener,
+ mLongPressBackRecentsListener, mHomeActionListener, mLongPressHomeListener);
mAssistManager.onConfigurationChanged();
}
@@ -1137,11 +1467,26 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
if (DEBUG) Log.v(TAG, "addNavigationBar: about to add " + mNavigationBarView);
if (mNavigationBarView == null) return;
+ ThemeConfig newTheme = mContext.getResources().getConfiguration().themeConfig;
+ if (newTheme != null &&
+ (mCurrentTheme == null || !mCurrentTheme.equals(newTheme))) {
+ // Nevermind, this will be re-created
+ return;
+ }
+
prepareNavigationBarView();
mWindowManager.addView(mNavigationBarView, getNavigationBarLayoutParams());
}
+ private void removeNavigationBar() {
+ if (DEBUG) Log.d(TAG, "removeNavigationBar: about to remove " + mNavigationBarView);
+ if (mNavigationBarView == null) return;
+
+ mWindowManager.removeView(mNavigationBarView);
+ mNavigationBarView = null;
+ }
+
private void repositionNavigationBar() {
if (mNavigationBarView == null || !mNavigationBarView.isAttachedToWindow()) return;
@@ -1176,6 +1521,18 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
return lp;
}
+ private Resources getNavbarThemedResources() {
+ String pkgName = mCurrentTheme.getOverlayForNavBar();
+ Resources res = null;
+ try {
+ res = mContext.getPackageManager().getThemedResourcesForApplication(
+ mContext.getPackageName(), pkgName);
+ } catch (PackageManager.NameNotFoundException e) {
+ res = mContext.getResources();
+ }
+ return res;
+ }
+
public void addIcon(String slot, int index, int viewIndex, StatusBarIcon icon) {
mIconController.addSystemIcon(slot, index, viewIndex, icon);
}
@@ -1272,6 +1629,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
if (mNavigationBarView != null) {
mNavigationBarView.setLayoutDirection(layoutDirection);
}
+ mIconController.refreshAllStatusBarIcons();
}
private void updateNotificationShade() {
@@ -1485,8 +1843,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
return entry.row.getParent() instanceof NotificationStackScrollLayout;
}
- @Override
- protected void updateNotifications() {
+ private void handleUpdateNotifications() {
mNotificationData.filterAndSort();
updateNotificationShade();
@@ -1494,11 +1851,33 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
}
@Override
+ protected void updateNotifications() {
+ if (!mHandler.hasMessages(MSG_UPDATE_NOTIFICATIONS)) {
+ mHandler.sendEmptyMessage(MSG_UPDATE_NOTIFICATIONS);
+ }
+ }
+
+ @Override
protected void updateRowStates() {
super.updateRowStates();
mNotificationPanel.notifyVisibleChildrenChanged();
}
+ protected void updateCarrierLabelVisibility() {
+ if (!mShowCarrierInPanel) return;
+
+ final boolean makeVisible = mStackScroller.getVisibility() == View.VISIBLE
+ && mState != StatusBarState.KEYGUARD;
+
+ if ((mCarrierLabel.getVisibility() == View.VISIBLE) != makeVisible) {
+ if (DEBUG) {
+ Log.d(TAG, "making carrier label " + (makeVisible?"visible":"invisible"));
+ }
+
+ mCarrierLabel.setVisibility(makeVisible ? View.VISIBLE : View.INVISIBLE);
+ }
+ }
+
@Override
protected void setAreThereNotifications() {
@@ -1699,18 +2078,29 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
+ " state=" + mState);
}
- Bitmap artworkBitmap = null;
+ Bitmap backdropBitmap = null;
+
+ // apply any album artwork first
if (mMediaMetadata != null) {
- artworkBitmap = mMediaMetadata.getBitmap(MediaMetadata.METADATA_KEY_ART);
- if (artworkBitmap == null) {
- artworkBitmap = mMediaMetadata.getBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART);
+ backdropBitmap = mMediaMetadata.getBitmap(MediaMetadata.METADATA_KEY_ART);
+ if (backdropBitmap == null) {
+ backdropBitmap = mMediaMetadata.getBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART);
// might still be null
}
}
- final boolean hasArtwork = artworkBitmap != null;
+ // apply user lockscreen image
+ if (mMediaMetadata == null && backdropBitmap == null) {
+ backdropBitmap = mKeyguardWallpaper;
+ }
+
+ final boolean hasBackdrop = backdropBitmap != null;
+ mKeyguardShowingMedia = hasBackdrop;
+ if (mStatusBarWindowManager != null) {
+ mStatusBarWindowManager.setShowingMedia(mKeyguardShowingMedia);
+ }
- if ((hasArtwork || DEBUG_MEDIA_FAKE_ARTWORK)
+ if ((hasBackdrop || DEBUG_MEDIA_FAKE_ARTWORK)
&& (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED)
&& mFingerprintUnlockController.getMode()
!= FingerprintUnlockController.MODE_WAKE_AND_UNLOCK_PULSING) {
@@ -1743,7 +2133,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
mBackdropBack.setBackgroundColor(0xFFFFFFFF);
mBackdropBack.setImageDrawable(new ColorDrawable(c));
} else {
- mBackdropBack.setImageBitmap(artworkBitmap);
+ mBackdropBack.setImageBitmap(backdropBitmap);
}
if (mScrimSrcModeEnabled) {
mBackdropBack.getDrawable().mutate().setXfermode(mSrcXferMode);
@@ -1947,6 +2337,10 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
return mLeaveOpenOnKeyguardHide;
}
+ public boolean isKeyguardShowingMedia() {
+ return mKeyguardShowingMedia;
+ }
+
public boolean isQsExpanded() {
return mNotificationPanel.isQsExpanded();
}
@@ -1955,6 +2349,10 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
return mWakeUpComingFromTouch;
}
+ void setBlur(float b){
+ mStatusBarWindowManager.setBlur(b);
+ }
+
public boolean isFalsingThresholdNeeded() {
return getBarState() == StatusBarState.KEYGUARD;
}
@@ -2105,6 +2503,9 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
case MSG_LAUNCH_TRANSITION_TIMEOUT:
onLaunchTransitionTimeout();
break;
+ case MSG_UPDATE_NOTIFICATIONS:
+ handleUpdateNotifications();
+ break;
}
}
}
@@ -2295,6 +2696,98 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
}
}
+ private void adjustBrightness(int x) {
+ mBrightnessChanged = true;
+ float raw = ((float) x) / mScreenWidth;
+
+ // Add a padding to the brightness control on both sides to
+ // make it easier to reach min/max brightness
+ float padded = Math.min(1.0f - BRIGHTNESS_CONTROL_PADDING,
+ Math.max(BRIGHTNESS_CONTROL_PADDING, raw));
+ float value = (padded - BRIGHTNESS_CONTROL_PADDING) /
+ (1 - (2.0f * BRIGHTNESS_CONTROL_PADDING));
+ try {
+ IPowerManager power = IPowerManager.Stub.asInterface(
+ ServiceManager.getService("power"));
+ if (power != null) {
+ if (mAutomaticBrightness) {
+ float adj = (2 * value) - 1;
+ adj = Math.max(adj, -1);
+ adj = Math.min(adj, 1);
+ final float val = adj;
+ power.setTemporaryScreenAutoBrightnessAdjustmentSettingOverride(val);
+ AsyncTask.execute(new Runnable() {
+ public void run() {
+ Settings.System.putFloatForUser(mContext.getContentResolver(),
+ Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ, val,
+ UserHandle.USER_CURRENT);
+ }
+ });
+ } else {
+ int newBrightness = mMinBrightness + (int) Math.round(value *
+ (android.os.PowerManager.BRIGHTNESS_ON - mMinBrightness));
+ newBrightness = Math.min(newBrightness, android.os.PowerManager.BRIGHTNESS_ON);
+ newBrightness = Math.max(newBrightness, mMinBrightness);
+ final int val = newBrightness;
+ power.setTemporaryScreenBrightnessSettingOverride(val);
+ AsyncTask.execute(new Runnable() {
+ @Override
+ public void run() {
+ Settings.System.putIntForUser(mContext.getContentResolver(),
+ Settings.System.SCREEN_BRIGHTNESS, val,
+ UserHandle.USER_CURRENT);
+ }
+ });
+ }
+
+
+ }
+ } catch (RemoteException e) {
+ Log.w(TAG, "Setting Brightness failed: " + e);
+ }
+ }
+
+ private void brightnessControl(MotionEvent event) {
+ final int action = event.getAction();
+ final int x = (int) event.getRawX();
+ final int y = (int) event.getRawY();
+ if (action == MotionEvent.ACTION_DOWN) {
+ if (y < mStatusBarHeaderHeight) {
+ mLinger = 0;
+ mInitialTouchX = x;
+ mInitialTouchY = y;
+ mJustPeeked = true;
+ mHandler.removeCallbacks(mLongPressBrightnessChange);
+ mHandler.postDelayed(mLongPressBrightnessChange,
+ BRIGHTNESS_CONTROL_LONG_PRESS_TIMEOUT);
+ }
+ } else if (action == MotionEvent.ACTION_MOVE) {
+ if (y < mStatusBarHeaderHeight && mJustPeeked) {
+ if (mLinger > BRIGHTNESS_CONTROL_LINGER_THRESHOLD) {
+ adjustBrightness(x);
+ } else {
+ final int xDiff = Math.abs(x - mInitialTouchX);
+ final int yDiff = Math.abs(y - mInitialTouchY);
+ final int touchSlop = ViewConfiguration.get(mContext).getScaledTouchSlop();
+ if (xDiff > yDiff) {
+ mLinger++;
+ }
+ if (xDiff > touchSlop || yDiff > touchSlop) {
+ mHandler.removeCallbacks(mLongPressBrightnessChange);
+ }
+ }
+ } else {
+ if (y > mStatusBarHeaderHeight) {
+ mJustPeeked = false;
+ }
+ mHandler.removeCallbacks(mLongPressBrightnessChange);
+ }
+ } else if (action == MotionEvent.ACTION_UP
+ || action == MotionEvent.ACTION_CANCEL) {
+ mHandler.removeCallbacks(mLongPressBrightnessChange);
+ }
+ }
+
public boolean interceptTouchEvent(MotionEvent event) {
if (DEBUG_GESTURES) {
if (event.getActionMasked() != MotionEvent.ACTION_MOVE) {
@@ -2321,16 +2814,29 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
mGestureRec.add(event);
}
+ if (mBrightnessControl) {
+ brightnessControl(event);
+ if ((mDisabled1 & StatusBarManager.DISABLE_EXPAND) != 0) {
+ return true;
+ }
+ }
+
+ final boolean upOrCancel =
+ event.getAction() == MotionEvent.ACTION_UP ||
+ event.getAction() == MotionEvent.ACTION_CANCEL;
if (mStatusBarWindowState == WINDOW_STATE_SHOWING) {
- final boolean upOrCancel =
- event.getAction() == MotionEvent.ACTION_UP ||
- event.getAction() == MotionEvent.ACTION_CANCEL;
if (upOrCancel && !mExpandedVisible) {
setInteracting(StatusBarManager.WINDOW_STATUS_BAR, false);
} else {
setInteracting(StatusBarManager.WINDOW_STATUS_BAR, true);
}
}
+ if (mBrightnessChanged && upOrCancel) {
+ mBrightnessChanged = false;
+ if (mJustPeeked && mExpandedVisible) {
+ mNotificationPanel.fling(10, false);
+ }
+ }
return false;
}
@@ -2813,7 +3319,9 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
private void addStatusBarWindow() {
makeStatusBarView();
- mStatusBarWindowManager = new StatusBarWindowManager(mContext);
+ mStatusBarWindow.addContent(mStatusBarWindowContent);
+ mStatusBarWindowManager = new StatusBarWindowManager(mContext, mKeyguardMonitor);
+ mStatusBarWindowManager.setShowingMedia(mKeyguardShowingMedia);
mStatusBarWindowManager.add(mStatusBarWindow, getStatusBarHeight());
}
@@ -2955,6 +3463,24 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
if (DEBUG_MEDIA_FAKE_ARTWORK) {
updateMediaMetaData(true);
}
+ } else if (Intent.ACTION_KEYGUARD_WALLPAPER_CHANGED.equals(action)) {
+ WallpaperManager wm = (WallpaperManager) mContext.getSystemService(
+ Context.WALLPAPER_SERVICE);
+ mKeyguardWallpaper = wm.getKeyguardBitmap();
+ updateMediaMetaData(true);
+ }
+ }
+ };
+
+ private BroadcastReceiver mPackageBroadcastReceiver = new BroadcastReceiver() {
+ public void onReceive(Context context, Intent intent) {
+ if (DEBUG) Log.v(TAG, "onReceive: " + intent);
+ String action = intent.getAction();
+ if (Intent.ACTION_PACKAGE_ADDED.equals(action) ||
+ Intent.ACTION_PACKAGE_CHANGED.equals(action) ||
+ Intent.ACTION_PACKAGE_FULLY_REMOVED.equals(action) ||
+ Intent.ACTION_PACKAGE_REMOVED.equals(action)) {
+ updateCustomRecentsLongPressHandler(true);
}
}
};
@@ -2995,7 +3521,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
}
updateDisplaySize(); // populates mDisplayMetrics
- updateResources();
+ updateResources(newConfig);
repositionNavigationBar();
updateRowStates();
mIconController.updateResources();
@@ -3007,12 +3533,23 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
public void userSwitched(int newUserId) {
super.userSwitched(newUserId);
if (MULTIUSER_DEBUG) mNotificationPanelDebugText.setText("USER " + newUserId);
+ WallpaperManager wm = (WallpaperManager)
+ mContext.getSystemService(Context.WALLPAPER_SERVICE);
+ mKeyguardWallpaper = null;
+ wm.forgetLoadedKeyguardWallpaper();
+
animateCollapsePanels();
updatePublicMode();
updateNotifications();
resetUserSetupObserver();
setControllerUsers();
mAssistManager.onUserSwitched(newUserId);
+
+ mKeyguardWallpaper = wm.getKeyguardBitmap();
+ updateMediaMetaData(true);
+ if (mNavigationBarView != null) {
+ mNavigationBarView.updateSettings();
+ }
}
private void setControllerUsers() {
@@ -3022,6 +3559,9 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
if (mSecurityController != null) {
mSecurityController.onUserSwitched(mCurrentUserId);
}
+ if (mBatteryController != null) {
+ mBatteryController.setUserId(mCurrentUserId);
+ }
}
private void resetUserSetupObserver() {
@@ -3032,6 +3572,128 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
mUserSetupObserver, mCurrentUserId);
}
+ private static void copyNotifications(ArrayList<Pair<String, StatusBarNotification>> dest,
+ NotificationData source) {
+ int N = source.size();
+ for (int i = 0; i < N; i++) {
+ NotificationData.Entry entry = source.get(i);
+ dest.add(Pair.create(entry.key, entry.notification));
+ }
+ }
+
+ private void removeSignalCallbacks(NetworkController networkController) {
+ final SignalClusterView signalCluster =
+ (SignalClusterView) mStatusBarView.findViewById(R.id.signal_cluster);
+ final SignalClusterView signalClusterKeyguard =
+ (SignalClusterView) mKeyguardStatusBar.findViewById(R.id.signal_cluster);
+ final SignalClusterView signalClusterQs =
+ (SignalClusterView) mHeader.findViewById(R.id.signal_cluster);
+ networkController.removeSignalCallback(signalCluster);
+ networkController.removeSignalCallback(signalClusterKeyguard);
+ networkController.removeSignalCallback(signalClusterQs);
+ }
+
+ private void recreateStatusBar() {
+ mRecreating = true;
+
+ if (mNetworkController != null) {
+ removeSignalCallbacks(mNetworkController);
+ }
+
+ mStatusBarWindow.removeContent(mStatusBarWindowContent);
+ mStatusBarWindow.clearDisappearingChildren();
+
+ RankingMap rankingMap = mNotificationData.getRankingMap();
+ // extract icons from the soon-to-be recreated viewgroup.
+ /*
+ int nIcons = mStatusIcons != null ? mStatusIcons.getChildCount() : 0;
+ ArrayList<StatusBarIcon> icons = new ArrayList<StatusBarIcon>(nIcons);
+ ArrayList<String> iconSlots = new ArrayList<String>(nIcons);
+ for (int i = 0; i < nIcons; i++) {
+ StatusBarIconView iconView = (StatusBarIconView)mStatusIcons.getChildAt(i);
+ icons.add(iconView.getStatusBarIcon());
+ iconSlots.add(iconView.getStatusBarSlot());
+ }
+ */
+
+ removeAllViews(mStatusBarWindowContent);
+
+ // extract notifications.
+ int nNotifs = mNotificationData.size();
+ ArrayList<Pair<String, StatusBarNotification>> notifications =
+ new ArrayList<Pair<String, StatusBarNotification>>(nNotifs);
+ copyNotifications(notifications, mNotificationData);
+ mNotificationData.clear();
+
+ makeStatusBarView();
+ repositionNavigationBar();
+
+ // recreate StatusBarIconViews.
+ /*
+ for (int i = 0; i < nIcons; i++) {
+ StatusBarIcon icon = icons.get(i);
+ String slot = iconSlots.get(i);
+ addIcon(slot, i, i, icon);
+ }
+ */
+
+ // recreate notifications.
+ for (int i = 0; i < nNotifs; i++) {
+ Pair<String, StatusBarNotification> notifData = notifications.get(i);
+ addNotificationViews(createNotificationViews(notifData.second), rankingMap);
+ }
+ mNotificationData.filterAndSort();
+
+ setAreThereNotifications();
+
+ mStatusBarWindow.addContent(mStatusBarWindowContent);
+
+ checkBarModes();
+
+ // Stop the command queue until the new status bar container settles and has a layout pass
+ mCommandQueue.pause();
+
+ if (mCustomTileListenerService != null) {
+ try {
+ mCustomTileListenerService.unregisterAsSystemService();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Unable to unregister custom tile listener", e);
+ }
+ }
+
+ mQSPanel.getHost().setCustomTileListenerService(null);
+
+ mStatusBarWindow.requestLayout();
+ mStatusBarWindow.getViewTreeObserver().addOnGlobalLayoutListener(
+ new ViewTreeObserver.OnGlobalLayoutListener() {
+ @Override
+ public void onGlobalLayout() {
+ mStatusBarWindow.getViewTreeObserver().removeOnGlobalLayoutListener(this);
+ mCommandQueue.resume();
+ mRecreating = false;
+ }
+ });
+ // restart the keyguard so it picks up the newly created ScrimController
+ startKeyguard();
+
+ // if the keyguard was showing while this change occurred we'll need to do some extra work
+ if (mState == StatusBarState.KEYGUARD) {
+ // this will make sure the keyguard is showing
+ showKeyguard();
+ }
+ }
+
+ private void removeAllViews(ViewGroup parent) {
+ int N = parent.getChildCount();
+ for (int i = 0; i < N; i++) {
+ View child = parent.getChildAt(i);
+ if (child instanceof ViewGroup) {
+ removeAllViews((ViewGroup) child);
+ }
+ }
+ parent.removeAllViews();
+ }
+
/**
* Reload some of our resources when the configuration changes.
*
@@ -3039,7 +3701,19 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
* should, but getting that smooth is tough. Someday we'll fix that. In the
* meantime, just update the things that we know change.
*/
- void updateResources() {
+ void updateResources(Configuration newConfig) {
+ // detect theme change.
+ ThemeConfig newTheme = newConfig != null ? newConfig.themeConfig : null;
+ final boolean updateStatusBar = shouldUpdateStatusbar(mCurrentTheme, newTheme);
+ final boolean updateNavBar = shouldUpdateNavbar(mCurrentTheme, newTheme);
+ if (newTheme != null) mCurrentTheme = (ThemeConfig) newTheme.clone();
+ if (updateStatusBar) {
+ mContext.recreateTheme();
+ recreateStatusBar();
+ } else {
+ loadDimens();
+ }
+
// Update the quick setting tiles
if (mQSPanel != null) {
mQSPanel.updateResources();
@@ -3053,6 +3727,53 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
if (mBrightnessMirrorController != null) {
mBrightnessMirrorController.updateResources();
}
+
+ if (mNavigationBarView != null && updateNavBar) {
+ mNavigationBarView.updateResources(getNavbarThemedResources());
+ }
+ }
+
+ /**
+ * Determines if we need to recreate the status bar due to a theme change. We currently
+ * check if the overlay for the status bar, fonts, or icons, or forced update count have
+ * changed.
+ *
+ * @param oldTheme
+ * @param newTheme
+ * @return True if we should recreate the status bar
+ */
+ private boolean shouldUpdateStatusbar(ThemeConfig oldTheme, ThemeConfig newTheme) {
+ // no newTheme, so no need to update status bar
+ if (newTheme == null) return false;
+
+ final String overlay = newTheme.getOverlayForStatusBar();
+ final String icons = newTheme.getIconPackPkgName();
+ final String fonts = newTheme.getFontPkgName();
+
+ return oldTheme == null ||
+ (overlay != null && !overlay.equals(oldTheme.getOverlayForStatusBar()) ||
+ (fonts != null && !fonts.equals(oldTheme.getFontPkgName())) ||
+ (icons != null && !icons.equals(oldTheme.getIconPackPkgName())) ||
+ newTheme.getLastThemeChangeRequestType() == RequestType.THEME_UPDATED);
+ }
+
+ /**
+ * Determines if we need to update the navbar resources due to a theme change. We currently
+ * check if the overlay for the navbar, or request type is {@link RequestType.THEME_UPDATED}.
+ *
+ * @param oldTheme
+ * @param newTheme
+ * @return True if we should update the navbar
+ */
+ private boolean shouldUpdateNavbar(ThemeConfig oldTheme, ThemeConfig newTheme) {
+ // no newTheme, so no need to update navbar
+ if (newTheme == null) return false;
+
+ final String overlay = newTheme.getOverlayForNavBar();
+
+ return oldTheme == null ||
+ (overlay != null && !overlay.equals(oldTheme.getOverlayForNavBar()) ||
+ newTheme.getLastThemeChangeRequestType() == RequestType.THEME_UPDATED);
}
protected void loadDimens() {
@@ -3066,6 +3787,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
mKeyguardMaxNotificationCount = res.getInteger(R.integer.keyguard_max_notification_count);
+ mStatusBarHeaderHeight = res.getDimensionPixelSize(R.dimen.status_bar_header_height);
+
if (DEBUG) Log.v(TAG, "updateResources");
}
@@ -3207,7 +3930,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
@Override
public boolean shouldDisableNavbarGestures() {
- return !isDeviceProvisioned() || (mDisabled1 & StatusBarManager.DISABLE_SEARCH) != 0;
+ return !isDeviceProvisioned() || (mDisabled1 & StatusBarManager.DISABLE_SEARCH) != 0
+ || (mNavigationBarView != null && mNavigationBarView.isInEditMode());
}
public void postStartActivityDismissingKeyguard(final PendingIntent intent) {
@@ -3566,6 +4290,10 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
}
}
+ boolean isSecure() {
+ return mStatusBarKeyguardViewManager != null && mStatusBarKeyguardViewManager.isSecure();
+ }
+
public long calculateGoingToFullShadeDelay() {
return mKeyguardFadingAwayDelay + mKeyguardFadingAwayDuration;
}
@@ -3646,6 +4374,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
updateStackScrollerState(goingToFullShade);
updateNotifications();
checkBarModes();
+ updateCarrierLabelVisibility();
updateMediaMetaData(false);
mKeyguardMonitor.notifyKeyguardState(mStatusBarKeyguardViewManager.isShowing(),
mStatusBarKeyguardViewManager.isSecure());
@@ -3727,7 +4456,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
}
private void showBouncer() {
- if (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED) {
+ if (!mRecreating &&
+ (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED)) {
mWaitingForKeyguardExit = mStatusBarKeyguardViewManager.isShowing();
mStatusBarKeyguardViewManager.dismiss();
}
@@ -3800,16 +4530,12 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
mKeyguardIndicationController.hideTransientIndicationDelayed(HINT_RESET_DELAY_MS);
}
- public void onCameraHintStarted() {
- mKeyguardIndicationController.showTransientIndication(R.string.camera_hint);
+ public void onCameraHintStarted(String hint) {
+ mKeyguardIndicationController.showTransientIndication(hint);
}
- public void onVoiceAssistHintStarted() {
- mKeyguardIndicationController.showTransientIndication(R.string.voice_hint);
- }
-
- public void onPhoneHintStarted() {
- mKeyguardIndicationController.showTransientIndication(R.string.phone_hint);
+ public void onLeftHintStarted(String hint) {
+ mKeyguardIndicationController.showTransientIndication(hint);
}
public void onTrackingStopped(boolean expand) {
@@ -3970,7 +4696,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
private void vibrateForCameraGesture() {
// Make sure to pass -1 for repeat so VibratorService doesn't stop us when going to sleep.
- mVibrator.vibrate(new long[] { 0, 750L }, -1 /* repeat */);
+ mVibrator.vibrate(new long[] { 0, 250L }, -1 /* repeat */);
}
public void onScreenTurnedOn() {
@@ -3994,6 +4720,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
private void handleLongPressBackRecents(View v) {
try {
boolean sendBackLongPress = false;
+ boolean hijackRecentsLongPress = false;
IActivityManager activityManager = ActivityManagerNative.getDefault();
boolean isAccessiblityEnabled = mAccessibilityManager.isEnabled();
if (activityManager.isInLockTaskMode() && !isAccessiblityEnabled) {
@@ -4004,17 +4731,23 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
activityManager.stopLockTaskModeOnCurrent();
// When exiting refresh disabled flags.
mNavigationBarView.setDisabledFlags(mDisabled1, true);
- } else if ((v.getId() == R.id.back)
+ } else if (NavbarEditor.NAVBAR_BACK.equals(v.getTag())
&& !mNavigationBarView.getRecentsButton().isPressed()) {
// If we aren't pressing recents right now then they presses
// won't be together, so send the standard long-press action.
sendBackLongPress = true;
+ } else if (NavbarEditor.NAVBAR_RECENT.equals(v.getTag())
+ && !activityManager.isInLockTaskMode()) {
+ hijackRecentsLongPress = true;
}
mLastLockToAppLongPress = time;
} else {
// If this is back still need to handle sending the long-press event.
- if (v.getId() == R.id.back) {
+ if (NavbarEditor.NAVBAR_BACK.equals(v.getTag())) {
sendBackLongPress = true;
+ } else if (NavbarEditor.NAVBAR_RECENT.equals(v.getTag())
+ && !activityManager.isInLockTaskMode()) {
+ hijackRecentsLongPress = true;
} else if (isAccessiblityEnabled && activityManager.isInLockTaskMode()) {
// When in accessibility mode a long press that is recents (not back)
// should stop lock task.
@@ -4028,11 +4761,201 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
keyButtonView.sendEvent(KeyEvent.ACTION_DOWN, KeyEvent.FLAG_LONG_PRESS);
keyButtonView.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_LONG_CLICKED);
}
+
+ if (hijackRecentsLongPress) {
+ // If there is a user-selected, registered handler for the
+ // recents long press, start the Intent. Otherwise,
+ // perform the default action, which is last app switching.
+
+ // Copy it so the value doesn't change between now and when the activity is started.
+ ComponentName customRecentsLongPressHandler = mCustomRecentsLongPressHandler;
+ if (customRecentsLongPressHandler != null) {
+ startCustomRecentsLongPressActivity(customRecentsLongPressHandler);
+ } else {
+ ActionUtils.switchToLastApp(mContext, mCurrentUserId);
+ }
+ }
} catch (RemoteException e) {
Log.d(TAG, "Unable to reach activity manager", e);
}
}
+ protected View.OnTouchListener mRecentsPreloadOnTouchListener = new View.OnTouchListener() {
+ @Override
+ public boolean onTouch(View v, MotionEvent event) {
+ int action = event.getAction() & MotionEvent.ACTION_MASK;
+
+ // Handle Document switcher
+ // Additional optimization when we have software system buttons - start loading the recent
+ // tasks on touch down
+ if (action == MotionEvent.ACTION_DOWN) {
+ preloadRecents();
+ } else if (action == MotionEvent.ACTION_CANCEL) {
+ cancelPreloadingRecents();
+ } else if (action == MotionEvent.ACTION_UP) {
+ if (!v.isPressed()) {
+ cancelPreloadingRecents();
+ }
+ }
+
+ // Handle custom recents long press
+ if (action == MotionEvent.ACTION_CANCEL ||
+ action == MotionEvent.ACTION_UP) {
+ cleanupCustomRecentsLongPressHandler();
+ }
+ return false;
+ }
+ };
+
+ /**
+ * If a custom Recents Long Press activity was dispatched, then the certain
+ * handlers need to be cleaned up after the event ends.
+ */
+ private void cleanupCustomRecentsLongPressHandler() {
+ if (mCustomRecentsLongPressed) {
+ mNavigationBarView.setSlippery(false);
+ }
+ mCustomRecentsLongPressed = false;
+ }
+
+ /**
+ * An ACTION_RECENTS_LONG_PRESS intent was received, and a custom handler is
+ * set and points to a valid app. Start this activity.
+ */
+ private void startCustomRecentsLongPressActivity(ComponentName customComponentName) {
+ Intent intent = new Intent(cyanogenmod.content.Intent.ACTION_RECENTS_LONG_PRESS);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
+
+ // Include the package name of the app currently in the foreground
+ IActivityManager am = ActivityManagerNative.getDefault();
+ List<ActivityManager.RecentTaskInfo> recentTasks = null;
+ try {
+ recentTasks = am.getRecentTasks(
+ 1, ActivityManager.RECENT_WITH_EXCLUDED, UserHandle.myUserId());
+ } catch (RemoteException e) {
+ Log.e(TAG, "Cannot get recent tasks", e);
+ }
+ if (recentTasks != null && recentTasks.size() > 0) {
+ String pkgName = recentTasks.get(0).baseIntent.getComponent().getPackageName();
+ intent.putExtra(Intent.EXTRA_CURRENT_PACKAGE_NAME, pkgName);
+ }
+
+ intent.setComponent(customComponentName);
+ try {
+ // Allow the touch event to continue into the new activity.
+ mNavigationBarView.setSlippery(true);
+ mCustomRecentsLongPressed = true;
+
+ mContext.startActivityAsUser(intent, new UserHandle(UserHandle.USER_CURRENT));
+
+ } catch (ActivityNotFoundException e) {
+ Log.e(TAG, "Cannot start activity", e);
+
+ // If the activity failed to launch, clean up
+ cleanupCustomRecentsLongPressHandler();
+ }
+ }
+
+ /**
+ * Get component name for the recent long press setting. Null means default switch to last app.
+ *
+ * Note: every time packages changed, the setting must be re-evaluated. This is to check that the
+ * component was not uninstalled or disabled.
+ */
+ private void updateCustomRecentsLongPressHandler(boolean scanPackages) {
+ // scanPackages should be true when the PhoneStatusBar is starting for
+ // the first time, and when any package activity occurred.
+ if (scanPackages) {
+ updateCustomRecentsLongPressCandidates();
+ }
+
+ String componentString = CMSettings.Secure.getString(mContext.getContentResolver(),
+ CMSettings.Secure.RECENTS_LONG_PRESS_ACTIVITY);
+ if (componentString == null) {
+ mCustomRecentsLongPressHandler = null;
+ return;
+ }
+
+ ComponentName customComponentName = ComponentName.unflattenFromString(componentString);
+ synchronized (mCustomRecentsLongPressHandlerCandidates) {
+ for (ComponentName candidate : mCustomRecentsLongPressHandlerCandidates) {
+ if (candidate.equals(customComponentName)) {
+ // Found match
+ mCustomRecentsLongPressHandler = customComponentName;
+
+ return;
+ }
+ }
+
+ // Did not find match, probably because the selected application has
+ // now been uninstalled for some reason. Since user-selected app is
+ // still saved inside Settings, PhoneStatusBar should fall back to
+ // the default for now. (We will update this either when the
+ // package is reinstalled or when the user selects another Setting.)
+ mCustomRecentsLongPressHandler = null;
+ }
+ }
+
+ /**
+ * Updates the cache of Recents Long Press applications.
+ *
+ * These applications must:
+ * - handle the cyanogenmod.contentIntent.ACTION_RECENTS_LONG_PRESS
+ * (which is permissions protected); and
+ * - not be disabled by the user or the system.
+ *
+ * More than one handler can be a candidate. When the action is invoked,
+ * the user setting (stored in CMSettings.Secure) is consulted.
+ */
+ private void updateCustomRecentsLongPressCandidates() {
+ synchronized (mCustomRecentsLongPressHandlerCandidates) {
+ mCustomRecentsLongPressHandlerCandidates.clear();
+
+ PackageManager pm = mContext.getPackageManager();
+ Intent intent = new Intent(cyanogenmod.content.Intent.ACTION_RECENTS_LONG_PRESS);
+
+ // Search for all apps that can handle ACTION_RECENTS_LONG_PRESS
+ List<ResolveInfo> activities = pm.queryIntentActivities(intent,
+ PackageManager.MATCH_DEFAULT_ONLY);
+ for (ResolveInfo info : activities) {
+ // Only cache packages that are not disabled
+ int packageState = mContext.getPackageManager().getApplicationEnabledSetting(
+ info.activityInfo.packageName);
+
+ if (packageState != PackageManager.COMPONENT_ENABLED_STATE_DISABLED &&
+ packageState != PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER) {
+
+ mCustomRecentsLongPressHandlerCandidates.add(
+ new ComponentName(info.activityInfo.packageName, info.activityInfo.name));
+ }
+
+ }
+ }
+ }
+
+ private ActivityManager.RunningTaskInfo getLastTask(final ActivityManager am) {
+ final String defaultHomePackage = resolveCurrentLauncherPackage();
+ List<ActivityManager.RunningTaskInfo> tasks = am.getRunningTasks(5);
+
+ for (int i = 1; i < tasks.size(); i++) {
+ String packageName = tasks.get(i).topActivity.getPackageName();
+ if (!packageName.equals(defaultHomePackage)
+ && !packageName.equals(mContext.getPackageName())) {
+ return tasks.get(i);
+ }
+ }
+
+ return null;
+ }
+
+ private String resolveCurrentLauncherPackage() {
+ final Intent launcherIntent = new Intent(Intent.ACTION_MAIN)
+ .addCategory(Intent.CATEGORY_HOME);
+ final PackageManager pm = mContext.getPackageManager();
+ final ResolveInfo launcherInfo = pm.resolveActivity(launcherIntent, 0);
+ return launcherInfo.activityInfo.packageName;
+ }
+
// Recents
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
index fa9c4bb..adba01f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -26,12 +26,15 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.UserInfo;
+import android.database.ContentObserver;
import android.media.AudioManager;
+import android.net.Uri;
import android.os.Handler;
import android.os.IRemoteCallback;
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
+import android.provider.Settings;
import android.provider.Settings.Global;
import android.telecom.TelecomManager;
import android.util.Log;
@@ -46,6 +49,9 @@ import com.android.systemui.statusbar.policy.CastController;
import com.android.systemui.statusbar.policy.CastController.CastDevice;
import com.android.systemui.statusbar.policy.HotspotController;
import com.android.systemui.statusbar.policy.UserInfoController;
+import com.android.systemui.statusbar.policy.SuController;
+
+import cyanogenmod.providers.CMSettings;
/**
* This class contains all of the policy about which icons are installed in the status
@@ -64,6 +70,7 @@ public class PhoneStatusBarPolicy implements Callback {
private static final String SLOT_VOLUME = "volume";
private static final String SLOT_ALARM_CLOCK = "alarm_clock";
private static final String SLOT_MANAGED_PROFILE = "managed_profile";
+ private static final String SLOT_SU = "su";
private final Context mContext;
private final StatusBarManager mService;
@@ -72,6 +79,8 @@ public class PhoneStatusBarPolicy implements Callback {
private final HotspotController mHotspot;
private final AlarmManager mAlarmManager;
private final UserInfoController mUserInfoController;
+ private boolean mAlarmIconVisible;
+ private final SuController mSuController;
// Assume it's all good unless we hear otherwise. We don't always seem
// to get broadcasts that it *is* there.
@@ -118,7 +127,7 @@ public class PhoneStatusBarPolicy implements Callback {
};
public PhoneStatusBarPolicy(Context context, CastController cast, HotspotController hotspot,
- UserInfoController userInfoController, BluetoothController bluetooth) {
+ UserInfoController userInfoController, BluetoothController bluetooth, SuController su) {
mContext = context;
mCast = cast;
mHotspot = hotspot;
@@ -127,6 +136,7 @@ public class PhoneStatusBarPolicy implements Callback {
mService = (StatusBarManager) context.getSystemService(Context.STATUS_BAR_SERVICE);
mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
mUserInfoController = userInfoController;
+ mSuController = su;
// listen for broadcasts
IntentFilter filter = new IntentFilter();
@@ -154,6 +164,10 @@ public class PhoneStatusBarPolicy implements Callback {
// Alarm clock
mService.setIcon(SLOT_ALARM_CLOCK, R.drawable.stat_sys_alarm, 0, null);
mService.setIconVisibility(SLOT_ALARM_CLOCK, false);
+ mAlarmIconObserver.onChange(true);
+ mContext.getContentResolver().registerContentObserver(
+ CMSettings.System.getUriFor(CMSettings.System.SHOW_ALARM_ICON),
+ false, mAlarmIconObserver);
// zen
mService.setIcon(SLOT_ZEN, R.drawable.stat_sys_zen_important, 0, null);
@@ -175,12 +189,31 @@ public class PhoneStatusBarPolicy implements Callback {
mService.setIconVisibility(SLOT_HOTSPOT, mHotspot.isHotspotEnabled());
mHotspot.addCallback(mHotspotCallback);
+ // su
+ mService.setIcon(SLOT_SU, R.drawable.stat_sys_su, 0, null);
+ mService.setIconVisibility(SLOT_SU, false);
+ mSuController.addCallback(mSuCallback);
+
// managed profile
mService.setIcon(SLOT_MANAGED_PROFILE, R.drawable.stat_sys_managed_profile_status, 0,
mContext.getString(R.string.accessibility_managed_profile));
mService.setIconVisibility(SLOT_MANAGED_PROFILE, false);
}
+ private ContentObserver mAlarmIconObserver = new ContentObserver(null) {
+ @Override
+ public void onChange(boolean selfChange, Uri uri) {
+ mAlarmIconVisible = CMSettings.System.getInt(mContext.getContentResolver(),
+ CMSettings.System.SHOW_ALARM_ICON, 1) == 1;
+ updateAlarm();
+ }
+
+ @Override
+ public void onChange(boolean selfChange) {
+ onChange(selfChange, null);
+ }
+ };
+
public void setZenMode(int zen) {
mZen = zen;
updateVolumeZen();
@@ -192,7 +225,7 @@ public class PhoneStatusBarPolicy implements Callback {
final boolean zenNone = mZen == Global.ZEN_MODE_NO_INTERRUPTIONS;
mService.setIcon(SLOT_ALARM_CLOCK, zenNone ? R.drawable.stat_sys_alarm_dim
: R.drawable.stat_sys_alarm, 0, null);
- mService.setIconVisibility(SLOT_ALARM_CLOCK, mCurrentUserSetup && hasAlarm);
+ mService.setIconVisibility(SLOT_ALARM_CLOCK, mCurrentUserSetup && hasAlarm && mAlarmIconVisible);
}
private final void updateSimState(Intent intent) {
@@ -404,6 +437,10 @@ public class PhoneStatusBarPolicy implements Callback {
}
};
+ private void updateSu() {
+ mService.setIconVisibility(SLOT_SU, mSuController.hasActiveSessions());
+ }
+
private final CastController.Callback mCastCallback = new CastController.Callback() {
@Override
public void onCastDevicesChanged() {
@@ -425,4 +462,12 @@ public class PhoneStatusBarPolicy implements Callback {
mCurrentUserSetup = userSetup;
updateAlarm();
}
+
+ private final SuController.Callback mSuCallback = new SuController.Callback() {
+ @Override
+ public void onSuSessionsChanged() {
+ updateSu();
+ }
+ };
+
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarTransitions.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarTransitions.java
index fb1addf..bb3095e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarTransitions.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarTransitions.java
@@ -36,7 +36,10 @@ public final class PhoneStatusBarTransitions extends BarTransitions {
private Animator mCurrentAnimation;
public PhoneStatusBarTransitions(PhoneStatusBarView view) {
- super(view, R.drawable.status_background);
+ super(view, R.drawable.status_background, R.color.status_bar_background_opaque,
+ R.color.status_bar_background_semi_transparent,
+ R.color.status_bar_background_transparent,
+ com.android.internal.R.color.battery_saver_mode_color);
mView = view;
final Resources res = mView.getContext().getResources();
mIconAlphaWhenOpaque = res.getFraction(R.dimen.status_bar_icon_drawing_alpha, 1, 1);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
index c0887ca..3b068d6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
@@ -193,6 +193,7 @@ public class PhoneStatusBarView extends PanelBar {
super.panelExpansionChanged(panel, frac, expanded);
mPanelFraction = frac;
updateScrimFraction();
+ mBar.setBlur(frac);
}
private void updateScrimFraction() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
index e66c63b..b6bb995 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
@@ -16,15 +16,27 @@
package com.android.systemui.statusbar.phone;
+<<<<<<< HEAD
+import android.app.ActivityManager;
+import android.content.ComponentName;
+=======
import android.app.PendingIntent;
+>>>>>>> 888ef59df9262e1308d383fb56b8d077fb4170d7
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
+import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Process;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.text.TextUtils;
import android.util.Log;
+import com.android.internal.logging.MetricsLogger;
+import android.widget.RemoteViews;
import com.android.systemui.R;
import com.android.systemui.qs.QSTile;
import com.android.systemui.qs.tiles.AirplaneModeTile;
@@ -32,13 +44,16 @@ import com.android.systemui.qs.tiles.BluetoothTile;
import com.android.systemui.qs.tiles.CastTile;
import com.android.systemui.qs.tiles.CellularTile;
import com.android.systemui.qs.tiles.ColorInversionTile;
+import com.android.systemui.qs.tiles.CustomQSTile;
import com.android.systemui.qs.tiles.DndTile;
+import com.android.systemui.qs.tiles.EditTile;
import com.android.systemui.qs.tiles.FlashlightTile;
import com.android.systemui.qs.tiles.HotspotTile;
import com.android.systemui.qs.tiles.IntentTile;
import com.android.systemui.qs.tiles.LocationTile;
import com.android.systemui.qs.tiles.RotationLockTile;
import com.android.systemui.qs.tiles.WifiTile;
+import com.android.systemui.statusbar.CustomTileData;
import com.android.systemui.statusbar.policy.BluetoothController;
import com.android.systemui.statusbar.policy.CastController;
import com.android.systemui.statusbar.policy.FlashlightController;
@@ -53,6 +68,10 @@ import com.android.systemui.statusbar.policy.ZenModeController;
import com.android.systemui.tuner.TunerService;
import com.android.systemui.tuner.TunerService.Tunable;
+import cyanogenmod.app.CustomTileListenerService;
+import cyanogenmod.app.StatusBarPanelCustomTile;
+import cyanogenmod.providers.CMSettings;
+
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@@ -65,7 +84,7 @@ public class QSTileHost implements QSTile.Host, Tunable {
private static final String TAG = "QSTileHost";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
- protected static final String TILES_SETTING = "sysui_qs_tiles";
+ public static final int TILES_PER_PAGE = 8;
private final Context mContext;
private final PhoneStatusBar mStatusBar;
@@ -84,6 +103,9 @@ public class QSTileHost implements QSTile.Host, Tunable {
private final KeyguardMonitor mKeyguard;
private final SecurityController mSecurity;
+ private CustomTileData mCustomTileData;
+ private CustomTileListenerService mCustomTileListenerService;
+
private Callback mCallback;
public QSTileHost(Context context, PhoneStatusBar statusBar,
@@ -106,19 +128,35 @@ public class QSTileHost implements QSTile.Host, Tunable {
mUserSwitcherController = userSwitcher;
mKeyguard = keyguard;
mSecurity = security;
+ mCustomTileData = new CustomTileData();
final HandlerThread ht = new HandlerThread(QSTileHost.class.getSimpleName(),
Process.THREAD_PRIORITY_BACKGROUND);
ht.start();
mLooper = ht.getLooper();
- TunerService.get(mContext).addTunable(this, TILES_SETTING);
+ TunerService.get(mContext).addTunableByProvider(this, CMSettings.Secure.QS_TILES, true);
}
public void destroy() {
TunerService.get(mContext).removeTunable(this);
}
+ public boolean isEditing() {
+ if (mCallback != null) {
+ return mCallback.isEditing();
+ }
+ return false;
+ }
+
+ public void setEditing(boolean editing) {
+ mCallback.setEditing(editing);
+ }
+
+ void setCustomTileListenerService(CustomTileListenerService customTileListenerService) {
+ mCustomTileListenerService = customTileListenerService;
+ }
+
@Override
public void setCallback(Callback callback) {
mCallback = callback;
@@ -129,14 +167,35 @@ public class QSTileHost implements QSTile.Host, Tunable {
return mTiles.values();
}
+ public List<String> getTileSpecs() {
+ return mTileSpecs;
+ }
+
+ public String getSpec(QSTile<?> tile) {
+ for (Map.Entry<String, QSTile<?>> entry : mTiles.entrySet()) {
+ if (entry.getValue() == tile) {
+ return entry.getKey();
+ }
+ }
+ return null;
+ }
+
@Override
public void startActivityDismissingKeyguard(final Intent intent) {
mStatusBar.postStartActivityDismissingKeyguard(intent, 0);
}
@Override
+<<<<<<< HEAD
+ public void removeCustomTile(StatusBarPanelCustomTile customTile) {
+ if (mCustomTileListenerService != null) {
+ mCustomTileListenerService.removeCustomTile(customTile.getPackage(),
+ customTile.getTag(), customTile.getId());
+ }
+=======
public void startActivityDismissingKeyguard(PendingIntent intent) {
mStatusBar.postStartActivityDismissingKeyguard(intent);
+>>>>>>> 888ef59df9262e1308d383fb56b8d077fb4170d7
}
@Override
@@ -150,6 +209,11 @@ public class QSTileHost implements QSTile.Host, Tunable {
}
@Override
+ public RemoteViews.OnClickHandler getOnClickHandler() {
+ return mStatusBar.getOnClickHandler();
+ }
+
+ @Override
public Looper getLooper() {
return mLooper;
}
@@ -214,7 +278,7 @@ public class QSTileHost implements QSTile.Host, Tunable {
@Override
public void onTuningChanged(String key, String newValue) {
- if (!TILES_SETTING.equals(key)) {
+ if (!CMSettings.Secure.QS_TILES.equals(key)) {
return;
}
if (DEBUG) Log.d(TAG, "Recreating tiles");
@@ -248,7 +312,14 @@ public class QSTileHost implements QSTile.Host, Tunable {
}
}
- protected QSTile<?> createTile(String tileSpec) {
+ @Override
+ public void goToSettingsPage() {
+ if (mCallback != null) {
+ mCallback.goToSettingsPage();
+ }
+ }
+
+ public QSTile<?> createTile(String tileSpec) {
if (tileSpec.equals("wifi")) return new WifiTile(this);
else if (tileSpec.equals("bt")) return new BluetoothTile(this);
else if (tileSpec.equals("inversion")) return new ColorInversionTile(this);
@@ -260,6 +331,7 @@ public class QSTileHost implements QSTile.Host, Tunable {
else if (tileSpec.equals("location")) return new LocationTile(this);
else if (tileSpec.equals("cast")) return new CastTile(this);
else if (tileSpec.equals("hotspot")) return new HotspotTile(this);
+ else if (tileSpec.equals("edit")) return new EditTile(this);
else if (tileSpec.startsWith(IntentTile.PREFIX)) return IntentTile.create(this,tileSpec);
else throw new IllegalArgumentException("Bad tile spec: " + tileSpec);
}
@@ -287,6 +359,80 @@ public class QSTileHost implements QSTile.Host, Tunable {
tiles.add(tile);
}
}
+ // ensure edit tile is present
+ if (tiles.size() < TILES_PER_PAGE && !tiles.contains("edit")) {
+ tiles.add("edit");
+ } else if (tiles.size() > TILES_PER_PAGE && !tiles.contains("edit")) {
+ tiles.add((TILES_PER_PAGE - 1), "edit");
+ }
return tiles;
}
+
+ public void remove(String tile) {
+ MetricsLogger.action(getContext(), MetricsLogger.TUNER_QS_REMOVE, tile);
+ List<String> tiles = new ArrayList<>(mTileSpecs);
+ tiles.remove(tile);
+ setTiles(tiles);
+ }
+
+ public void setTiles(List<String> tiles) {
+ CMSettings.Secure.putStringForUser(getContext().getContentResolver(),
+ CMSettings.Secure.QS_TILES,
+ TextUtils.join(",", tiles), ActivityManager.getCurrentUser());
+ }
+
+ @Override
+ public void resetTiles() {
+ setEditing(false);
+ CMSettings.Secure.putStringForUser(getContext().getContentResolver(),
+ CMSettings.Secure.QS_TILES, "default", ActivityManager.getCurrentUser());
+ }
+
+ public static int getLabelResource(String spec) {
+ if (spec.equals("wifi")) return R.string.quick_settings_wifi_label;
+ else if (spec.equals("bt")) return R.string.quick_settings_bluetooth_label;
+ else if (spec.equals("inversion")) return R.string.quick_settings_inversion_label;
+ else if (spec.equals("cell")) return R.string.quick_settings_cellular_detail_title;
+ else if (spec.equals("airplane")) return R.string.airplane_mode;
+ else if (spec.equals("dnd")) return R.string.quick_settings_dnd_label;
+ else if (spec.equals("rotation")) return R.string.quick_settings_rotation_locked_label;
+ else if (spec.equals("flashlight")) return R.string.quick_settings_flashlight_label;
+ else if (spec.equals("location")) return R.string.quick_settings_location_label;
+ else if (spec.equals("cast")) return R.string.quick_settings_cast_title;
+ else if (spec.equals("hotspot")) return R.string.quick_settings_hotspot_label;
+ else if (spec.equals("edit")) return R.string.quick_settings_edit_label;
+ return 0;
+ }
+
+ void updateCustomTile(StatusBarPanelCustomTile sbc) {
+ if (mTiles.containsKey(sbc.getKey())) {
+ QSTile<?> tile = mTiles.get(sbc.getKey());
+ if (tile instanceof CustomQSTile) {
+ CustomQSTile qsTile = (CustomQSTile) tile;
+ qsTile.update(sbc);
+ }
+ }
+ }
+
+ void addCustomTile(StatusBarPanelCustomTile sbc) {
+ mCustomTileData.add(new CustomTileData.Entry(sbc));
+ mTiles.put(sbc.getKey(), new CustomQSTile(this, sbc));
+ if (mCallback != null) {
+ mCallback.onTilesChanged();
+ }
+ }
+
+ void removeCustomTileSysUi(String key) {
+ if (mTiles.containsKey(key)) {
+ mTiles.remove(key);
+ mCustomTileData.remove(key);
+ if (mCallback != null) {
+ mCallback.onTilesChanged();
+ }
+ }
+ }
+
+ CustomTileData getCustomTileData() {
+ return mCustomTileData;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SettingsButton.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SettingsButton.java
index 18db5b8..3e0aa18 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SettingsButton.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SettingsButton.java
@@ -17,18 +17,18 @@ package com.android.systemui.statusbar.phone;
import android.animation.Animator;
import android.animation.Animator.AnimatorListener;
+import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.content.Context;
-import android.graphics.drawable.RippleDrawable;
-import android.os.Handler;
-import android.os.Message;
import android.util.AttributeSet;
+import android.view.HapticFeedbackConstants;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
+import android.view.animation.DecelerateInterpolator;
import com.android.keyguard.AlphaOptimizedImageButton;
public class SettingsButton extends AlphaOptimizedImageButton {
@@ -56,6 +56,10 @@ public class SettingsButton extends AlphaOptimizedImageButton {
return mUpToSpeed;
}
+ public void consumeClick() {
+ mUpToSpeed = false;
+ }
+
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getActionMasked()) {
@@ -78,6 +82,7 @@ public class SettingsButton extends AlphaOptimizedImageButton {
if ((x < -mSlop) || (y < -mSlop) || (x > getWidth() + mSlop)
|| (y > getHeight() + mSlop)) {
cancelLongClick();
+ startExitAnimation();
}
break;
}
@@ -99,32 +104,11 @@ public class SettingsButton extends AlphaOptimizedImageButton {
}
private void startExitAnimation() {
+ cancelAnimation();
animate()
- .translationX(((View) getParent().getParent()).getWidth() - getX())
- .alpha(0)
- .setDuration(RUN_DURATION)
- .setInterpolator(AnimationUtils.loadInterpolator(mContext,
- android.R.interpolator.accelerate_cubic))
- .setListener(new AnimatorListener() {
- @Override
- public void onAnimationStart(Animator animation) {
- }
-
- @Override
- public void onAnimationRepeat(Animator animation) {
- }
-
- @Override
- public void onAnimationEnd(Animator animation) {
- setAlpha(1f);
- setTranslationX(0);
- cancelLongClick();
- }
-
- @Override
- public void onAnimationCancel(Animator animation) {
- }
- })
+ .rotation(0)
+ .setDuration(ACCEL_LENGTH)
+ .setInterpolator(new DecelerateInterpolator(4))
.start();
}
@@ -164,6 +148,8 @@ public class SettingsButton extends AlphaOptimizedImageButton {
mAnimator.setDuration(FULL_SPEED_LENGTH);
mAnimator.setRepeatCount(Animation.INFINITE);
mAnimator.start();
+
+ performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
}
private final Runnable mLongPressCallback = new Runnable() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java
index 971978d..6624b30 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java
@@ -16,18 +16,33 @@
package com.android.systemui.statusbar.phone;
+import android.app.ActivityManager;
+import android.app.ActivityManagerNative;
import android.app.AlarmManager;
+import android.app.IUserSwitchObserver;
import android.app.PendingIntent;
+import android.content.ContentUris;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.res.Configuration;
import android.content.res.Resources;
+import android.database.ContentObserver;
import android.graphics.Outline;
import android.graphics.Rect;
import android.graphics.drawable.Animatable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.RippleDrawable;
+import android.os.Handler;
+import android.os.IRemoteCallback;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.provider.AlarmClock;
+import android.provider.CalendarContract;
+import android.provider.Settings;
+import android.net.Uri;
import android.util.AttributeSet;
+import android.util.Log;
import android.util.MathUtils;
import android.util.TypedValue;
import android.view.View;
@@ -40,31 +55,40 @@ import android.widget.Switch;
import android.widget.TextView;
import android.widget.Toast;
+import com.android.internal.logging.MetricsConstants;
import com.android.keyguard.KeyguardStatusView;
+import com.android.systemui.BatteryLevelTextView;
import com.android.systemui.BatteryMeterView;
import com.android.systemui.FontSizeUtils;
import com.android.systemui.R;
+import com.android.systemui.cm.UserContentObserver;
+import com.android.systemui.qs.QSDragPanel;
import com.android.systemui.qs.QSPanel;
import com.android.systemui.qs.QSTile;
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.statusbar.policy.NetworkControllerImpl.EmergencyListener;
import com.android.systemui.statusbar.policy.NextAlarmController;
import com.android.systemui.statusbar.policy.UserInfoController;
+import com.android.systemui.statusbar.policy.WeatherController;
+import com.android.systemui.statusbar.policy.WeatherControllerImpl;
import com.android.systemui.tuner.TunerService;
import java.text.NumberFormat;
+import cyanogenmod.app.StatusBarPanelCustomTile;
+import cyanogenmod.providers.CMSettings;
+
/**
* The view to manage the header area in the expanded status bar.
*/
public class StatusBarHeaderView extends RelativeLayout implements View.OnClickListener,
- BatteryController.BatteryStateChangeCallback, NextAlarmController.NextAlarmChangeCallback,
- EmergencyListener {
+ NextAlarmController.NextAlarmChangeCallback, WeatherController.Callback, EmergencyListener {
private boolean mExpanded;
private boolean mListening;
private ViewGroup mSystemIconsContainer;
+ private ViewGroup mWeatherContainer;
private View mSystemIconsSuperContainer;
private View mDateGroup;
private View mClock;
@@ -83,8 +107,10 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL
private Switch mQsDetailHeaderSwitch;
private ImageView mQsDetailHeaderProgress;
private TextView mEmergencyCallsOnly;
- private TextView mBatteryLevel;
+ private BatteryLevelTextView mBatteryLevel;
private TextView mAlarmStatus;
+ private TextView mWeatherLine1, mWeatherLine2;
+ private TextView mEditTileDoneText;
private boolean mShowEmergencyCallsOnly;
private boolean mAlarmShowing;
@@ -114,7 +140,8 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL
private ActivityStarter mActivityStarter;
private BatteryController mBatteryController;
private NextAlarmController mNextAlarmController;
- private QSPanel mQSPanel;
+ private WeatherController mWeatherController;
+ private QSDragPanel mQSPanel;
private final Rect mClipBounds = new Rect();
@@ -127,6 +154,10 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL
private float mCurrentT;
private boolean mShowingDetail;
private boolean mDetailTransitioning;
+ private SettingsObserver mSettingsObserver;
+ private boolean mShowWeather;
+ private boolean mShowBatteryTextExpanded;
+ private boolean mEditing;
public StatusBarHeaderView(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -139,7 +170,9 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL
mSystemIconsContainer = (ViewGroup) findViewById(R.id.system_icons_container);
mSystemIconsSuperContainer.setOnClickListener(this);
mDateGroup = findViewById(R.id.date_group);
+ mDateGroup.setOnClickListener(this);
mClock = findViewById(R.id.clock);
+ mClock.setOnClickListener(this);
mTime = (TextView) findViewById(R.id.time_view);
mAmPm = (TextView) findViewById(R.id.am_pm_view);
mMultiUserSwitch = (MultiUserSwitch) findViewById(R.id.multi_user_switch);
@@ -155,11 +188,17 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL
mQsDetailHeaderSwitch = (Switch) mQsDetailHeader.findViewById(android.R.id.toggle);
mQsDetailHeaderProgress = (ImageView) findViewById(R.id.qs_detail_header_progress);
mEmergencyCallsOnly = (TextView) findViewById(R.id.header_emergency_calls_only);
- mBatteryLevel = (TextView) findViewById(R.id.battery_level);
+ mBatteryLevel = (BatteryLevelTextView) findViewById(R.id.battery_level_text);
mAlarmStatus = (TextView) findViewById(R.id.alarm_status);
mAlarmStatus.setOnClickListener(this);
mSignalCluster = findViewById(R.id.signal_cluster);
mSystemIcons = (LinearLayout) findViewById(R.id.system_icons);
+ mWeatherContainer = (LinearLayout) findViewById(R.id.weather_container);
+ mWeatherContainer.setOnClickListener(this);
+ mWeatherLine1 = (TextView) findViewById(R.id.weather_line_1);
+ mWeatherLine2 = (TextView) findViewById(R.id.weather_line_2);
+ mEditTileDoneText = (TextView) findViewById(R.id.done);
+ mSettingsObserver = new SettingsObserver(new Handler());
loadDimens();
updateVisibilities();
updateClockScale();
@@ -211,7 +250,6 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL
@Override
protected void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
- FontSizeUtils.updateFontSize(mBatteryLevel, R.dimen.battery_level_text_size);
FontSizeUtils.updateFontSize(mEmergencyCallsOnly,
R.dimen.qs_emergency_calls_only_text_size);
FontSizeUtils.updateFontSize(mDateCollapsed, R.dimen.qs_date_collapsed_size);
@@ -274,17 +312,25 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL
public void setActivityStarter(ActivityStarter activityStarter) {
mActivityStarter = activityStarter;
+ if (mMultiUserSwitch != null) {
+ mMultiUserSwitch.setActivityStarter(activityStarter);
+ }
}
public void setBatteryController(BatteryController batteryController) {
mBatteryController = batteryController;
((BatteryMeterView) findViewById(R.id.battery)).setBatteryController(batteryController);
+ mBatteryLevel.setBatteryController(batteryController);
}
public void setNextAlarmController(NextAlarmController nextAlarmController) {
mNextAlarmController = nextAlarmController;
}
+ public void setWeatherController(WeatherController weatherController) {
+ mWeatherController = weatherController;
+ }
+
public int getCollapsedHeight() {
return mCollapsedHeight;
}
@@ -305,6 +351,9 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL
boolean changed = expanded != mExpanded;
mExpanded = expanded;
if (changed) {
+ if (mShowingDetail && !expanded) {
+ mQsPanelCallback.onShowingDetail(null);
+ }
updateEverything();
}
}
@@ -335,14 +384,14 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL
mDateExpanded.setVisibility(mExpanded && mAlarmShowing ? View.INVISIBLE : View.VISIBLE);
mAlarmStatus.setVisibility(mExpanded && mAlarmShowing ? View.VISIBLE : View.INVISIBLE);
mSettingsContainer.setVisibility(mExpanded ? View.VISIBLE : View.INVISIBLE);
- mQsDetailHeader.setVisibility(mExpanded && mShowingDetail? View.VISIBLE : View.INVISIBLE);
+ mWeatherContainer.setVisibility(mExpanded && mShowWeather ? View.VISIBLE : View.GONE);
+ mQsDetailHeader.setVisibility(mExpanded && mShowingDetail ? View.VISIBLE : View.INVISIBLE);
if (mSignalCluster != null) {
updateSignalClusterDetachment();
}
mEmergencyCallsOnly.setVisibility(mExpanded && mShowEmergencyCallsOnly ? VISIBLE : GONE);
- mBatteryLevel.setVisibility(mExpanded ? View.VISIBLE : View.GONE);
- mSettingsContainer.findViewById(R.id.tuner_icon).setVisibility(
- TunerService.isTunerEnabled(mContext) ? View.VISIBLE : View.INVISIBLE);
+ mBatteryLevel.setForceShown(mExpanded && mShowBatteryTextExpanded);
+ mBatteryLevel.setVisibility(View.VISIBLE);
}
private void updateSignalClusterDetachment() {
@@ -375,11 +424,13 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL
private void updateListeners() {
if (mListening) {
- mBatteryController.addStateChangedCallback(this);
+ mSettingsObserver.observe();
mNextAlarmController.addStateChangedCallback(this);
+ mWeatherController.addCallback(this);
} else {
- mBatteryController.removeStateChangedCallback(this);
mNextAlarmController.removeStateChangedCallback(this);
+ mWeatherController.removeCallback(this);
+ mSettingsObserver.unobserve();
}
}
@@ -408,17 +459,6 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL
}
@Override
- public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) {
- String percentage = NumberFormat.getPercentInstance().format((double) level / 100.0);
- mBatteryLevel.setText(percentage);
- }
-
- @Override
- public void onPowerSaveChanged() {
- // could not care less
- }
-
- @Override
public void onNextAlarmChanged(AlarmManager.AlarmClockInfo nextAlarm) {
mNextAlarm = nextAlarm;
if (nextAlarm != null) {
@@ -429,6 +469,19 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL
requestCaptureValues();
}
+ @Override
+ public void onWeatherChanged(WeatherController.WeatherInfo info) {
+ if (info.temp == null || info.condition == null) {
+ mWeatherLine1.setText(null);
+ } else {
+ mWeatherLine1.setText(mContext.getString(
+ R.string.status_bar_expanded_header_weather_format,
+ info.temp,
+ info.condition));
+ }
+ mWeatherLine2.setText(info.city);
+ }
+
private void updateClickTargets() {
mMultiUserSwitch.setClickable(mExpanded);
mMultiUserSwitch.setFocusable(mExpanded);
@@ -509,20 +562,11 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL
public void onClick(View v) {
if (v == mSettingsButton) {
if (mSettingsButton.isTunerClick()) {
- if (TunerService.isTunerEnabled(mContext)) {
- TunerService.showResetRequest(mContext, new Runnable() {
- @Override
- public void run() {
- // Relaunch settings so that the tuner disappears.
- startSettingsActivity();
- }
- });
- } else {
- Toast.makeText(getContext(), R.string.tuner_toast, Toast.LENGTH_LONG).show();
- TunerService.setTunerEnabled(mContext, true);
- }
+ mSettingsButton.consumeClick();
+ mQSPanel.getHost().setEditing(!mQSPanel.getHost().isEditing());
+ } else {
+ startSettingsActivity();
}
- startSettingsActivity();
} else if (v == mSystemIconsSuperContainer) {
startBatteryActivity();
} else if (v == mAlarmStatus && mNextAlarm != null) {
@@ -530,6 +574,12 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL
if (showIntent != null) {
mActivityStarter.startPendingIntentDismissingKeyguard(showIntent);
}
+ } else if (v == mClock) {
+ startClockActivity();
+ } else if (v == mDateGroup) {
+ startDateActivity();
+ } else if (v == mWeatherContainer) {
+ startForecastActivity();
}
}
@@ -543,7 +593,27 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL
true /* dismissShade */);
}
- public void setQSPanel(QSPanel qsp) {
+ private void startClockActivity() {
+ mActivityStarter.startActivity(new Intent(AlarmClock.ACTION_SHOW_ALARMS),
+ true /* dismissShade */);
+ }
+
+ private void startDateActivity() {
+ Uri.Builder builder = CalendarContract.CONTENT_URI.buildUpon();
+ builder.appendPath("time");
+ ContentUris.appendId(builder, System.currentTimeMillis());
+ Intent intent = new Intent(Intent.ACTION_VIEW).setData(builder.build());
+ mActivityStarter.startActivity(intent, true /* dismissShade */);
+ }
+
+ private void startForecastActivity() {
+ Intent intent = new Intent(Intent.ACTION_MAIN);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ intent.setComponent(WeatherControllerImpl.COMPONENT_WEATHER_FORECAST);
+ mActivityStarter.startActivity(intent, true /* dismissShade */);
+ }
+
+ public void setQSPanel(QSDragPanel qsp) {
mQSPanel = qsp;
if (mQSPanel != null) {
mQSPanel.setCallback(mQsPanelCallback);
@@ -585,6 +655,7 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL
target.avatarScale = mMultiUserAvatar.getScaleX();
target.avatarX = mMultiUserSwitch.getLeft() + mMultiUserAvatar.getLeft();
target.avatarY = mMultiUserSwitch.getTop() + mMultiUserAvatar.getTop();
+ target.weatherY = mClock.getBottom() - mWeatherLine1.getHeight();
if (getLayoutDirection() == LAYOUT_DIRECTION_LTR) {
target.batteryX = mSystemIconsSuperContainer.getLeft()
+ mSystemIconsContainer.getRight();
@@ -623,6 +694,7 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL
mTime.setScaleY(values.timeScale);
mClock.setY(values.clockY - mClock.getHeight());
mDateGroup.setY(values.dateY);
+ mWeatherContainer.setY(values.weatherY);
mAlarmStatus.setY(values.dateY - mAlarmStatus.getPaddingTop());
mMultiUserAvatar.setScaleX(values.avatarScale);
mMultiUserAvatar.setScaleY(values.avatarScale);
@@ -663,6 +735,8 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL
applyAlpha(mDateExpanded, values.dateExpandedAlpha);
applyAlpha(mBatteryLevel, values.batteryLevelAlpha);
applyAlpha(mSettingsContainer, values.settingsAlpha);
+ applyAlpha(mWeatherLine1, values.settingsAlpha);
+ applyAlpha(mWeatherLine2, values.settingsAlpha);
applyAlpha(mSignalCluster, values.signalClusterAlpha);
if (!mExpanded) {
mTime.setScaleX(1f);
@@ -671,6 +745,50 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL
updateAmPmTranslation();
}
+ public void setEditing(boolean editing) {
+ mEditing = editing;
+ if (mEditing) {
+ mQsPanelCallback.onShowingDetail(new QSTile.DetailAdapter() {
+ @Override
+ public StatusBarPanelCustomTile getCustomTile() {
+ return null;
+ }
+
+ @Override
+ public int getTitle() {
+ return R.string.quick_settings_edit_label;
+ }
+
+ @Override
+ public Boolean getToggleState() {
+ return null;
+ }
+
+ @Override
+ public View createDetailView(Context context, View convertView, ViewGroup parent) {
+ return null;
+ }
+
+ @Override
+ public Intent getSettingsIntent() {
+ return null;
+ }
+
+ @Override
+ public void setToggleState(boolean state) {
+
+ }
+
+ @Override
+ public int getMetricsCategory() {
+ return MetricsConstants.DONT_TRACK_ME_BRO;
+ }
+ });
+ } else {
+ mQsPanelCallback.onShowingDetail(null);
+ }
+ }
+
/**
* Captures all layout values (position, visibility) for a certain state. This is used for
* animations.
@@ -690,10 +808,12 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL
float batteryX;
float batteryY;
float batteryLevelAlpha;
+ float batteryLevelExpandedAlpha;
float settingsAlpha;
float settingsTranslation;
float signalClusterAlpha;
float settingsRotation;
+ float weatherY;
public void interpoloate(LayoutValues v1, LayoutValues v2, float t) {
timeScale = v1.timeScale * (1 - t) + v2.timeScale * t;
@@ -705,6 +825,7 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL
batteryX = v1.batteryX * (1 - t) + v2.batteryX * t;
batteryY = v1.batteryY * (1 - t) + v2.batteryY * t;
settingsTranslation = v1.settingsTranslation * (1 - t) + v2.settingsTranslation * t;
+ weatherY = v1.weatherY * (1 - t) + v2.weatherY * t;
float t1 = Math.max(0, t - 0.5f) * 2;
settingsRotation = v1.settingsRotation * (1 - t1) + v2.settingsRotation * t1;
@@ -720,6 +841,8 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL
dateExpandedAlpha = v1.dateExpandedAlpha * (1 - t3) + v2.dateExpandedAlpha * t3;
dateCollapsedAlpha = v1.dateCollapsedAlpha * (1 - t3) + v2.dateCollapsedAlpha * t3;
alarmStatusAlpha = v1.alarmStatusAlpha * (1 - t3) + v2.alarmStatusAlpha * t3;
+ batteryLevelExpandedAlpha =
+ v1.batteryLevelExpandedAlpha * (1 - t3) + v2.batteryLevelExpandedAlpha * t3;
}
}
@@ -778,18 +901,33 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL
final boolean showingDetail = detail != null;
transition(mClock, !showingDetail);
transition(mDateGroup, !showingDetail);
+ if (mShowWeather) {
+ transition(mWeatherContainer, !showingDetail);
+ }
if (mAlarmShowing) {
- transition(mAlarmStatus, !showingDetail);
+ transition(mAlarmStatus, !showingDetail && !mDetailTransitioning);
}
transition(mQsDetailHeader, showingDetail);
mShowingDetail = showingDetail;
if (showingDetail) {
mQsDetailHeaderTitle.setText(detail.getTitle());
final Boolean toggleState = detail.getToggleState();
- if (toggleState == null) {
+ if (detail.getTitle() == R.string.quick_settings_edit_label) {
+ mEditTileDoneText.setVisibility(View.VISIBLE);
mQsDetailHeaderSwitch.setVisibility(INVISIBLE);
+ mQsDetailHeader.setClickable(true);
+ mQsDetailHeader.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ mQSPanel.getHost().setEditing(false);
+ }
+ });
+ } else if (toggleState == null) {
+ mQsDetailHeaderSwitch.setVisibility(INVISIBLE);
+ mEditTileDoneText.setVisibility(View.GONE);
mQsDetailHeader.setClickable(false);
} else {
+ mEditTileDoneText.setVisibility(View.GONE);
mQsDetailHeaderSwitch.setVisibility(VISIBLE);
mQsDetailHeaderSwitch.setChecked(toggleState);
mQsDetailHeader.setClickable(true);
@@ -829,4 +967,58 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL
.start();
}
};
+
+ class SettingsObserver extends UserContentObserver {
+ SettingsObserver(Handler handler) {
+ super(handler);
+ }
+
+ @Override
+ protected void observe() {
+ super.observe();
+
+ ContentResolver resolver = mContext.getContentResolver();
+ resolver.registerContentObserver(CMSettings.System.getUriFor(
+ CMSettings.System.STATUS_BAR_SHOW_WEATHER), false, this, UserHandle.USER_ALL);
+ resolver.registerContentObserver(CMSettings.System.getUriFor(
+ CMSettings.System.STATUS_BAR_BATTERY_STYLE), false, this, UserHandle.USER_ALL);
+ resolver.registerContentObserver(CMSettings.System.getUriFor(
+ CMSettings.System.STATUS_BAR_SHOW_BATTERY_PERCENT), false, this, UserHandle.USER_ALL);
+ update();
+ }
+
+ @Override
+ protected void unobserve() {
+ super.unobserve();
+
+ ContentResolver resolver = mContext.getContentResolver();
+ resolver.unregisterContentObserver(this);
+ }
+
+ @Override
+ public void update() {
+
+ ContentResolver resolver = mContext.getContentResolver();
+ int currentUserId = ActivityManager.getCurrentUser();
+ int batteryStyle = CMSettings.System.getIntForUser(resolver,
+ CMSettings.System.STATUS_BAR_BATTERY_STYLE, 0, currentUserId);
+ boolean showExpandedBatteryPercentage = CMSettings.System.getIntForUser(resolver,
+ CMSettings.System.STATUS_BAR_SHOW_BATTERY_PERCENT, 0, currentUserId) == 0;
+
+ switch (batteryStyle) {
+ case 4: //BATTERY_METER_GONE
+ case 6: //BATTERY_METER_TEXT
+ showExpandedBatteryPercentage = false;
+ break;
+ default:
+ break;
+ }
+
+ mShowBatteryTextExpanded = showExpandedBatteryPercentage;
+ mShowWeather = CMSettings.System.getInt(
+ resolver, CMSettings.System.STATUS_BAR_SHOW_WEATHER, 1) == 1;
+ updateVisibilities();
+ requestCaptureValues();
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
index 5de1c13..93ac4e0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
@@ -24,6 +24,7 @@ import android.graphics.Color;
import android.os.Bundle;
import android.os.Handler;
import android.os.SystemClock;
+import android.provider.Settings;
import android.text.TextUtils;
import android.util.ArraySet;
import android.view.View;
@@ -36,12 +37,14 @@ import android.widget.TextView;
import com.android.internal.statusbar.StatusBarIcon;
import com.android.internal.util.NotificationColorUtil;
+import com.android.systemui.BatteryLevelTextView;
import com.android.systemui.BatteryMeterView;
import com.android.systemui.FontSizeUtils;
import com.android.systemui.R;
import com.android.systemui.statusbar.NotificationData;
import com.android.systemui.statusbar.SignalClusterView;
import com.android.systemui.statusbar.StatusBarIconView;
+import com.android.systemui.statusbar.policy.Clock;
import com.android.systemui.tuner.TunerService;
import com.android.systemui.tuner.TunerService.Tunable;
@@ -73,8 +76,10 @@ public class StatusBarIconController implements Tunable {
private IconMerger mNotificationIcons;
private View mNotificationIconArea;
private ImageView mMoreIcon;
+ private BatteryLevelTextView mBatteryLevelTextView;
private BatteryMeterView mBatteryMeterView;
- private TextView mClock;
+ private ClockController mClockController;
+ private View mCenterClockLayout;
private int mIconSize;
private int mIconHPadding;
@@ -117,8 +122,9 @@ public class StatusBarIconController implements Tunable {
mMoreIcon = (ImageView) statusBar.findViewById(R.id.moreIcon);
mNotificationIcons.setOverflowIndicator(mMoreIcon);
mStatusIconsKeyguard = (LinearLayout) keyguardStatusBar.findViewById(R.id.statusIcons);
+ mBatteryLevelTextView =
+ (BatteryLevelTextView) statusBar.findViewById(R.id.battery_level_text);
mBatteryMeterView = (BatteryMeterView) statusBar.findViewById(R.id.battery);
- mClock = (TextView) statusBar.findViewById(R.id.clock);
mLinearOutSlowIn = AnimationUtils.loadInterpolator(mContext,
android.R.interpolator.linear_out_slow_in);
mFastOutSlowIn = AnimationUtils.loadInterpolator(mContext,
@@ -126,6 +132,8 @@ public class StatusBarIconController implements Tunable {
mDarkModeIconColorSingleTone = context.getColor(R.color.dark_mode_icon_color_single_tone);
mLightModeIconColorSingleTone = context.getColor(R.color.light_mode_icon_color_single_tone);
mHandler = new Handler();
+ mClockController = new ClockController(statusBar, mNotificationIcons, mHandler);
+ mCenterClockLayout = statusBar.findViewById(R.id.center_clock_layout);
updateResources();
TunerService.get(mContext).addTunable(this, ICON_BLACKLIST);
@@ -158,7 +166,7 @@ public class StatusBarIconController implements Tunable {
com.android.internal.R.dimen.status_bar_icon_size);
mIconHPadding = mContext.getResources().getDimensionPixelSize(
R.dimen.status_bar_icon_padding);
- FontSizeUtils.updateFontSize(mClock, R.dimen.status_bar_clock_size);
+ mClockController.updateFontSize();
}
public void addSystemIcon(String slot, int index, int viewIndex, StatusBarIcon icon) {
@@ -247,22 +255,26 @@ public class StatusBarIconController implements Tunable {
public void hideSystemIconArea(boolean animate) {
animateHide(mSystemIconArea, animate);
+ animateHide(mCenterClockLayout, animate);
}
public void showSystemIconArea(boolean animate) {
animateShow(mSystemIconArea, animate);
+ animateShow(mCenterClockLayout, animate);
}
public void hideNotificationIconArea(boolean animate) {
animateHide(mNotificationIconArea, animate);
+ animateHide(mCenterClockLayout, animate);
}
public void showNotificationIconArea(boolean animate) {
animateShow(mNotificationIconArea, animate);
+ animateShow(mCenterClockLayout, animate);
}
public void setClockVisibility(boolean visible) {
- mClock.setVisibility(visible ? View.VISIBLE : View.GONE);
+ mClockController.setVisibility(visible);
}
public void dump(PrintWriter pw) {
@@ -392,8 +404,9 @@ public class StatusBarIconController implements Tunable {
}
mSignalCluster.setIconTint(mIconTint, mDarkIntensity);
mMoreIcon.setImageTintList(ColorStateList.valueOf(mIconTint));
+ mBatteryLevelTextView.setTextColor(mIconTint);
mBatteryMeterView.setDarkIntensity(mDarkIntensity);
- mClock.setTextColor(mIconTint);
+ mClockController.setTextColor(mIconTint);
applyNotificationIconsTint();
}
@@ -462,4 +475,20 @@ public class StatusBarIconController implements Tunable {
}
return ret;
}
+
+ public void refreshAllStatusBarIcons() {
+ refreshAllIconsForLayout(mStatusIcons);
+ refreshAllIconsForLayout(mStatusIconsKeyguard);
+ refreshAllIconsForLayout(mNotificationIcons);
+ }
+
+ private void refreshAllIconsForLayout(LinearLayout ll) {
+ final int count = ll.getChildCount();
+ for (int n = 0; n < count; n++) {
+ View child = ll.getChildAt(n);
+ if (child instanceof StatusBarIconView) {
+ ((StatusBarIconView) child).updateDrawable();
+ }
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index 05f6e57..f679a69 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -94,6 +94,7 @@ public class StatusBarKeyguardViewManager {
mContainer = container;
mStatusBarWindowManager = statusBarWindowManager;
mScrimController = scrimController;
+ if (mBouncer != null) mBouncer.removeView();
mFingerprintUnlockController = fingerprintUnlockController;
mBouncer = new KeyguardBouncer(mContext, mViewMediatorCallback, mLockPatternUtils,
mStatusBarWindowManager, container);
@@ -197,6 +198,7 @@ public class StatusBarKeyguardViewManager {
updateStates();
}
mPhoneStatusBar.onScreenTurnedOn();
+ mStatusBarWindowManager.onKeyguardChanged();
}
public void onScreenTurnedOff() {
@@ -542,4 +544,8 @@ public class StatusBarKeyguardViewManager {
public ViewRootImpl getViewRootImpl() {
return mPhoneStatusBar.getStatusBarView().getViewRootImpl();
}
+
+ public boolean isKeyguardShowingMedia() {
+ return mPhoneStatusBar.isKeyguardShowingMedia();
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
index ccfa0dd..117d19d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
@@ -19,18 +19,24 @@ package com.android.systemui.statusbar.phone;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.content.res.Resources;
+import android.graphics.Point;
import android.graphics.PixelFormat;
+import android.os.Handler;
import android.os.SystemProperties;
import android.view.Gravity;
+import android.view.Display;
+import android.view.SurfaceSession;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
+import android.view.WindowManagerPolicy;
import com.android.keyguard.R;
import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.statusbar.BaseStatusBar;
import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.policy.KeyguardMonitor;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -39,7 +45,7 @@ import java.lang.reflect.Field;
/**
* Encapsulates all logic for the status bar window state management.
*/
-public class StatusBarWindowManager {
+public class StatusBarWindowManager implements KeyguardMonitor.Callback {
private final Context mContext;
private final WindowManager mWindowManager;
@@ -49,14 +55,33 @@ public class StatusBarWindowManager {
private int mBarHeight;
private final boolean mKeyguardScreenRotation;
private final float mScreenBrightnessDoze;
+
+ private boolean mKeyguardBlurEnabled;
+ private boolean mShowingMedia;
+ private BlurLayer mKeyguardBlur;
+ private final SurfaceSession mFxSession;
+
+ private final KeyguardMonitor mKeyguardMonitor;
+
+ private static final int TYPE_LAYER_MULTIPLIER = 10000; // refer to WindowManagerService.TYPE_LAYER_MULTIPLIER
+ private static final int TYPE_LAYER_OFFSET = 1000; // refer to WindowManagerService.TYPE_LAYER_OFFSET
+
+ private static final int STATUS_BAR_LAYER = 16 * TYPE_LAYER_MULTIPLIER + TYPE_LAYER_OFFSET;
+
private final State mCurrentState = new State();
- public StatusBarWindowManager(Context context) {
+ public StatusBarWindowManager(Context context, KeyguardMonitor kgm) {
mContext = context;
mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
mKeyguardScreenRotation = shouldEnableKeyguardScreenRotation();
mScreenBrightnessDoze = mContext.getResources().getInteger(
com.android.internal.R.integer.config_screenBrightnessDoze) / 255f;
+
+ mKeyguardMonitor = kgm;
+ mKeyguardMonitor.addCallback(this);
+ mKeyguardBlurEnabled = mContext.getResources().getBoolean(
+ com.android.internal.R.bool.config_ui_blur_enabled);
+ mFxSession = new SurfaceSession();
}
private boolean shouldEnableKeyguardScreenRotation() {
@@ -72,7 +97,6 @@ public class StatusBarWindowManager {
* @param barHeight The height of the status bar in collapsed state.
*/
public void add(View statusBarView, int barHeight) {
-
// Now that the status bar window encompasses the sliding panel and its
// translucent backdrop, the entire thing is made TRANSLUCENT and is
// hardware-accelerated.
@@ -96,15 +120,30 @@ public class StatusBarWindowManager {
mWindowManager.addView(mStatusBarView, mLp);
mLpChanged = new WindowManager.LayoutParams();
mLpChanged.copyFrom(mLp);
+
+ if (mKeyguardBlurEnabled) {
+ Display display = mWindowManager.getDefaultDisplay();
+ Point xy = new Point();
+ display.getRealSize(xy);
+ mKeyguardBlur = new BlurLayer(mFxSession, xy.x, xy.y, "KeyGuard");
+ if (mKeyguardBlur != null) {
+ mKeyguardBlur.setLayer(STATUS_BAR_LAYER - 2);
+ }
+ }
}
private void applyKeyguardFlags(State state) {
if (state.keyguardShowing) {
- mLpChanged.flags |= WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
mLpChanged.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
+ if (!mKeyguardBlurEnabled) {
+ mLpChanged.flags |= WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
+ }
} else {
mLpChanged.flags &= ~WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
mLpChanged.privateFlags &= ~WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
+ if (mKeyguardBlurEnabled) {
+ mKeyguardBlur.hide();
+ }
}
}
@@ -217,13 +256,33 @@ public class StatusBarWindowManager {
}
}
+ private void applyKeyguardBlurShow(){
+ boolean isblur = false;
+ if (mCurrentState.keyguardShowing && mKeyguardBlurEnabled
+ && !mCurrentState.keyguardOccluded
+ && !mShowingMedia) {
+ isblur = true;
+ }
+ if (mKeyguardBlur != null) {
+ if (isblur) {
+ mKeyguardBlur.show();
+ } else {
+ mKeyguardBlur.hide();
+ }
+ }
+ }
+
public void setKeyguardShowing(boolean showing) {
mCurrentState.keyguardShowing = showing;
apply(mCurrentState);
}
public void setKeyguardOccluded(boolean occluded) {
+ final boolean oldOccluded = mCurrentState.keyguardOccluded;
mCurrentState.keyguardOccluded = occluded;
+ if (oldOccluded != occluded) {
+ applyKeyguardBlurShow();
+ }
apply(mCurrentState);
}
@@ -263,6 +322,23 @@ public class StatusBarWindowManager {
apply(mCurrentState);
}
+ void setBlur(float b){
+ if (mKeyguardBlurEnabled && mKeyguardBlur != null) {
+ float minBlur = mKeyguardMonitor.isSecure() ? 1.0f : 0.0f;
+ if (b < minBlur) {
+ b = minBlur;
+ } else if (b > 1.0f) {
+ b = 1.0f;
+ }
+ mKeyguardBlur.setBlur(b);
+ }
+ }
+
+ public void setShowingMedia(boolean showingMedia) {
+ mShowingMedia = showingMedia;
+ applyKeyguardBlurShow();
+ }
+
/**
* @param state The {@link StatusBarState} of the status bar.
*/
@@ -300,6 +376,11 @@ public class StatusBarWindowManager {
apply(mCurrentState);
}
+ @Override
+ public void onKeyguardChanged() {
+ applyKeyguardBlurShow();
+ }
+
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
pw.println("StatusBarWindowManager state:");
pw.println(mCurrentState);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
index 0e22aa8..75d2283 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
@@ -17,29 +17,42 @@
package com.android.systemui.statusbar.phone;
import android.app.StatusBarManager;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.res.TypedArray;
+import android.database.ContentObserver;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.media.session.MediaSessionLegacyHelper;
+import android.net.Uri;
+import android.os.Handler;
import android.os.IBinder;
+import android.os.IPowerManager;
+import android.os.PowerManager;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.PowerManager;
+import android.provider.Settings;
import android.util.AttributeSet;
+import android.util.Log;
+import android.view.GestureDetector;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
+import android.view.ViewConfiguration;
import android.view.ViewRootImpl;
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
import android.widget.FrameLayout;
-
import com.android.systemui.R;
import com.android.systemui.statusbar.BaseStatusBar;
import com.android.systemui.statusbar.DragDownHelper;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
+import cyanogenmod.providers.CMSettings;
public class StatusBarWindowView extends FrameLayout {
@@ -56,11 +69,21 @@ public class StatusBarWindowView extends FrameLayout {
private PhoneStatusBar mService;
private final Paint mTransparentSrcPaint = new Paint();
+ private int mStatusBarHeaderHeight;
+
+ private boolean mDoubleTapToSleepEnabled;
+ private GestureDetector mDoubleTapGesture;
+ private Handler mHandler = new Handler();
+ private SettingsObserver mSettingsObserver;
+
public StatusBarWindowView(Context context, AttributeSet attrs) {
super(context, attrs);
setMotionEventSplittingEnabled(false);
mTransparentSrcPaint.setColor(0);
mTransparentSrcPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC));
+ mStatusBarHeaderHeight = context
+ .getResources().getDimensionPixelSize(R.dimen.status_bar_header_height);
+ mSettingsObserver = new SettingsObserver(mHandler);
}
@Override
@@ -141,6 +164,21 @@ public class StatusBarWindowView extends FrameLayout {
protected void onAttachedToWindow () {
super.onAttachedToWindow();
+ mSettingsObserver.observe();
+ mDoubleTapGesture = new GestureDetector(mContext, new GestureDetector.SimpleOnGestureListener() {
+ @Override
+ public boolean onDoubleTap(MotionEvent e) {
+ PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
+ Log.d(TAG, "Gesture!!");
+ if(pm != null)
+ pm.goToSleep(e.getEventTime());
+ else
+ Log.d(TAG, "getSystemService returned null PowerManager");
+
+ return true;
+ }
+ });
+
// We really need to be able to animate while window animations are going on
// so that activities may be started asynchronously from panel animations
final ViewRootImpl root = getViewRootImpl();
@@ -164,6 +202,12 @@ public class StatusBarWindowView extends FrameLayout {
}
@Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ mSettingsObserver.unobserve();
+ }
+
+ @Override
public boolean dispatchKeyEvent(KeyEvent event) {
boolean down = event.getAction() == KeyEvent.ACTION_DOWN;
switch (event.getKeyCode()) {
@@ -211,6 +255,11 @@ public class StatusBarWindowView extends FrameLayout {
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean intercept = false;
+ if (mDoubleTapToSleepEnabled
+ && ev.getY() < mStatusBarHeaderHeight) {
+ if (DEBUG) Log.w(TAG, "logging double tap gesture");
+ mDoubleTapGesture.onTouchEvent(ev);
+ }
if (mNotificationPanel.isFullyExpanded()
&& mStackScrollLayout.getVisibility() == View.VISIBLE
&& mService.getBarState() == StatusBarState.KEYGUARD
@@ -288,6 +337,20 @@ public class StatusBarWindowView extends FrameLayout {
}
}
+ public void addContent(View content) {
+ addView(content);
+ mStackScrollLayout = (NotificationStackScrollLayout) content.findViewById(
+ R.id.notification_stack_scroller);
+ mNotificationPanel = (NotificationPanelView) content.findViewById(R.id.notification_panel);
+ mDragDownHelper = new DragDownHelper(getContext(), this, mStackScrollLayout, mService);
+ mBrightnessMirror = content.findViewById(R.id.brightness_mirror);
+
+ }
+
+ public void removeContent(View content) {
+ removeView(content);
+ }
+
public class LayoutParams extends FrameLayout.LayoutParams {
public boolean ignoreRightInset;
@@ -305,5 +368,39 @@ public class StatusBarWindowView extends FrameLayout {
a.recycle();
}
}
+
+ class SettingsObserver extends ContentObserver {
+ SettingsObserver(Handler handler) {
+ super(handler);
+ }
+
+ void observe() {
+ ContentResolver resolver = mContext.getContentResolver();
+ resolver.registerContentObserver(CMSettings.System.getUriFor(
+ CMSettings.System.DOUBLE_TAP_SLEEP_GESTURE), false, this);
+ update();
+ }
+
+ void unobserve() {
+ ContentResolver resolver = mContext.getContentResolver();
+ resolver.unregisterContentObserver(this);
+ }
+
+ @Override
+ public void onChange(boolean selfChange) {
+ update();
+ }
+
+ @Override
+ public void onChange(boolean selfChange, Uri uri) {
+ update();
+ }
+
+ public void update() {
+ ContentResolver resolver = mContext.getContentResolver();
+ mDoubleTapToSleepEnabled = CMSettings.System
+ .getInt(resolver, CMSettings.System.DOUBLE_TAP_SLEEP_GESTURE, 1) == 1;
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java
index d701b3c..9ebb79f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java
@@ -33,12 +33,7 @@ public class SystemUIDialog extends AlertDialog {
super(context, R.style.Theme_SystemUI_Dialog);
mContext = context;
- getWindow().setType(WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL);
- getWindow().addFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM
- | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
- WindowManager.LayoutParams attrs = getWindow().getAttributes();
- attrs.setTitle(getClass().getSimpleName());
- getWindow().setAttributes(attrs);
+ makeSystemUIDialog(this);
}
public void setShowForAllUsers(boolean show) {
@@ -62,4 +57,13 @@ public class SystemUIDialog extends AlertDialog {
public void setNegativeButton(int resId, OnClickListener onClick) {
setButton(BUTTON_NEGATIVE, mContext.getString(resId), onClick);
}
+
+ public static void makeSystemUIDialog(AlertDialog d) {
+ d.getWindow().setType(WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL);
+ d.getWindow().addFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM
+ | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
+ WindowManager.LayoutParams attrs = d.getWindow().getAttributes();
+ attrs.setTitle(SystemUIDialog.class.getClass().getSimpleName());
+ d.getWindow().setAttributes(attrs);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java
index d1b69ab..a154544 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java
@@ -17,10 +17,14 @@
package com.android.systemui.statusbar.policy;
import android.content.BroadcastReceiver;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.database.ContentObserver;
+import android.net.Uri;
import android.os.BatteryManager;
+import android.os.Handler;
import android.os.PowerManager;
import android.util.Log;
@@ -28,10 +32,22 @@ import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
+import cyanogenmod.providers.CMSettings;
+
public class BatteryController extends BroadcastReceiver {
private static final String TAG = "BatteryController";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+ public static final int STYLE_ICON_PORTRAIT = 0;
+ public static final int STYLE_CIRCLE = 2;
+ public static final int STYLE_GONE = 4;
+ public static final int STYLE_ICON_LANDSCAPE = 5;
+ public static final int STYLE_TEXT = 6;
+
+ public static final int PERCENTAGE_MODE_OFF = 0;
+ public static final int PERCENTAGE_MODE_INSIDE = 1;
+ public static final int PERCENTAGE_MODE_OUTSIDE = 2;
+
private final ArrayList<BatteryStateChangeCallback> mChangeCallbacks = new ArrayList<>();
private final PowerManager mPowerManager;
@@ -41,7 +57,12 @@ public class BatteryController extends BroadcastReceiver {
private boolean mCharged;
private boolean mPowerSave;
- public BatteryController(Context context) {
+ private int mStyle;
+ private int mPercentMode;
+ private int mUserId;
+ private SettingsObserver mObserver;
+
+ public BatteryController(Context context, Handler handler) {
mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
IntentFilter filter = new IntentFilter();
@@ -51,6 +72,14 @@ public class BatteryController extends BroadcastReceiver {
context.registerReceiver(this, filter);
updatePowerSave();
+
+ mObserver = new SettingsObserver(context, handler);
+ mObserver.observe();
+ }
+
+ public void setUserId(int userId) {
+ mUserId = userId;
+ mObserver.observe();
}
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
@@ -65,6 +94,7 @@ public class BatteryController extends BroadcastReceiver {
public void addStateChangedCallback(BatteryStateChangeCallback cb) {
mChangeCallbacks.add(cb);
cb.onBatteryLevelChanged(mLevel, mPluggedIn, mCharging);
+ cb.onBatteryStyleChanged(mStyle, mPercentMode);
}
public void removeStateChangedCallback(BatteryStateChangeCallback cb) {
@@ -121,8 +151,56 @@ public class BatteryController extends BroadcastReceiver {
}
}
+ private void fireSettingsChanged() {
+ final int N = mChangeCallbacks.size();
+ for (int i = 0; i < N; i++) {
+ mChangeCallbacks.get(i).onBatteryStyleChanged(mStyle, mPercentMode);
+ }
+ }
+
public interface BatteryStateChangeCallback {
void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging);
void onPowerSaveChanged();
+ void onBatteryStyleChanged(int style, int percentMode);
}
+
+ private final class SettingsObserver extends ContentObserver {
+ private ContentResolver mResolver;
+ private boolean mRegistered;
+
+ private final Uri STYLE_URI =
+ CMSettings.System.getUriFor(CMSettings.System.STATUS_BAR_BATTERY_STYLE);
+ private final Uri PERCENT_URI =
+ CMSettings.System.getUriFor(CMSettings.System.STATUS_BAR_SHOW_BATTERY_PERCENT);
+
+ public SettingsObserver(Context context, Handler handler) {
+ super(handler);
+ mResolver = context.getContentResolver();
+ }
+
+ public void observe() {
+ if (mRegistered) {
+ mResolver.unregisterContentObserver(this);
+ }
+ mResolver.registerContentObserver(STYLE_URI, false, this, mUserId);
+ mResolver.registerContentObserver(PERCENT_URI, false, this, mUserId);
+ mRegistered = true;
+
+ update();
+ }
+
+ @Override
+ public void onChange(boolean selfChange, Uri uri) {
+ update();
+ }
+
+ private void update() {
+ mStyle = CMSettings.System.getIntForUser(mResolver,
+ CMSettings.System.STATUS_BAR_BATTERY_STYLE, 0, mUserId);
+ mPercentMode = CMSettings.System.getIntForUser(mResolver,
+ CMSettings.System.STATUS_BAR_SHOW_BATTERY_PERCENT, 0, mUserId);
+
+ fireSettingsChanged();
+ }
+ };
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java
index 0340984..1ccf80b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java
@@ -38,7 +38,7 @@ public class BrightnessMirrorController {
private final View mPanelHolder;
private final int[] mInt2Cache = new int[2];
- public BrightnessMirrorController(StatusBarWindowView statusBarWindow) {
+ public BrightnessMirrorController(View statusBarWindow) {
mScrimBehind = (ScrimView) statusBarWindow.findViewById(R.id.scrim_behind);
mBrightnessMirror = statusBarWindow.findViewById(R.id.brightness_mirror);
mPanelHolder = statusBarWindow.findViewById(R.id.panel_holder);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CallbackHandler.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CallbackHandler.java
index e618cb8..69f8846 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CallbackHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CallbackHandler.java
@@ -124,16 +124,19 @@ public class CallbackHandler extends Handler implements EmergencyListener, Signa
@Override
public void setMobileDataIndicators(final IconState statusIcon, final IconState qsIcon,
- final int statusType, final int qsType,final boolean activityIn,
- final boolean activityOut, final String typeContentDescription,
- final String description, final boolean isWide, final int subId) {
+ final int statusType, final int qsType, final boolean activityIn,
+ final boolean activityOut, final int dataActivityId, final int mobileActivityId,
+ final int stackedDataIcon, final int stackedVoiceIcon,
+ final String typeContentDescription, final String description, final boolean isWide,
+ final int subId) {
post(new Runnable() {
@Override
public void run() {
for (SignalCallback signalCluster : mSignalCallbacks) {
signalCluster.setMobileDataIndicators(statusIcon, qsIcon, statusType, qsType,
- activityIn, activityOut, typeContentDescription, description, isWide,
- subId);
+ activityIn, activityOut, dataActivityId, mobileActivityId,
+ stackedDataIcon, stackedVoiceIcon,
+ typeContentDescription, description, isWide, subId);
}
}
});
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastControllerImpl.java
index e344954..4d3a49f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastControllerImpl.java
@@ -164,7 +164,7 @@ public class CastControllerImpl implements CastController {
@Override
public void startCasting(CastDevice device) {
- if (device == null || device.tag == null) return;
+ if (device == null || !(device.tag instanceof RouteInfo)) return;
final RouteInfo route = (RouteInfo) device.tag;
if (DEBUG) Log.d(TAG, "startCasting: " + routeToString(route));
mMediaRouter.selectRoute(ROUTE_TYPE_REMOTE_DISPLAY, route);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
index 61986ad..0cc82dc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
@@ -34,6 +34,7 @@ import android.widget.TextView;
import com.android.systemui.DemoMode;
import com.android.systemui.R;
+import com.android.systemui.cm.UserContentObserver;
import java.text.SimpleDateFormat;
import java.util.Calendar;
@@ -52,11 +53,11 @@ public class Clock extends TextView implements DemoMode {
private SimpleDateFormat mClockFormat;
private Locale mLocale;
- private static final int AM_PM_STYLE_NORMAL = 0;
- private static final int AM_PM_STYLE_SMALL = 1;
- private static final int AM_PM_STYLE_GONE = 2;
+ public static final int AM_PM_STYLE_NORMAL = 0;
+ public static final int AM_PM_STYLE_SMALL = 1;
+ public static final int AM_PM_STYLE_GONE = 2;
- private final int mAmPmStyle;
+ private int mAmPmStyle = AM_PM_STYLE_GONE;
public Clock(Context context) {
this(context, null);
@@ -68,15 +69,6 @@ public class Clock extends TextView implements DemoMode {
public Clock(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
- TypedArray a = context.getTheme().obtainStyledAttributes(
- attrs,
- R.styleable.Clock,
- 0, 0);
- try {
- mAmPmStyle = a.getInt(R.styleable.Clock_amPmStyle, AM_PM_STYLE_GONE);
- } finally {
- a.recycle();
- }
}
@Override
@@ -138,7 +130,7 @@ public class Clock extends TextView implements DemoMode {
};
final void updateClock() {
- if (mDemoMode) return;
+ if (mDemoMode || mCalendar == null) return;
mCalendar.setTimeInMillis(System.currentTimeMillis());
setText(getSmallTime());
}
@@ -244,5 +236,11 @@ public class Clock extends TextView implements DemoMode {
setText(getSmallTime());
}
}
+
+ public void setAmPmStyle(int style) {
+ mAmPmStyle = style;
+ mClockFormatString = "";
+ updateClock();
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeadZone.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeadZone.java
index 6eb88be..9864a0a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeadZone.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeadZone.java
@@ -46,6 +46,7 @@ public class DeadZone extends View {
// mHold ms, then move back over the course of mDecay ms
private int mHold, mDecay;
private boolean mVertical;
+ private boolean mStartFromRight;
private long mLastPokeTime;
private final Runnable mDebugFlash = new Runnable() {
@@ -73,6 +74,7 @@ public class DeadZone extends View {
int index = a.getInt(R.styleable.DeadZone_orientation, -1);
mVertical = (index == VERTICAL);
+ mStartFromRight = false; // Assume deadzone is starting from the left side of the zone
if (DEBUG)
Slog.v(TAG, this + " size=[" + mSizeMin + "-" + mSizeMax + "] hold=" + mHold
@@ -100,6 +102,7 @@ public class DeadZone extends View {
mShouldFlash = dbg;
mFlashFrac = 0f;
postInvalidate();
+ mFlashFrac = dbg ? 1f : 0f;
}
// I made you a touch event...
@@ -117,7 +120,19 @@ public class DeadZone extends View {
Slog.v(TAG, this + " ACTION_DOWN: " + event.getX() + "," + event.getY());
}
int size = (int) getSize(event.getEventTime());
- if ((mVertical && event.getX() < size) || event.getY() < size) {
+ boolean isCaptured;
+ if (mVertical && mStartFromRight) {
+ // Landscape on the left side of the screen
+ float pixelsFromRight = getWidth() - event.getX();
+ isCaptured = 0 <= pixelsFromRight && pixelsFromRight < size;
+ } else if (mVertical) {
+ // Landscape
+ isCaptured = event.getX() < size;
+ } else {
+ // Portrait
+ isCaptured = event.getY() < size;
+ }
+ if (isCaptured) {
if (CHATTY) {
Slog.v(TAG, "consuming errant click: (" + event.getX() + "," + event.getY() + ")");
}
@@ -147,6 +162,11 @@ public class DeadZone extends View {
return mFlashFrac;
}
+ public void setStartFromRight(boolean startFromRight) {
+ mStartFromRight = startFromRight;
+ if (mShouldFlash) postInvalidate();
+ }
+
@Override
public void onDraw(Canvas can) {
if (!mShouldFlash || mFlashFrac <= 0f) {
@@ -154,7 +174,17 @@ public class DeadZone extends View {
}
final int size = (int) getSize(SystemClock.uptimeMillis());
- can.clipRect(0, 0, mVertical ? size : can.getWidth(), mVertical ? can.getHeight() : size);
+ if (mVertical && mStartFromRight) {
+ // Landscape on the left side of the screen
+ can.clipRect(can.getWidth() - size, 0, can.getWidth(), can.getHeight());
+ } else if (mVertical) {
+ // Landscape
+ can.clipRect(0, 0, size, can.getHeight());
+ } else {
+ // Portrait
+ can.clipRect(0, 0, can.getWidth(), size);
+ }
+
final float frac = DEBUG ? (mFlashFrac - 0.5f) + 0.5f : mFlashFrac;
can.drawARGB((int) (frac * 0xFF), 0xDD, 0xEE, 0xAA);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonRipple.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonRipple.java
index 3f63b5f..ed41121 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonRipple.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonRipple.java
@@ -66,16 +66,19 @@ public class KeyButtonRipple extends Drawable {
private final HashSet<Animator> mRunningAnimations = new HashSet<>();
private final ArrayList<Animator> mTmpArray = new ArrayList<>();
+ private int mRippleColor;
+
public KeyButtonRipple(Context ctx, View targetView) {
mMaxWidth = ctx.getResources().getDimensionPixelSize(R.dimen.key_button_ripple_max_width);
mTargetView = targetView;
+ mRippleColor = ctx.getResources().getColor(R.color.navbutton_ripple_color);
}
private Paint getRipplePaint() {
if (mRipplePaint == null) {
mRipplePaint = new Paint();
mRipplePaint.setAntiAlias(true);
- mRipplePaint.setColor(0xffffffff);
+ mRipplePaint.setColor(mRippleColor);
}
return mRipplePaint;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
index 4d268ce..f6a4566 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
@@ -18,6 +18,9 @@ package com.android.systemui.statusbar.policy;
import android.app.ActivityManager;
import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.content.res.ThemeConfig;
import android.content.res.Configuration;
import android.content.res.TypedArray;
import android.hardware.input.InputManager;
@@ -39,28 +42,46 @@ import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.ImageView;
import com.android.systemui.R;
+import com.android.systemui.statusbar.phone.NavbarEditor;
import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLICK;
import static android.view.accessibility.AccessibilityNodeInfo.ACTION_LONG_CLICK;
+import cyanogenmod.power.PerformanceManager;
+
public class KeyButtonView extends ImageView {
+ public static final int CURSOR_REPEAT_FLAGS = KeyEvent.FLAG_SOFT_KEYBOARD
+ | KeyEvent.FLAG_KEEP_TOUCH_MODE;
+
private int mContentDescriptionRes;
private long mDownTime;
private int mCode;
+ private boolean mIsSmall;
private int mTouchSlop;
private boolean mSupportsLongpress = true;
+ private boolean mInEditMode;
private AudioManager mAudioManager;
private boolean mGestureAborted;
+ private boolean mPerformedLongClick;
+
+ private PerformanceManager mPerf;
private final Runnable mCheckLongPress = new Runnable() {
public void run() {
if (isPressed()) {
// Log.d("KeyButtonView", "longpressed: " + this);
- if (isLongClickable()) {
+ if (mCode == KeyEvent.KEYCODE_DPAD_LEFT || mCode == KeyEvent.KEYCODE_DPAD_RIGHT) {
+ sendEvent(KeyEvent.ACTION_UP, CURSOR_REPEAT_FLAGS,
+ System.currentTimeMillis(), false);
+ sendEvent(KeyEvent.ACTION_DOWN, CURSOR_REPEAT_FLAGS,
+ System.currentTimeMillis(), false);
+ postDelayed(mCheckLongPress, ViewConfiguration.getKeyRepeatDelay());
+ } else if (isLongClickable()) {
// Just an old-fashioned ImageView
+ mPerformedLongClick = true;
performLongClick();
- } else if (mSupportsLongpress) {
+ } else {
sendEvent(KeyEvent.ACTION_DOWN, KeyEvent.FLAG_LONG_PRESS);
sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_LONG_CLICKED);
}
@@ -94,6 +115,7 @@ public class KeyButtonView extends ImageView {
mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
setBackground(new KeyButtonRipple(context, this));
+ mPerf = PerformanceManager.getInstance(context);
}
@Override
@@ -142,7 +164,78 @@ public class KeyButtonView extends ImageView {
return super.performAccessibilityActionInternal(action, arguments);
}
+ @Override
+ public Resources getResources() {
+ ThemeConfig themeConfig = mContext.getResources().getConfiguration().themeConfig;
+ Resources res = null;
+ if (themeConfig != null) {
+ try {
+ final String navbarThemePkgName = themeConfig.getOverlayForNavBar();
+ final String sysuiThemePkgName = themeConfig.getOverlayForStatusBar();
+ // Check if the same theme is applied for systemui, if so we can skip this
+ if (navbarThemePkgName != null && !navbarThemePkgName.equals(sysuiThemePkgName)) {
+ res = mContext.getPackageManager().getThemedResourcesForApplication(
+ mContext.getPackageName(), navbarThemePkgName);
+ }
+ } catch (PackageManager.NameNotFoundException e) {
+ // don't care since we'll handle res being null below
+ }
+ }
+
+ return res != null ? res : super.getResources();
+ }
+
+ public void setEditMode(boolean editMode) {
+ mInEditMode = editMode;
+ updateVisibility();
+ }
+
+ public void setInfo(NavbarEditor.ButtonInfo item, boolean isVertical, boolean isSmall) {
+ final Resources res = getResources();
+ final int keyDrawableResId;
+
+ setTag(item);
+ setContentDescription(res.getString(item.contentDescription));
+ mCode = item.keyCode;
+ mIsSmall = isSmall;
+
+ if (isSmall) {
+ keyDrawableResId = item.sideResource;
+ } else if (!isVertical) {
+ keyDrawableResId = item.portResource;
+ } else {
+ keyDrawableResId = item.landResource;
+ }
+ // The reason for setImageDrawable vs setImageResource is because setImageResource calls
+ // relayout() w/o any checks. setImageDrawable performs size checks and only calls relayout
+ // if necessary. We rely on this because otherwise the setX/setY attributes which are post
+ // layout cause it to mess up the layout.
+ setImageDrawable(res.getDrawable(keyDrawableResId));
+ updateVisibility();
+ }
+
+ private void updateVisibility() {
+ if (mInEditMode) {
+ setVisibility(View.VISIBLE);
+ return;
+ }
+
+ NavbarEditor.ButtonInfo info = (NavbarEditor.ButtonInfo) getTag();
+ if (info == NavbarEditor.NAVBAR_EMPTY) {
+ setVisibility(mIsSmall ? View.INVISIBLE : View.GONE);
+ } else if (info == NavbarEditor.NAVBAR_CONDITIONAL_MENU) {
+ setVisibility(View.INVISIBLE);
+ }
+ }
+
+ private boolean supportsLongPress() {
+ return mSupportsLongpress;
+ }
+
public boolean onTouchEvent(MotionEvent ev) {
+ if (mInEditMode) {
+ return false;
+ }
final int action = ev.getAction();
int x, y;
if (action == MotionEvent.ACTION_DOWN) {
@@ -152,22 +245,32 @@ public class KeyButtonView extends ImageView {
return false;
}
+ // A lot of stuff is about to happen. Lets get ready.
+ mPerf.cpuBoost(750000);
+
switch (action) {
case MotionEvent.ACTION_DOWN:
mDownTime = SystemClock.uptimeMillis();
setPressed(true);
- if (mCode != 0) {
+ if (mCode == KeyEvent.KEYCODE_DPAD_LEFT || mCode == KeyEvent.KEYCODE_DPAD_RIGHT) {
+ sendEvent(KeyEvent.ACTION_DOWN, KeyEvent.FLAG_VIRTUAL_HARD_KEY
+ | KeyEvent.FLAG_KEEP_TOUCH_MODE, mDownTime, false);
+ } else if (mCode != 0) {
sendEvent(KeyEvent.ACTION_DOWN, 0, mDownTime);
} else {
// Provide the same haptic feedback that the system offers for virtual keys.
performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY);
}
- removeCallbacks(mCheckLongPress);
- postDelayed(mCheckLongPress, ViewConfiguration.getLongPressTimeout());
+
+ if (supportsLongPress()) {
+ removeCallbacks(mCheckLongPress);
+ postDelayed(mCheckLongPress, ViewConfiguration.getLongPressTimeout());
+ }
+
break;
case MotionEvent.ACTION_MOVE:
- x = (int)ev.getX();
- y = (int)ev.getY();
+ x = (int) ev.getX();
+ y = (int) ev.getY();
setPressed(x >= -mTouchSlop
&& x < getWidth() + mTouchSlop
&& y >= -mTouchSlop
@@ -178,7 +281,13 @@ public class KeyButtonView extends ImageView {
if (mCode != 0) {
sendEvent(KeyEvent.ACTION_UP, KeyEvent.FLAG_CANCELED);
}
+
removeCallbacks(mCheckLongPress);
+
+ if (supportsLongPress()) {
+ removeCallbacks(mCheckLongPress);
+ }
+
break;
case MotionEvent.ACTION_UP:
final boolean doIt = isPressed();
@@ -193,11 +302,17 @@ public class KeyButtonView extends ImageView {
}
} else {
// no key code, just a regular ImageView
- if (doIt) {
+ if (doIt && !mPerformedLongClick) {
performClick();
}
}
+
removeCallbacks(mCheckLongPress);
+
+ if (supportsLongPress()) {
+ removeCallbacks(mCheckLongPress);
+ }
+ mPerformedLongClick = false;
break;
}
@@ -213,10 +328,17 @@ public class KeyButtonView extends ImageView {
}
void sendEvent(int action, int flags, long when) {
+ sendEvent(action, flags, when, true);
+ }
+
+ void sendEvent(int action, int flags, long when, boolean applyDefaultFlags) {
final int repeatCount = (flags & KeyEvent.FLAG_LONG_PRESS) != 0 ? 1 : 0;
+ if (applyDefaultFlags) {
+ flags |= KeyEvent.FLAG_FROM_SYSTEM | KeyEvent.FLAG_VIRTUAL_HARD_KEY;
+ }
final KeyEvent ev = new KeyEvent(mDownTime, when, action, mCode, repeatCount,
0, KeyCharacterMap.VIRTUAL_KEYBOARD, 0,
- flags | KeyEvent.FLAG_FROM_SYSTEM | KeyEvent.FLAG_VIRTUAL_HARD_KEY,
+ flags,
InputDevice.SOURCE_KEYBOARD);
InputManager.getInstance().injectInputEvent(ev,
InputManager.INJECT_INPUT_EVENT_MODE_ASYNC);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
index b65bf43..631a4d0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
@@ -17,6 +17,7 @@ package com.android.systemui.statusbar.policy;
import android.content.Context;
import android.content.Intent;
+import android.content.res.Resources;
import android.net.NetworkCapabilities;
import android.os.Looper;
import android.telephony.PhoneStateListener;
@@ -56,6 +57,12 @@ public class MobileSignalController extends SignalController<
// @VisibleForDemoMode
final SparseArray<MobileIconGroup> mNetworkToIconLookup;
+ private boolean mLastShowSpn;
+ private String mLastSpn;
+ private String mLastDataSpn;
+ private boolean mLastShowPlmn;
+ private String mLastPlmn;
+
// Since some pieces of the phone state are interdependent we store it locally,
// this could potentially become part of MobileState for simplification/complication
// of code.
@@ -66,6 +73,12 @@ public class MobileSignalController extends SignalController<
private MobileIconGroup mDefaultIcons;
private Config mConfig;
+ private final int STATUS_BAR_STYLE_ANDROID_DEFAULT = 0;
+ private final int STATUS_BAR_STYLE_CDMA_1X_COMBINED = 1;
+ private final int STATUS_BAR_STYLE_DEFAULT_DATA = 2;
+ private final int STATUS_BAR_STYLE_DATA_VOICE = 3;
+ private int mStyle = STATUS_BAR_STYLE_ANDROID_DEFAULT;
+
// TODO: Reduce number of vars passed in, if we have the NetworkController, probably don't
// need listener lists anymore.
public MobileSignalController(Context context, Config config, boolean hasMobileData,
@@ -86,7 +99,14 @@ public class MobileSignalController extends SignalController<
mNetworkNameDefault = getStringIfExists(
com.android.internal.R.string.lockscreen_carrier_default);
- mapIconSets();
+ if (config.readIconsFromXml) {
+ TelephonyIcons.readIconsFromXml(context);
+ mDefaultIcons = !mConfig.showAtLeast3G ? TelephonyIcons.G : TelephonyIcons.THREE_G;
+ } else {
+ mapIconSets();
+ }
+
+ mStyle = context.getResources().getInteger(R.integer.status_bar_style);
String networkName = info.getCarrierName() != null ? info.getCarrierName().toString()
: mNetworkNameDefault;
@@ -100,7 +120,9 @@ public class MobileSignalController extends SignalController<
public void setConfiguration(Config config) {
mConfig = config;
- mapIconSets();
+ if (!config.readIconsFromXml) {
+ mapIconSets();
+ }
updateTelephony();
}
@@ -159,6 +181,7 @@ public class MobileSignalController extends SignalController<
mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_EVDO_B, TelephonyIcons.THREE_G);
mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_EHRPD, TelephonyIcons.THREE_G);
mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_UMTS, TelephonyIcons.THREE_G);
+ mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_TD_SCDMA, TelephonyIcons.THREE_G);
if (!mConfig.showAtLeast3G) {
mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_UNKNOWN,
@@ -191,14 +214,20 @@ public class MobileSignalController extends SignalController<
if (mConfig.show4gForLte) {
mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_LTE, TelephonyIcons.FOUR_G);
+ mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_LTE_CA,
+ TelephonyIcons.FOUR_G_PLUS);
} else {
mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_LTE, TelephonyIcons.LTE);
+ mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_LTE_CA, TelephonyIcons.LTE);
}
mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_IWLAN, TelephonyIcons.WFC);
}
@Override
public void notifyListeners() {
+ if (mConfig.readIconsFromXml) {
+ generateIconGroup();
+ }
MobileIconGroup icons = getIcons();
String contentDescription = getStringIfExists(getContentDescription());
@@ -228,9 +257,14 @@ public class MobileSignalController extends SignalController<
&& mCurrentState.activityOut;
showDataIcon &= mCurrentState.isDefault
|| mCurrentState.iconGroup == TelephonyIcons.ROAMING;
+ showDataIcon &= mStyle == STATUS_BAR_STYLE_ANDROID_DEFAULT;
int typeIcon = showDataIcon ? icons.mDataType : 0;
+ int dataActivityId = showMobileActivity() ? 0 : icons.mActivityId;
+ int mobileActivityId = showMobileActivity() ? icons.mActivityId : 0;
mCallbackHandler.setMobileDataIndicators(statusIcon, qsIcon, typeIcon, qsTypeIcon,
- activityIn, activityOut, dataContentDescription, description, icons.mIsWide,
+ activityIn, activityOut, dataActivityId, mobileActivityId,
+ icons.mStackedDataIcon, icons.mStackedVoiceIcon,
+ dataContentDescription, description, icons.mIsWide,
mSubscriptionInfo.getSubscriptionId());
}
@@ -239,6 +273,15 @@ public class MobileSignalController extends SignalController<
return new MobileState();
}
+ @Override
+ public int getCurrentIconId() {
+ if (mConfig.readIconsFromXml && mCurrentState.connected) {
+ return getIcons().mSingleSignalIcon;
+ } else {
+ return super.getCurrentIconId();
+ }
+ }
+
private boolean hasService() {
if (mServiceState != null) {
// Consider the device to be in service if either voice or data
@@ -296,6 +339,11 @@ public class MobileSignalController extends SignalController<
} else if (action.equals(TelephonyIntents.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED)) {
updateDataSim();
notifyListenersIfNecessary();
+ } else if (action.equals(Intent.ACTION_LOCALE_CHANGED)) {
+ if (mConfig.showLocale) {
+ updateNetworkName(mLastShowSpn, mLastSpn, mLastDataSpn, mLastShowPlmn, mLastPlmn);
+ notifyListenersIfNecessary();
+ }
}
}
@@ -315,27 +363,75 @@ public class MobileSignalController extends SignalController<
}
}
+ private String getLocalString(String originalString) {
+ return android.util.NativeTextHelper.getLocalString(mContext, originalString,
+ com.android.internal.R.array.origin_carrier_names,
+ com.android.internal.R.array.locale_carrier_names);
+ }
+
+ private String getNetworkClassString(ServiceState state) {
+ if (state != null && (state.getDataRegState() == ServiceState.STATE_IN_SERVICE ||
+ state.getVoiceRegState() == ServiceState.STATE_IN_SERVICE)) {
+ int voiceNetType = state.getVoiceNetworkType();
+ int dataNetType = state.getDataNetworkType();
+ int chosenNetType =
+ ((dataNetType == TelephonyManager.NETWORK_TYPE_UNKNOWN)
+ ? voiceNetType : dataNetType);
+ TelephonyManager tm = (TelephonyManager)mContext.getSystemService(
+ Context.TELEPHONY_SERVICE);
+ return tm.networkClassToString(chosenNetType);
+ } else {
+ return "";
+ }
+ }
+
/**
* Updates the network's name based on incoming spn and plmn.
*/
void updateNetworkName(boolean showSpn, String spn, String dataSpn,
boolean showPlmn, String plmn) {
+ mLastShowSpn = showSpn;
+ mLastSpn = spn;
+ mLastDataSpn = dataSpn;
+ mLastShowPlmn = showPlmn;
+ mLastPlmn = plmn;
if (CHATTY) {
Log.d("CarrierLabel", "updateNetworkName showSpn=" + showSpn
+ " spn=" + spn + " dataSpn=" + dataSpn
+ " showPlmn=" + showPlmn + " plmn=" + plmn);
}
+ if (mConfig.showLocale) {
+ if (showSpn && !TextUtils.isEmpty(spn)) {
+ spn = getLocalString(spn);
+ }
+ if (showSpn && !TextUtils.isEmpty(dataSpn)) {
+ dataSpn = getLocalString(dataSpn);
+ }
+ if (showPlmn && !TextUtils.isEmpty(plmn)) {
+ plmn = getLocalString(plmn);
+ }
+ }
+ if (showPlmn && showSpn && !TextUtils.isEmpty(spn) && !TextUtils.isEmpty(plmn)
+ && plmn.equals(spn)) {
+ showSpn = false;
+ }
+ String networkClass = getNetworkClassString(mServiceState);
StringBuilder str = new StringBuilder();
StringBuilder strData = new StringBuilder();
if (showPlmn && plmn != null) {
str.append(plmn);
strData.append(plmn);
+ if (mConfig.showRat) {
+ str.append(" ").append(networkClass);
+ strData.append(" ").append(networkClass);
+ }
}
if (showSpn && spn != null) {
if (str.length() != 0) {
str.append(mNetworkNameSeparator);
}
str.append(spn);
+ if (mConfig.showRat) str.append(" ").append(networkClass);
}
if (str.length() != 0) {
mCurrentState.networkName = str.toString();
@@ -347,6 +443,7 @@ public class MobileSignalController extends SignalController<
strData.append(mNetworkNameSeparator);
}
strData.append(dataSpn);
+ if (mConfig.showRat) strData.append(" ").append(networkClass);
}
if (strData.length() != 0) {
mCurrentState.networkNameData = strData.toString();
@@ -362,7 +459,7 @@ public class MobileSignalController extends SignalController<
*/
private final void updateTelephony() {
if (DEBUG) {
- Log.d(mTag, "updateTelephonySignalStrength: hasService=" + hasService()
+ Log.d(mTag, "updateTelephony: hasService=" + hasService()
+ " ss=" + mSignalStrength);
}
mCurrentState.connected = hasService() && mSignalStrength != null;
@@ -371,6 +468,13 @@ public class MobileSignalController extends SignalController<
mCurrentState.level = mSignalStrength.getCdmaLevel();
} else {
mCurrentState.level = mSignalStrength.getLevel();
+ if (mConfig.showRsrpSignalLevelforLTE) {
+ int dataType = mServiceState.getDataNetworkType();
+ if (dataType == TelephonyManager.NETWORK_TYPE_LTE ||
+ dataType == TelephonyManager.NETWORK_TYPE_LTE_CA) {
+ mCurrentState.level = getAlternateLteLevel(mSignalStrength);
+ }
+ }
}
}
if (mNetworkToIconLookup.indexOfKey(mDataNetType) >= 0) {
@@ -396,15 +500,225 @@ public class MobileSignalController extends SignalController<
mCurrentState.networkName = mServiceState.getOperatorAlphaShort();
}
+ if (mConfig.readIconsFromXml) {
+ mCurrentState.voiceLevel = getVoiceSignalLevel();
+ }
+
notifyListenersIfNecessary();
}
+ private void generateIconGroup() {
+ final int level = mCurrentState.level;
+ final int voiceLevel = mCurrentState.voiceLevel;
+ final int inet = mCurrentState.inetCondition;
+ final boolean dataConnected = mCurrentState.dataConnected;
+ final boolean roaming = isRoaming();
+ final int voiceType = getVoiceNetworkType();
+ final int dataType = getDataNetworkType();
+
+ int[][] sbIcons = TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH;
+ int[][] qsIcons = TelephonyIcons.QS_TELEPHONY_SIGNAL_STRENGTH;
+ int[] contentDesc = AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH;
+ int sbDiscState = TelephonyIcons.TELEPHONY_NO_NETWORK;
+ int qsDiscState = TelephonyIcons.QS_TELEPHONY_NO_NETWORK;
+ int discContentDesc = AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0];
+ int dataContentDesc, dataTypeIcon, qsDataTypeIcon, dataActivityId;
+ int singleSignalIcon, stackedDataIcon = 0, stackedVoiceIcon = 0;
+
+ final int slotId = getSimSlotIndex();
+ if (slotId < 0 || slotId > mPhone.getPhoneCount()) {
+ Log.e(mTag, "generateIconGroup invalid slotId:" + slotId);
+ return;
+ }
+
+ if (DEBUG) Log.d(mTag, "generateIconGroup slot:" + slotId + " style:" + mStyle
+ + " connected:" + mCurrentState.connected + " inetCondition:" + inet
+ + " roaming:" + roaming + " level:" + level + " voiceLevel:" + voiceLevel
+ + " dataConnected:" + dataConnected
+ + " dataActivity:" + mCurrentState.dataActivity
+ + " CS:" + voiceType
+ + "/" + TelephonyManager.getNetworkTypeName(voiceType)
+ + ", PS:" + dataType
+ + "/" + TelephonyManager.getNetworkTypeName(dataType));
+
+ // Update data icon set
+ int chosenNetworkType = ((dataType == TelephonyManager.NETWORK_TYPE_UNKNOWN)
+ ? voiceType : dataType);
+ TelephonyIcons.updateDataType(slotId, chosenNetworkType, mConfig.showAtLeast3G,
+ mConfig.show4gForLte, mConfig.hspaDataDistinguishable, inet);
+
+ // Update signal strength icons
+ singleSignalIcon = TelephonyIcons.getSignalStrengthIcon(slotId, inet, level, roaming);
+ if (DEBUG) {
+ Log.d(mTag, "singleSignalIcon:" + getResourceName(singleSignalIcon));
+ }
+
+ dataActivityId = (mCurrentState.dataConnected && slotId >= 0) ?
+ TelephonyIcons.getDataActivity(slotId, mCurrentState.dataActivity) : 0;
+
+ // Convert the icon to unstacked if necessary.
+ int unstackedSignalIcon = TelephonyIcons.convertMobileStrengthIcon(singleSignalIcon);
+ if (DEBUG) {
+ Log.d(mTag, "unstackedSignalIcon:" + getResourceName(unstackedSignalIcon));
+ }
+ if (singleSignalIcon != unstackedSignalIcon) {
+ stackedDataIcon = singleSignalIcon;
+ singleSignalIcon = unstackedSignalIcon;
+ }
+
+ if (mStyle == STATUS_BAR_STYLE_CDMA_1X_COMBINED) {
+ if (!roaming && showDataAndVoice()) {
+ stackedVoiceIcon = TelephonyIcons.getStackedVoiceIcon(voiceLevel);
+ } else if (roaming && dataActivityId != 0) {
+ // Remove data type indicator if already shown in data activity icon.
+ singleSignalIcon = TelephonyIcons.getRoamingSignalIconId(level, inet);
+ }
+ }
+
+ // Clear satcked data icon if no satcked voice icon.
+ if (stackedVoiceIcon == 0) stackedDataIcon = 0;
+
+ contentDesc = TelephonyIcons.getSignalStrengthDes(slotId);
+ sbDiscState = TelephonyIcons.getSignalNullIcon(slotId);
+ if (DEBUG) {
+ Log.d(mTag, "singleSignalIcon=" + getResourceName(singleSignalIcon)
+ + " dataActivityId=" + getResourceName(dataActivityId)
+ + " stackedDataIcon=" + getResourceName(stackedDataIcon)
+ + " stackedVoiceIcon=" + getResourceName(stackedVoiceIcon));
+ }
+
+ // Update data net type icons
+ if (dataType == TelephonyManager.NETWORK_TYPE_IWLAN) {
+ // wimax is a special 4g network not handled by telephony
+ dataTypeIcon = TelephonyIcons.ICON_4G;
+ qsDataTypeIcon = TelephonyIcons.QS_DATA_4G;
+ dataContentDesc = R.string.accessibility_data_connection_4g;
+ } else {
+ dataTypeIcon = TelephonyIcons.getDataTypeIcon(slotId);
+ dataContentDesc = TelephonyIcons.getDataTypeDesc(slotId);
+ qsDataTypeIcon = TelephonyIcons.getQSDataTypeIcon(slotId);
+ }
+ if (roaming) {
+ dataTypeIcon = TelephonyIcons.ROAMING_ICON;
+ qsDataTypeIcon = TelephonyIcons.QS_DATA_R;
+ }
+ if (DEBUG) {
+ Log.d(mTag, "updateDataNetType, dataTypeIcon=" + getResourceName(dataTypeIcon)
+ + " qsDataTypeIcon=" + getResourceName(qsDataTypeIcon)
+ + " dataContentDesc=" + dataContentDesc);
+ }
+ mCurrentState.iconGroup = new MobileIconGroup(
+ TelephonyManager.getNetworkTypeName(dataType),
+ sbIcons, qsIcons, contentDesc, 0, 0, sbDiscState, qsDiscState, discContentDesc,
+ dataContentDesc, dataTypeIcon, false, qsDataTypeIcon,
+ singleSignalIcon, stackedDataIcon, stackedVoiceIcon, dataActivityId);
+ }
+
+ private int getSimSlotIndex() {
+ int slotId = -1;
+ if (mSubscriptionInfo != null) {
+ slotId = mSubscriptionInfo.getSimSlotIndex();
+ }
+ if (DEBUG) Log.d(mTag, "getSimSlotIndex, slotId: " + slotId);
+ return slotId;
+ }
+
+ private boolean showMobileActivity() {
+ return (mStyle == STATUS_BAR_STYLE_DEFAULT_DATA)
+ || (mStyle == STATUS_BAR_STYLE_ANDROID_DEFAULT);
+ }
+
+ private int getVoiceNetworkType() {
+ if (mServiceState == null) {
+ return TelephonyManager.NETWORK_TYPE_UNKNOWN;
+ }
+ return mServiceState.getVoiceNetworkType();
+ }
+
+ private int getDataNetworkType() {
+ if (mServiceState == null) {
+ return TelephonyManager.NETWORK_TYPE_UNKNOWN;
+ }
+ return mServiceState.getDataNetworkType();
+ }
+
+ private int getVoiceSignalLevel() {
+ if (mSignalStrength == null) {
+ return SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
+ }
+ boolean isCdma = TelephonyManager.PHONE_TYPE_CDMA == TelephonyManager.getDefault()
+ .getCurrentPhoneType(mSubscriptionInfo.getSubscriptionId());
+ return isCdma ? mSignalStrength.getCdmaLevel() : mSignalStrength.getGsmLevel();
+ }
+
+ private boolean showDataAndVoice() {
+ if (mStyle != STATUS_BAR_STYLE_CDMA_1X_COMBINED) {
+ return false;
+ }
+ int dataType = getDataNetworkType();
+ int voiceType = getVoiceNetworkType();
+ if ((dataType == TelephonyManager.NETWORK_TYPE_EVDO_0
+ || dataType == TelephonyManager.NETWORK_TYPE_EVDO_0
+ || dataType == TelephonyManager.NETWORK_TYPE_EVDO_A
+ || dataType == TelephonyManager.NETWORK_TYPE_EVDO_B
+ || dataType == TelephonyManager.NETWORK_TYPE_EHRPD
+ || dataType == TelephonyManager.NETWORK_TYPE_LTE
+ || dataType == TelephonyManager.NETWORK_TYPE_LTE_CA)
+ && (voiceType == TelephonyManager.NETWORK_TYPE_GSM
+ || voiceType == TelephonyManager.NETWORK_TYPE_1xRTT
+ || voiceType == TelephonyManager.NETWORK_TYPE_CDMA)) {
+ return true;
+ }
+ return false;
+ }
+
+ private boolean show1xOnly() {
+ int dataType = getDataNetworkType();
+ int voiceType = getVoiceNetworkType();
+ if (dataType == TelephonyManager.NETWORK_TYPE_1xRTT
+ || dataType == TelephonyManager.NETWORK_TYPE_CDMA) {
+ return true;
+ }
+ return false;
+ }
+
+ private int getAlternateLteLevel(SignalStrength signalStrength) {
+ int lteRsrp = signalStrength.getLteDbm();
+ int rsrpLevel = SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
+ if (lteRsrp > -44) rsrpLevel = SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
+ else if (lteRsrp >= -97) rsrpLevel = SignalStrength.SIGNAL_STRENGTH_GREAT;
+ else if (lteRsrp >= -105) rsrpLevel = SignalStrength.SIGNAL_STRENGTH_GOOD;
+ else if (lteRsrp >= -113) rsrpLevel = SignalStrength.SIGNAL_STRENGTH_MODERATE;
+ else if (lteRsrp >= -120) rsrpLevel = SignalStrength.SIGNAL_STRENGTH_POOR;
+ else if (lteRsrp >= -140) rsrpLevel = SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
+ if (DEBUG) {
+ Log.d(mTag, "getAlternateLteLevel lteRsrp:" + lteRsrp + " rsrpLevel = " + rsrpLevel);
+ }
+ return rsrpLevel;
+ }
+
+ protected String getResourceName(int resId) {
+ if (resId != 0) {
+ final Resources res = mContext.getResources();
+ try {
+ return res.getResourceName(resId);
+ } catch (android.content.res.Resources.NotFoundException ex) {
+ return "(unknown)";
+ }
+ } else {
+ return "(null)";
+ }
+ }
+
@VisibleForTesting
void setActivity(int activity) {
mCurrentState.activityIn = activity == TelephonyManager.DATA_ACTIVITY_INOUT
|| activity == TelephonyManager.DATA_ACTIVITY_IN;
mCurrentState.activityOut = activity == TelephonyManager.DATA_ACTIVITY_INOUT
|| activity == TelephonyManager.DATA_ACTIVITY_OUT;
+ if (mConfig.readIconsFromXml) {
+ mCurrentState.dataActivity = activity;
+ }
notifyListenersIfNecessary();
}
@@ -440,6 +754,7 @@ public class MobileSignalController extends SignalController<
+ " dataState=" + state.getDataRegState());
}
mServiceState = state;
+ updateNetworkName(mLastShowSpn, mLastSpn, mLastDataSpn, mLastShowPlmn, mLastPlmn);
updateTelephony();
}
@@ -478,17 +793,35 @@ public class MobileSignalController extends SignalController<
final int mDataType;
final boolean mIsWide;
final int mQsDataType;
+ final int mSingleSignalIcon;
+ final int mStackedDataIcon;
+ final int mStackedVoiceIcon;
+ final int mActivityId;
public MobileIconGroup(String name, int[][] sbIcons, int[][] qsIcons, int[] contentDesc,
int sbNullState, int qsNullState, int sbDiscState, int qsDiscState,
int discContentDesc, int dataContentDesc, int dataType, boolean isWide,
int qsDataType) {
+ this(name, sbIcons, qsIcons, contentDesc, sbNullState, qsNullState, sbDiscState,
+ qsDiscState, discContentDesc, dataContentDesc, dataType, isWide,
+ qsDataType, 0, 0, 0, 0);
+ }
+
+ public MobileIconGroup(String name, int[][] sbIcons, int[][] qsIcons, int[] contentDesc,
+ int sbNullState, int qsNullState, int sbDiscState, int qsDiscState,
+ int discContentDesc, int dataContentDesc, int dataType, boolean isWide,
+ int qsDataType, int singleSignalIcon, int stackedDataIcon,
+ int stackedVoicelIcon, int activityId) {
super(name, sbIcons, qsIcons, contentDesc, sbNullState, qsNullState, sbDiscState,
qsDiscState, discContentDesc);
mDataContentDescription = dataContentDesc;
mDataType = dataType;
mIsWide = isWide;
mQsDataType = qsDataType;
+ mSingleSignalIcon = singleSignalIcon;
+ mStackedDataIcon = stackedDataIcon;
+ mStackedVoiceIcon = stackedVoicelIcon;
+ mActivityId = activityId;
}
}
@@ -501,6 +834,8 @@ public class MobileSignalController extends SignalController<
boolean airplaneMode;
boolean carrierNetworkChangeMode;
boolean isDefault;
+ int dataActivity;
+ int voiceLevel;
@Override
public void copyFrom(State s) {
@@ -514,6 +849,8 @@ public class MobileSignalController extends SignalController<
isEmergency = state.isEmergency;
airplaneMode = state.airplaneMode;
carrierNetworkChangeMode = state.carrierNetworkChangeMode;
+ dataActivity = state.dataActivity;
+ voiceLevel = state.voiceLevel;
}
@Override
@@ -527,6 +864,7 @@ public class MobileSignalController extends SignalController<
builder.append("isDefault=").append(isDefault).append(',');
builder.append("isEmergency=").append(isEmergency).append(',');
builder.append("airplaneMode=").append(airplaneMode).append(',');
+ builder.append("voiceLevel=").append(voiceLevel).append(',');
builder.append("carrierNetworkChangeMode=").append(carrierNetworkChangeMode);
}
@@ -540,6 +878,7 @@ public class MobileSignalController extends SignalController<
&& ((MobileState) o).isEmergency == isEmergency
&& ((MobileState) o).airplaneMode == airplaneMode
&& ((MobileState) o).carrierNetworkChangeMode == carrierNetworkChangeMode
+ && ((MobileState) o).voiceLevel == voiceLevel
&& ((MobileState) o).isDefault == isDefault;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
index 38656ee..1ed147f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
@@ -39,8 +39,10 @@ public interface NetworkController {
boolean activityIn, boolean activityOut, String description);
void setMobileDataIndicators(IconState statusIcon, IconState qsIcon, int statusType,
- int qsType, boolean activityIn, boolean activityOut, String typeContentDescription,
- String description, boolean isWide, int subId);
+ int qsType, boolean activityIn, boolean activityOut, int dataActivityId,
+ int mobileActivityId, int stackedDataIcon, int stackedVoiceIcon,
+ String typeContentDescription, String description,
+ boolean isWide, int subId);
void setSubs(List<SubscriptionInfo> subs);
void setNoSims(boolean show);
@@ -82,7 +84,7 @@ public interface NetworkController {
public interface AccessPointCallback {
void onAccessPointsChanged(List<AccessPoint> accessPoints);
- void onSettingsActivityTriggered(Intent settingsIntent);
+ void onSettingsActivityTriggered(Intent intent);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
index 2996808..bf7e489 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -210,6 +210,7 @@ public class NetworkControllerImpl extends BroadcastReceiver
filter.addAction(TelephonyIntents.SPN_STRINGS_UPDATED_ACTION);
filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
filter.addAction(ConnectivityManager.INET_CONDITION_ACTION);
+ filter.addAction(Intent.ACTION_LOCALE_CHANGED);
filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
mContext.registerReceiver(this, filter, null, mReceiverHandler);
mListening = true;
@@ -377,6 +378,10 @@ public class NetworkControllerImpl extends BroadcastReceiver
} else if (action.equals(TelephonyIntents.ACTION_SIM_STATE_CHANGED)) {
// Might have different subscriptions now.
updateMobileControllers();
+ } else if (action.equals(Intent.ACTION_LOCALE_CHANGED)) {
+ for (MobileSignalController controller : mMobileSignalControllers.values()) {
+ controller.handleBroadcast(intent);
+ }
} else if (action.equals(TelephonyIntents.ACTION_SERVICE_STATE_CHANGED)) {
mLastServiceState = ServiceState.newFromBundle(intent.getExtras());
if (mMobileSignalControllers.size() == 0) {
@@ -751,6 +756,7 @@ public class NetworkControllerImpl extends BroadcastReceiver
datatype.equals("1x") ? TelephonyIcons.ONE_X :
datatype.equals("3g") ? TelephonyIcons.THREE_G :
datatype.equals("4g") ? TelephonyIcons.FOUR_G :
+ datatype.equals("4g+") ? TelephonyIcons.FOUR_G_PLUS :
datatype.equals("e") ? TelephonyIcons.E :
datatype.equals("g") ? TelephonyIcons.G :
datatype.equals("h") ? TelephonyIcons.H :
@@ -780,7 +786,7 @@ public class NetworkControllerImpl extends BroadcastReceiver
private SubscriptionInfo addSignalController(int id, int simSlotIndex) {
SubscriptionInfo info = new SubscriptionInfo(id, "", simSlotIndex, "", "", 0, 0, "", 0,
- null, 0, 0, "");
+ null, 0, 0, "", 0);
mMobileSignalControllers.put(id, new MobileSignalController(mContext,
mConfig, mHasMobileDataFeature, mPhone, mCallbackHandler, this, info,
mSubDefaults, mReceiverHandler.getLooper()));
@@ -825,6 +831,10 @@ public class NetworkControllerImpl extends BroadcastReceiver
boolean alwaysShowCdmaRssi = false;
boolean show4gForLte = false;
boolean hspaDataDistinguishable;
+ boolean readIconsFromXml;
+ boolean showRsrpSignalLevelforLTE;
+ boolean showLocale;
+ boolean showRat;
static Config readConfig(Context context) {
Config config = new Config();
@@ -836,6 +846,14 @@ public class NetworkControllerImpl extends BroadcastReceiver
config.show4gForLte = res.getBoolean(R.bool.config_show4GForLTE);
config.hspaDataDistinguishable =
res.getBoolean(R.bool.config_hspa_data_distinguishable);
+ config.readIconsFromXml = res.getBoolean(R.bool.config_read_icons_from_xml);
+ config.showRsrpSignalLevelforLTE =
+ res.getBoolean(R.bool.config_showRsrpSignalLevelforLTE);
+ config.showLocale =
+ res.getBoolean(com.android.internal.R.bool.config_monitor_locale_change);
+ config.showRat =
+ res.getBoolean(com.android.internal.R.bool.config_display_rat);
+
return config;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockControllerImpl.java
index c3bcd94..e54df32 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockControllerImpl.java
@@ -64,7 +64,7 @@ public final class RotationLockControllerImpl implements RotationLockController
}
public boolean isRotationLockAffordanceVisible() {
- return RotationPolicy.isRotationLockToggleVisible(mContext);
+ return RotationPolicy.isRotationSupported(mContext);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SignalCallbackAdapter.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SignalCallbackAdapter.java
index dce889f..511ad2b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SignalCallbackAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SignalCallbackAdapter.java
@@ -36,8 +36,9 @@ public class SignalCallbackAdapter implements SignalCallback {
@Override
public void setMobileDataIndicators(IconState statusIcon, IconState qsIcon, int statusType,
- int qsType, boolean activityIn, boolean activityOut, String typeContentDescription,
- String description, boolean isWide, int subId) {
+ int qsType, boolean activityIn, boolean activityOut, int dataActivity,
+ int mobileActivity, int stackedDataIcon, int stackedVoiceIcon,
+ String typeContentDescription, String description, boolean isWide, int subId) {
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SuController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SuController.java
new file mode 100644
index 0000000..5f1e52e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SuController.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2014 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 com.android.systemui.statusbar.policy;
+
+public interface SuController {
+ void addCallback(Callback callback);
+ void removeCallback(Callback callback);
+ boolean hasActiveSessions();
+
+ public interface Callback {
+ void onSuSessionsChanged();
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SuControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SuControllerImpl.java
new file mode 100644
index 0000000..1ba334a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SuControllerImpl.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2014 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 com.android.systemui.statusbar.policy;
+
+import android.app.ActivityManager;
+import android.app.AppOpsManager;
+import android.app.StatusBarManager;
+import android.content.BroadcastReceiver;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Handler;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.provider.Settings;
+import android.util.Log;
+
+import com.android.systemui.R;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A controller to manage changes to superuser-related states and update the views accordingly.
+ */
+public class SuControllerImpl implements SuController {
+ private static final String TAG = "SuControllerImpl";
+
+ private static final int[] mSuOpArray = new int[] {AppOpsManager.OP_SU};
+
+ private ArrayList<Callback> mCallbacks = new ArrayList<Callback>();
+
+ private Context mContext;
+
+ private AppOpsManager mAppOpsManager;
+
+ private boolean mHasActiveSuSessions;
+
+ public SuControllerImpl(Context context) {
+ mContext = context;
+
+ mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
+
+ IntentFilter intentFilter = new IntentFilter();
+ intentFilter.addAction(AppOpsManager.ACTION_SU_SESSION_CHANGED);
+ context.registerReceiverAsUser(new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ Log.i(TAG, "Got change");
+ String action = intent.getAction();
+ if (AppOpsManager.ACTION_SU_SESSION_CHANGED.equals(action)) {
+ updateActiveSuSessions();
+ }
+ }
+ }, UserHandle.ALL, intentFilter, null, new Handler());
+
+ updateActiveSuSessions();
+ }
+
+ @Override
+ public void addCallback(Callback callback) {
+ mCallbacks.add(callback);
+ fireCallback(callback);
+ }
+
+ @Override
+ public void removeCallback(Callback callback) {
+ mCallbacks.remove(callback);
+ }
+
+ @Override
+ public boolean hasActiveSessions() {
+ return mHasActiveSuSessions;
+ }
+
+ private void fireCallback(Callback callback) {
+ callback.onSuSessionsChanged();
+ }
+
+ private void fireCallbacks() {
+ for (Callback callback : mCallbacks) {
+ callback.onSuSessionsChanged();
+ }
+ }
+
+ /**
+ * Returns true if a su session is active
+ */
+ private boolean hasActiveSuSessions() {
+ List<AppOpsManager.PackageOps> packages
+ = mAppOpsManager.getPackagesForOps(mSuOpArray);
+ // AppOpsManager can return null when there is no requested data.
+ if (packages != null) {
+ final int numPackages = packages.size();
+ for (int packageInd = 0; packageInd < numPackages; packageInd++) {
+ AppOpsManager.PackageOps packageOp = packages.get(packageInd);
+ List<AppOpsManager.OpEntry> opEntries = packageOp.getOps();
+ if (opEntries != null) {
+ final int numOps = opEntries.size();
+ for (int opInd = 0; opInd < numOps; opInd++) {
+ AppOpsManager.OpEntry opEntry = opEntries.get(opInd);
+ if (opEntry.getOp() == AppOpsManager.OP_SU) {
+ if (opEntry.isRunning()) {
+ return true;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return false;
+ }
+
+ private void updateActiveSuSessions() {
+ boolean hadActiveSuSessions = mHasActiveSuSessions;
+ mHasActiveSuSessions = hasActiveSuSessions();
+ if (mHasActiveSuSessions != hadActiveSuSessions) {
+ fireCallbacks();
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java
index 83e0446..2c9f2b9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java
@@ -1,4 +1,6 @@
/*
+ * Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,6 +18,14 @@
package com.android.systemui.statusbar.policy;
+import android.content.Context;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.telephony.SignalStrength;
+import android.telephony.TelephonyManager;
+import android.util.Log;
+import android.util.SparseArray;
+
import com.android.systemui.R;
import com.android.systemui.statusbar.policy.MobileSignalController.MobileIconGroup;
@@ -68,6 +78,20 @@ class TelephonyIcons {
R.drawable.stat_sys_signal_4_fully }
};
+ //Default roaming icons with R indicator
+ static final int[][] TELEPHONY_SIGNAL_STRENGTH_ROAMING_R = {
+ { R.drawable.stat_sys_signal_0_default_roam,
+ R.drawable.stat_sys_signal_1_default_roam,
+ R.drawable.stat_sys_signal_2_default_roam,
+ R.drawable.stat_sys_signal_3_default_roam,
+ R.drawable.stat_sys_signal_4_default_roam },
+ { R.drawable.stat_sys_signal_0_default_fully_roam,
+ R.drawable.stat_sys_signal_1_default_fully_roam,
+ R.drawable.stat_sys_signal_2_default_fully_roam,
+ R.drawable.stat_sys_signal_3_default_fully_roam,
+ R.drawable.stat_sys_signal_4_default_fully_roam }
+ };
+
//CarrierNetworkChange
static final int[][] TELEPHONY_CARRIER_NETWORK_CHANGE = {
{ R.drawable.stat_sys_signal_carrier_network_change_animation,
@@ -182,6 +206,19 @@ class TelephonyIcons {
static final int QS_DATA_4G = R.drawable.ic_qs_signal_4g;
+ static final int[][] DATA_4G_PLUS = {
+ { R.drawable.stat_sys_data_fully_connected_4g_plus,
+ R.drawable.stat_sys_data_fully_connected_4g_plus,
+ R.drawable.stat_sys_data_fully_connected_4g_plus,
+ R.drawable.stat_sys_data_fully_connected_4g_plus },
+ { R.drawable.stat_sys_data_fully_connected_4g_plus,
+ R.drawable.stat_sys_data_fully_connected_4g_plus,
+ R.drawable.stat_sys_data_fully_connected_4g_plus,
+ R.drawable.stat_sys_data_fully_connected_4g_plus }
+ };
+
+ static final int QS_DATA_4G_PLUS = R.drawable.ic_qs_signal_4g_plus;
+
// LTE branded "LTE"
static final int[][] DATA_LTE = {
{ R.drawable.stat_sys_data_fully_connected_lte,
@@ -204,6 +241,7 @@ class TelephonyIcons {
static final int ICON_H = R.drawable.stat_sys_data_fully_connected_h;
static final int ICON_3G = R.drawable.stat_sys_data_fully_connected_3g;
static final int ICON_4G = R.drawable.stat_sys_data_fully_connected_4g;
+ static final int ICON_4G_PLUS = R.drawable.stat_sys_data_fully_connected_4g_plus;
static final int ICON_1X = R.drawable.stat_sys_data_fully_connected_1x;
static final int ICON_CARRIER_NETWORK_CHANGE =
R.drawable.stat_sys_signal_carrier_network_change_animation;
@@ -211,9 +249,407 @@ class TelephonyIcons {
static final int QS_ICON_LTE = R.drawable.ic_qs_signal_lte;
static final int QS_ICON_3G = R.drawable.ic_qs_signal_3g;
static final int QS_ICON_4G = R.drawable.ic_qs_signal_4g;
+ static final int QS_ICON_4G_PLUS = R.drawable.ic_qs_signal_4g_plus;
static final int QS_ICON_1X = R.drawable.ic_qs_signal_1x;
static final int QS_ICON_CARRIER_NETWORK_CHANGE =
R.drawable.ic_qs_signal_carrier_network_change_animation;
+ static final int DATA_TYPE_UNKNOWN = 0;
+ static final int DATA_TYPE_G = 1;
+ static final int DATA_TYPE_E = 2;
+ static final int DATA_TYPE_2G = 3;
+ static final int DATA_TYPE_3G = 4;
+ static final int DATA_TYPE_4G = 5;
+ static final int DATA_TYPE_H = 6;
+ static final int DATA_TYPE_HP = 7;
+ static final int DATA_TYPE_1X = 8;
+ static final int DATA_TYPE_LTE = 9;
+
+ static final int SIGNAL_STRENGTH_TYPE_G = 0;
+ static final int SIGNAL_STRENGTH_TYPE_E = 1;
+ static final int SIGNAL_STRENGTH_TYPE_3G = 2;
+ static final int SIGNAL_STRENGTH_TYPE_4G = 3;
+ static final int SIGNAL_STRENGTH_TYPE_H = 4;
+ static final int SIGNAL_STRENGTH_TYPE_HP = 5;
+ static final int SIGNAL_STRENGTH_TYPE_1X = 6;
+ static final int SIGNAL_STRENGTH_TYPE_CDMA = 7;
+ static final int SIGNAL_STRENGTH_TYPE_UMTS = 8;
+
+ static final boolean DEBUG = true;
+ static final int DEFAULT_SUB = 0;
+ static final int INET_TYPE_NUM = 2;
+ static final int SIGNAL_LEVEL_NUM = SignalStrength.NUM_SIGNAL_STRENGTH_BINS;
+ static final String TAG = "TelephonyIcons";
+ static final String NS = "com.android.systemui";
+
+ static String[] mDataTypeArray, mDataTypeGenerationArray;
+ static String[] mDataTypeDescriptionArray, mDataTypeGenerationDescArray;
+ static String[] mDataActivityArray;
+ static String[] mSignalStrengthArray, mSignalStrengthRoamingArray;
+ static String[] mSignalNullArray;
+ static String[] mSignalStrengthDesc;
+
+ static int[] mSelectedDataTypeIcon;
+ static int[] mSelectedQSDataTypeIcon;
+ static String[] mSelectedDataTypeDesc;
+ static int[] mSelectedDataActivityIndex;
+ static int[] mSelectedSignalStreagthIndex;
+ static SparseArray<Integer> mStacked2SingleIconLookup;
+
+ private static Resources mRes;
+ private static boolean isInitiated = false;
+
+ static void readIconsFromXml(Context context) {
+ if (isInitiated) {
+ log(TAG, "readIconsFromXml, already read!");
+ return;
+ }
+
+ mRes = context.getResources();
+ try {
+ mDataTypeArray = mRes.getStringArray(R.array.multi_data_type);
+ mDataTypeDescriptionArray = mRes.getStringArray(
+ R.array.telephony_data_type_description);
+ mDataTypeGenerationArray = mRes.getStringArray(
+ R.array.telephony_data_type_generation);
+ mDataTypeGenerationDescArray = mRes.getStringArray(
+ R.array.telephony_data_type_generation_description);
+ mDataActivityArray = mRes.getStringArray(R.array.multi_data_activity);
+ mSignalStrengthArray = mRes.getStringArray(R.array.multi_signal_strength);
+ mSignalStrengthRoamingArray = mRes.getStringArray(
+ R.array.multi_signal_strength_roaming);
+ mSignalNullArray = mRes.getStringArray(R.array.multi_signal_null);
+ mSignalStrengthDesc = mRes.getStringArray(R.array.signal_strength_description);
+ initStacked2SingleIconLookup();
+ } catch (android.content.res.Resources.NotFoundException e) {
+ isInitiated = false;
+ log(TAG, "readIconsFromXml, exception happened: " + e);
+ return;
+ }
+
+ if (mSelectedDataTypeIcon == null
+ && mDataTypeArray.length != 0) {
+ mSelectedDataTypeIcon = new int[mDataTypeArray.length];
+ }
+ if (mSelectedQSDataTypeIcon == null
+ && mDataTypeArray.length != 0) {
+ mSelectedQSDataTypeIcon = new int[mDataTypeArray.length];
+ }
+ if (mSelectedDataTypeDesc == null
+ && mDataTypeArray.length != 0) {
+ mSelectedDataTypeDesc = new String[mDataTypeArray.length];
+ }
+ if (mSelectedDataActivityIndex == null
+ && mDataActivityArray.length != 0) {
+ mSelectedDataActivityIndex = new int[mDataActivityArray.length];
+ }
+ if (mSelectedSignalStreagthIndex == null
+ && mSignalStrengthArray.length != 0) {
+ mSelectedSignalStreagthIndex = new int[mSignalStrengthArray.length];
+ }
+ isInitiated = true;
+ }
+
+ static void initStacked2SingleIconLookup() {
+ mStacked2SingleIconLookup = new SparseArray<>();
+ TypedArray stackedIcons = mRes.obtainTypedArray(R.array.stacked_signal_icons);
+ TypedArray singleIcons = mRes.obtainTypedArray(R.array.single_signal_icons);
+
+ mStacked2SingleIconLookup.clear();
+ for (int i = 0; i < stackedIcons.length() && i < singleIcons.length(); i++) {
+ mStacked2SingleIconLookup.put(stackedIcons.getResourceId(i,0),
+ singleIcons.getResourceId(i,0));
+ }
+ stackedIcons.recycle();
+ singleIcons.recycle();
+ log(TAG, "initStacked2SingleIconLookup: size=" + mStacked2SingleIconLookup.size());
+ }
+
+ static int getSignalNullIcon(int slot) {
+ if (mSignalNullArray == null) {
+ return 0;
+ }
+ String resName = mSignalNullArray[slot];
+ log(TAG, "null signal icon name: " + resName);
+ int resId = mRes.getIdentifier(resName, null, NS);
+ return resId;
+ }
+
+ static void updateDataType(int slot, int type, boolean showAtLeast3G,
+ boolean show4GforLte, boolean hspaDistinguishable, int inet) {
+ log(TAG, "updateDataType "
+ + String.format("slot=%d, type=%d, inetCondition=%d",
+ slot, type, inet)
+ + " showAtLeast3G=" + String.valueOf(showAtLeast3G)
+ + " show4GforLte=" + String.valueOf(show4GforLte)
+ + " hspaDistinguishable=" + String.valueOf(hspaDistinguishable));
+
+ String resName = mDataTypeArray[slot];
+ int resId = mRes.getIdentifier(resName, null, NS);
+ String[] dataTypeArray = mRes.getStringArray(resId);
+
+ log(TAG, "data type item name: " + resName + " id:" + resId);
+
+ switch (type) {
+ case TelephonyManager.NETWORK_TYPE_UNKNOWN:
+ if (!showAtLeast3G) {
+ mSelectedDataTypeIcon[slot] = mRes.getIdentifier(
+ dataTypeArray[type], null, NS);
+ mSelectedQSDataTypeIcon[slot] = 0;
+ mSelectedDataTypeDesc[slot] = mDataTypeDescriptionArray[type];
+ mSelectedDataActivityIndex[slot] = 0;
+ mSelectedSignalStreagthIndex[slot] = 0;
+ break;
+ } else {
+ // fall through
+ }
+ case TelephonyManager.NETWORK_TYPE_EDGE:
+ if (!showAtLeast3G) {
+ mSelectedDataTypeIcon[slot] = mRes.getIdentifier(
+ dataTypeArray[type], null, NS);
+ mSelectedQSDataTypeIcon[slot] = QS_DATA_E;
+ mSelectedDataTypeDesc[slot] = mDataTypeDescriptionArray[type];
+ mSelectedDataActivityIndex[slot] = DATA_TYPE_E;
+ mSelectedSignalStreagthIndex[slot] = SIGNAL_STRENGTH_TYPE_E;
+ break;
+ } else {
+ // fall through
+ }
+ case TelephonyManager.NETWORK_TYPE_UMTS:
+ case TelephonyManager.NETWORK_TYPE_TD_SCDMA:
+ mSelectedDataActivityIndex[slot] = DATA_TYPE_3G;
+ mSelectedDataTypeIcon[slot] = mRes.getIdentifier(
+ dataTypeArray[type], null, NS);
+ mSelectedQSDataTypeIcon[slot] = QS_DATA_3G;
+ mSelectedDataTypeDesc[slot] = mDataTypeDescriptionArray[type];
+ mSelectedSignalStreagthIndex[slot] = SIGNAL_STRENGTH_TYPE_UMTS;
+ break;
+ case TelephonyManager.NETWORK_TYPE_HSDPA:
+ case TelephonyManager.NETWORK_TYPE_HSUPA:
+ case TelephonyManager.NETWORK_TYPE_HSPA:
+ if (hspaDistinguishable) {
+ mSelectedDataActivityIndex[slot] = DATA_TYPE_H;
+ mSelectedDataTypeIcon[slot] = mRes.getIdentifier(
+ dataTypeArray[type], null, NS);
+ mSelectedQSDataTypeIcon[slot] = QS_DATA_H;
+ mSelectedDataTypeDesc[slot] = mDataTypeDescriptionArray[type];
+ mSelectedSignalStreagthIndex[slot] = SIGNAL_STRENGTH_TYPE_H;
+ } else {
+ mSelectedDataActivityIndex[slot] = DATA_TYPE_3G;
+ mSelectedDataTypeIcon[slot] = mRes.getIdentifier(
+ mDataTypeGenerationArray[0], null, NS);
+ mSelectedQSDataTypeIcon[slot] = QS_DATA_3G;
+ mSelectedDataTypeDesc[slot] = mDataTypeGenerationDescArray[0];
+ mSelectedSignalStreagthIndex[slot] = SIGNAL_STRENGTH_TYPE_3G;
+
+ }
+ break;
+ case TelephonyManager.NETWORK_TYPE_HSPAP:
+ if (hspaDistinguishable) {
+ mSelectedDataActivityIndex[slot] = DATA_TYPE_HP;
+ mSelectedDataTypeIcon[slot] = mRes.getIdentifier(
+ dataTypeArray[type], null, NS);
+ mSelectedQSDataTypeIcon[slot] = QS_DATA_H;
+ mSelectedDataTypeDesc[slot] = mDataTypeDescriptionArray[type];
+ mSelectedSignalStreagthIndex[slot] = SIGNAL_STRENGTH_TYPE_HP;
+ } else {
+ mSelectedDataActivityIndex[slot] = DATA_TYPE_3G;
+ mSelectedDataTypeIcon[slot] = mRes.getIdentifier(
+ mDataTypeGenerationArray[0], null, NS);
+ mSelectedQSDataTypeIcon[slot] = QS_DATA_3G;
+ mSelectedDataTypeDesc[slot] = mDataTypeGenerationDescArray[0];
+ mSelectedSignalStreagthIndex[slot] = SIGNAL_STRENGTH_TYPE_3G;
+ }
+ break;
+ case TelephonyManager.NETWORK_TYPE_CDMA:
+ if (!showAtLeast3G) {
+ mSelectedDataActivityIndex[slot] = DATA_TYPE_1X;
+ mSelectedDataTypeIcon[slot] = mRes.getIdentifier(
+ dataTypeArray[type], null, NS);
+ mSelectedQSDataTypeIcon[slot] = QS_DATA_1X;
+ mSelectedDataTypeDesc[slot] = mDataTypeDescriptionArray[type];
+ mSelectedSignalStreagthIndex[slot] = SIGNAL_STRENGTH_TYPE_CDMA;
+ break;
+ } else {
+ // fall through
+ }
+ case TelephonyManager.NETWORK_TYPE_1xRTT:
+ if (!showAtLeast3G) {
+ mSelectedDataActivityIndex[slot] = DATA_TYPE_1X;
+ mSelectedDataTypeIcon[slot] = mRes.getIdentifier(
+ dataTypeArray[type], null, NS);
+ mSelectedQSDataTypeIcon[slot] = QS_DATA_1X;
+ mSelectedDataTypeDesc[slot] = mDataTypeDescriptionArray[type];
+ mSelectedSignalStreagthIndex[slot] = SIGNAL_STRENGTH_TYPE_1X;
+ break;
+ } else {
+ // fall through
+ }
+ case TelephonyManager.NETWORK_TYPE_EVDO_0: //fall through
+ case TelephonyManager.NETWORK_TYPE_EVDO_A:
+ case TelephonyManager.NETWORK_TYPE_EVDO_B:
+ case TelephonyManager.NETWORK_TYPE_EHRPD:
+ mSelectedDataActivityIndex[slot] = DATA_TYPE_3G;
+ mSelectedDataTypeIcon[slot] = mRes.getIdentifier(
+ dataTypeArray[type], null, NS);
+ mSelectedQSDataTypeIcon[slot] = QS_DATA_3G;
+ mSelectedDataTypeDesc[slot] = mDataTypeDescriptionArray[type];
+ mSelectedSignalStreagthIndex[slot] = SIGNAL_STRENGTH_TYPE_3G;
+ break;
+ case TelephonyManager.NETWORK_TYPE_LTE:
+ case TelephonyManager.NETWORK_TYPE_LTE_CA:
+ if (show4GforLte) {
+ mSelectedDataActivityIndex[slot] = DATA_TYPE_4G;
+ mSelectedDataTypeIcon[slot] = mRes.getIdentifier(
+ mDataTypeGenerationArray[1], null, NS);
+ if ( type == TelephonyManager.NETWORK_TYPE_LTE_CA) {
+ //Select 4G+ icon.
+ mSelectedDataTypeIcon[slot] = mRes.getIdentifier(
+ mDataTypeGenerationArray[2], null, NS);
+ }
+ mSelectedQSDataTypeIcon[slot] = QS_DATA_4G;
+ mSelectedDataTypeDesc[slot] = mDataTypeGenerationDescArray[1];
+ mSelectedSignalStreagthIndex[slot] = SIGNAL_STRENGTH_TYPE_4G;
+ } else {
+ mSelectedDataActivityIndex[slot] = DATA_TYPE_LTE;
+ mSelectedDataTypeIcon[slot] = mRes.getIdentifier(
+ dataTypeArray[type], null, NS);
+ mSelectedQSDataTypeIcon[slot] = QS_DATA_LTE;
+ mSelectedDataTypeDesc[slot] = mDataTypeDescriptionArray[type];
+ mSelectedSignalStreagthIndex[slot] = SIGNAL_STRENGTH_TYPE_4G;
+ }
+ break;
+ case TelephonyManager.NETWORK_TYPE_GPRS:
+ case TelephonyManager.NETWORK_TYPE_GSM:
+ if (!showAtLeast3G) {
+ mSelectedDataActivityIndex[slot] = DATA_TYPE_G;
+ mSelectedDataTypeIcon[slot] = mRes.getIdentifier(
+ dataTypeArray[type], null, NS);
+ mSelectedQSDataTypeIcon[slot] = QS_DATA_G;
+ mSelectedDataTypeDesc[slot] = mDataTypeDescriptionArray[type];
+ mSelectedSignalStreagthIndex[slot] = SIGNAL_STRENGTH_TYPE_G;
+ } else {
+ mSelectedDataActivityIndex[slot] = DATA_TYPE_3G;
+ mSelectedDataTypeIcon[slot] = mRes.getIdentifier(
+ mDataTypeGenerationArray[0], null, NS);
+ mSelectedQSDataTypeIcon[slot] = QS_DATA_3G;
+ mSelectedDataTypeDesc[slot] = mDataTypeGenerationDescArray[0];;
+ mSelectedSignalStreagthIndex[slot] = SIGNAL_STRENGTH_TYPE_3G;
+ }
+ break;
+ default:
+ mSelectedDataActivityIndex[slot] = DATA_TYPE_UNKNOWN;
+ mSelectedDataTypeIcon[slot] = 0;
+ mSelectedQSDataTypeIcon[slot] = 0;
+ mSelectedDataTypeDesc[slot] = "";
+ mSelectedSignalStreagthIndex[slot] = SIGNAL_STRENGTH_TYPE_G;
+ break;
+ }
+ log(TAG, "updateDataType " + String.format(
+ "mSelectedDataTypeIcon[%d]=%d, mSelectedDataActivityIndex=%d",
+ slot, mSelectedDataTypeIcon[slot], mSelectedDataActivityIndex[slot]));
+ }
+
+
+ static int getQSDataTypeIcon(int slot) {
+ return mSelectedQSDataTypeIcon[slot];
+ }
+
+ static int getDataTypeIcon(int slot) {
+ log(TAG, "getDataTypeIcon " + String.format("sub=%d", slot));
+ return mSelectedDataTypeIcon[slot];
+ }
+
+ static int getDataTypeDesc(int slot) {
+ return mRes.getIdentifier(mSelectedDataTypeDesc[slot], null, NS);
+ }
+
+ static int getDataActivity(int slot, int activity) {
+ log(TAG, String.format("getDataActivity, slot=%d, activity=%d",
+ slot, activity));
+
+ String[] dataActivityArray = mRes.getStringArray(
+ mRes.getIdentifier(mDataActivityArray[slot], null, NS));
+ String[] selectedTypeArray = mRes.getStringArray(mRes.getIdentifier(
+ dataActivityArray[mSelectedDataActivityIndex[slot]], null, NS));
+
+ return mRes.getIdentifier(selectedTypeArray[activity], null, NS);
+ }
+
+ static int getSignalStrengthIcon(int slot, int inet, int level, boolean roaming) {
+ log(TAG, "getSignalStrengthIcon: " + String.format(
+ "slot=%d, inetCondition=%d, level=%d, roaming=%b", slot, inet, level, roaming));
+
+ String[] signalStrengthArray, selectedTypeArray;
+
+ signalStrengthArray = mRes.getStringArray(mRes.getIdentifier(!roaming ?
+ mSignalStrengthArray[slot] : mSignalStrengthRoamingArray[slot], null, NS));
+ log(TAG, String.format("signalStrengthArray.length=%d", signalStrengthArray.length));
+
+ selectedTypeArray = mRes.getStringArray(mRes.getIdentifier(
+ signalStrengthArray[mSelectedSignalStreagthIndex[slot]], null, NS));
+ log(TAG, String.format("selectedTypeArray.length=%d", selectedTypeArray.length));
+
+ String[] inetArray = mRes.getStringArray(
+ mRes.getIdentifier(selectedTypeArray[inet], null, NS));
+ log(TAG, String.format("inetArray.length=%d", inetArray.length));
+
+ return mRes.getIdentifier(inetArray[level], null, NS);
+ }
+
+
+ static int convertMobileStrengthIcon(int stackedIcon) {
+ if (mStacked2SingleIconLookup == null) {
+ return stackedIcon;
+ }
+ int index = mStacked2SingleIconLookup.indexOfKey(stackedIcon);
+ if (index >= 0) {
+ return mStacked2SingleIconLookup.get(stackedIcon);
+ }
+ return stackedIcon;
+ }
+
+ static int getStackedVoiceIcon(int level) {
+ int retValue = 0;
+ switch(level){
+ case SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN:
+ retValue = R.drawable.stat_sys_signal_0_2g;
+ break;
+ case SignalStrength.SIGNAL_STRENGTH_POOR:
+ retValue = R.drawable.stat_sys_signal_1_2g;
+ break;
+ case SignalStrength.SIGNAL_STRENGTH_MODERATE:
+ retValue = R.drawable.stat_sys_signal_2_2g;
+ break;
+ case SignalStrength.SIGNAL_STRENGTH_GOOD:
+ retValue = R.drawable.stat_sys_signal_3_2g;
+ break;
+ case SignalStrength.SIGNAL_STRENGTH_GREAT:
+ retValue = R.drawable.stat_sys_signal_4_2g;
+ break;
+ default:
+ break;
+ }
+ return retValue;
+ }
+
+ static int getRoamingSignalIconId(int level, int inet){
+ return TELEPHONY_SIGNAL_STRENGTH_ROAMING_R[inet][level];
+ }
+
+ static int[] getSignalStrengthDes(int slot) {
+ int[] resId = new int[SIGNAL_LEVEL_NUM];
+ for (int i = 0; i < SIGNAL_LEVEL_NUM; i++) {
+ resId[i] = mRes.getIdentifier(mSignalStrengthDesc[i], null, NS);
+ }
+ return resId;
+ }
+
+ private static void log(String tag, String str){
+ if (DEBUG) {
+ Log.d(tag, str);
+ }
+ }
+
static final MobileIconGroup CARRIER_NETWORK_CHANGE = new MobileIconGroup(
"CARRIER_NETWORK_CHANGE",
@@ -344,6 +780,21 @@ class TelephonyIcons {
TelephonyIcons.QS_DATA_4G
);
+ static final MobileIconGroup FOUR_G_PLUS = new MobileIconGroup(
+ "4G+",
+ TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH,
+ TelephonyIcons.QS_TELEPHONY_SIGNAL_STRENGTH,
+ AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH,
+ 0,0,
+ TelephonyIcons.TELEPHONY_NO_NETWORK,
+ TelephonyIcons.QS_TELEPHONY_NO_NETWORK,
+ AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0],
+ R.string.accessibility_data_connection_4g_plus,
+ TelephonyIcons.ICON_4G_PLUS,
+ true,
+ TelephonyIcons.QS_DATA_4G_PLUS
+ );
+
static final MobileIconGroup LTE = new MobileIconGroup(
"LTE",
TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
index 3e8d4e9..38fb275 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
@@ -53,6 +53,7 @@ import com.android.systemui.R;
import com.android.systemui.qs.QSTile;
import com.android.systemui.qs.tiles.UserDetailView;
import com.android.systemui.statusbar.phone.SystemUIDialog;
+import cyanogenmod.app.StatusBarPanelCustomTile;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -587,6 +588,11 @@ public class UserSwitcherController {
}
@Override
+ public StatusBarPanelCustomTile getCustomTile() {
+ return null;
+ }
+
+ @Override
public Boolean getToggleState() {
return null;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WeatherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WeatherController.java
new file mode 100644
index 0000000..1fa4956
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WeatherController.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2014 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 com.android.systemui.statusbar.policy;
+
+public interface WeatherController {
+ void addCallback(Callback callback);
+ void removeCallback(Callback callback);
+ WeatherInfo getWeatherInfo();
+
+ public interface Callback {
+ void onWeatherChanged(WeatherInfo temp);
+ }
+ public static class WeatherInfo {
+ public String temp = null;
+ public String city = null;
+ public String condition = null;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WeatherControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WeatherControllerImpl.java
new file mode 100644
index 0000000..288bc7e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WeatherControllerImpl.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2014 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 com.android.systemui.statusbar.policy;
+
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.database.ContentObserver;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Handler;
+import android.provider.Settings;
+import android.util.Log;
+
+import java.util.ArrayList;
+
+public class WeatherControllerImpl implements WeatherController {
+
+ private static final String TAG = WeatherController.class.getSimpleName();
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+ public static final ComponentName COMPONENT_WEATHER_FORECAST = new ComponentName(
+ "com.cyanogenmod.lockclock", "com.cyanogenmod.lockclock.weather.ForecastActivity");
+ public static final String ACTION_UPDATE_FINISHED
+ = "com.cyanogenmod.lockclock.action.WEATHER_UPDATE_FINISHED";
+ public static final String EXTRA_UPDATE_CANCELLED = "update_cancelled";
+ public static final String ACTION_FORCE_WEATHER_UPDATE
+ = "com.cyanogenmod.lockclock.action.FORCE_WEATHER_UPDATE";
+ public static final Uri CURRENT_WEATHER_URI
+ = Uri.parse("content://com.cyanogenmod.lockclock.weather.provider/weather/current");
+ public static final String[] WEATHER_PROJECTION = new String[]{
+ "temperature",
+ "city",
+ "condition"
+ };
+
+ private final ArrayList<Callback> mCallbacks = new ArrayList<Callback>();
+ private final Receiver mReceiver = new Receiver();
+ private final Context mContext;
+
+ private WeatherInfo mCachedInfo = new WeatherInfo();
+
+ public WeatherControllerImpl(Context context) {
+ mContext = context;
+ mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
+ queryWeather();
+ final IntentFilter filter = new IntentFilter();
+ filter.addAction(ACTION_UPDATE_FINISHED);
+ mContext.registerReceiver(mReceiver, filter);
+ }
+
+ public void addCallback(Callback callback) {
+ if (callback == null || mCallbacks.contains(callback)) return;
+ if (DEBUG) Log.d(TAG, "addCallback " + callback);
+ mCallbacks.add(callback);
+ callback.onWeatherChanged(mCachedInfo); // immediately update with current values
+ }
+
+ public void removeCallback(Callback callback) {
+ if (callback == null) return;
+ if (DEBUG) Log.d(TAG, "removeCallback " + callback);
+ mCallbacks.remove(callback);
+ }
+
+ @Override
+ public WeatherInfo getWeatherInfo() {
+ return mCachedInfo;
+ }
+
+ private void queryWeather() {
+ Cursor c = mContext.getContentResolver().query(CURRENT_WEATHER_URI, WEATHER_PROJECTION,
+ null, null, null);
+ if (c == null) {
+ if(DEBUG) Log.e(TAG, "cursor was null for temperature, forcing weather update");
+ mContext.sendBroadcast(new Intent(ACTION_FORCE_WEATHER_UPDATE));
+ } else {
+ try {
+ c.moveToFirst();
+ mCachedInfo.temp = c.getString(0);
+ mCachedInfo.city = c.getString(1);
+ mCachedInfo.condition = c.getString(2);
+ } finally {
+ c.close();
+ }
+ }
+ }
+
+ private void fireCallback() {
+ for (Callback callback : mCallbacks) {
+ callback.onWeatherChanged(mCachedInfo);
+ }
+ }
+
+ private final class Receiver extends BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (DEBUG) Log.d(TAG, "onReceive " + intent.getAction());
+ if (intent.hasExtra(EXTRA_UPDATE_CANCELLED)) {
+ if (intent.getBooleanExtra(EXTRA_UPDATE_CANCELLED, false)) {
+ // no update
+ return;
+ }
+ }
+ queryWeather();
+ fireCallback();
+ }
+ }
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java
index 9b1e72a..29be2c9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java
@@ -29,6 +29,7 @@ import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.AsyncChannel;
+import com.android.systemui.R;
import com.android.systemui.statusbar.policy.NetworkController.IconState;
import java.util.List;
@@ -75,8 +76,10 @@ public class WifiSignalController extends
@Override
public void notifyListeners() {
// only show wifi in the cluster if connected or if wifi-only
+ boolean visibleWhenEnabled = mContext.getResources().getBoolean(
+ R.bool.config_showWifiIndicatorWhenEnabled);
boolean wifiVisible = mCurrentState.enabled
- && (mCurrentState.connected || !mHasMobileData);
+ && (mCurrentState.connected || !mHasMobileData || visibleWhenEnabled);
String wifiDesc = wifiVisible ? mCurrentState.ssid : null;
boolean ssidPresent = wifiVisible && mCurrentState.ssid != null;
String contentDescription = getStringIfExists(getContentDescription());
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index af38f5f..4ec8b43 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -53,6 +53,8 @@ import com.android.systemui.statusbar.phone.ScrimController;
import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.statusbar.policy.ScrollAdapter;
+import cyanogenmod.power.PerformanceManager;
+
import java.util.ArrayList;
import java.util.HashSet;
@@ -208,6 +210,9 @@ public class NotificationStackScrollLayout extends ViewGroup
private boolean mDelegateToScrollView;
private boolean mDisallowScrollingInThisMotion;
private long mGoToFullShadeDelay;
+
+ private final PerformanceManager mPerf;
+
private ViewTreeObserver.OnPreDrawListener mChildrenUpdater
= new ViewTreeObserver.OnPreDrawListener() {
@Override
@@ -254,6 +259,8 @@ public class NotificationStackScrollLayout extends ViewGroup
mExpandHelper.setEventSource(this);
mExpandHelper.setScrollAdapter(this);
+ mPerf = PerformanceManager.getInstance(context);
+
mSwipeHelper = new SwipeHelper(SwipeHelper.X, this, getContext());
mSwipeHelper.setLongPressListener(mLongPressListener);
initView(context);
@@ -839,6 +846,11 @@ public class NotificationStackScrollLayout extends ViewGroup
&& !mOnlyScrollingInThisMotion) {
horizontalSwipeWantsIt = mSwipeHelper.onTouchEvent(ev);
}
+
+ if (expandWantsIt && mIsBeingDragged) {
+ mPerf.cpuBoost(200 * 1000);
+ }
+
return horizontalSwipeWantsIt || scrollerWantsIt || expandWantsIt || super.onTouchEvent(ev);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
index cf696a1..93995f8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
@@ -42,6 +42,8 @@ public class StackScrollAlgorithm {
private static final int MAX_ITEMS_IN_BOTTOM_STACK = 3;
private static final int MAX_ITEMS_IN_TOP_STACK = 3;
+ private static final int DEFAULT_CORNER_RADIUS = 2;
+
public static final float DIMMED_SCALE = 0.95f;
private int mPaddingBetweenElements;
@@ -72,6 +74,7 @@ public class StackScrollAlgorithm {
private int mMaxNotificationHeight;
private boolean mScaleDimmed;
private HeadsUpManager mHeadsUpManager;
+ private boolean mPerformClipping;
public StackScrollAlgorithm(Context context) {
initConstants(context);
@@ -128,6 +131,12 @@ public class StackScrollAlgorithm {
R.dimen.notification_collapse_second_card_padding);
mScaleDimmed = context.getResources().getDisplayMetrics().densityDpi
>= DisplayMetrics.DENSITY_420;
+
+ // We don't want to clip the notification if a theme overrides the corner radius with
+ // a value larger than the default.
+ mPerformClipping = context.getResources()
+ .getDimension(R.dimen.notification_material_rounded_rect_radius) <=
+ DEFAULT_CORNER_RADIUS * context.getResources().getDisplayMetrics().density;
}
public boolean shouldScaleDimmed() {
@@ -228,8 +237,7 @@ public class StackScrollAlgorithm {
// In the unlocked shade we have to clip a little bit higher because of the rounded
// corners of the notifications, but only if we are not fully overlapped by
// the top card.
- float clippingCorrection = state.dimmed
- ? 0
+ float clippingCorrection = state.dimmed ? (mPerformClipping ? 0 : newHeight)
: mRoundedRectCornerRadius * state.scale;
clipHeight += clippingCorrection;
}
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/QsTuner.java b/packages/SystemUI/src/com/android/systemui/tuner/QsTuner.java
index 37ac098..95ca509 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/QsTuner.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/QsTuner.java
@@ -15,14 +15,23 @@
*/
package com.android.systemui.tuner;
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
import android.app.ActivityManager;
import android.app.AlertDialog;
import android.app.Fragment;
import android.content.ClipData;
+import android.content.ClipDescription;
import android.content.Context;
import android.content.DialogInterface;
+import android.graphics.Canvas;
+import android.graphics.Point;
+import android.graphics.PointF;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.provider.Settings.Secure;
+import android.support.v4.view.ViewPager;
import android.text.TextUtils;
import android.util.Log;
import android.view.DragEvent;
@@ -30,11 +39,9 @@ import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
-import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnDragListener;
-import android.view.View.OnTouchListener;
import android.view.ViewGroup;
import android.widget.EditText;
import android.widget.FrameLayout;
@@ -42,6 +49,8 @@ import android.widget.ScrollView;
import com.android.internal.logging.MetricsLogger;
import com.android.systemui.R;
+import com.android.systemui.qs.QSDragPanel;
+import com.android.systemui.qs.QSPage;
import com.android.systemui.qs.QSPanel;
import com.android.systemui.qs.QSTile;
import com.android.systemui.qs.QSTile.Host.Callback;
@@ -52,6 +61,7 @@ import com.android.systemui.statusbar.phone.QSTileHost;
import com.android.systemui.statusbar.policy.SecurityController;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
public class QsTuner extends Fragment implements Callback {
@@ -59,16 +69,13 @@ public class QsTuner extends Fragment implements Callback {
private static final String TAG = "QsTuner";
private static final int MENU_RESET = Menu.FIRST;
+ private static final int MENU_EDIT = Menu.FIRST + 1;
private DraggableQsPanel mQsPanel;
private CustomHost mTileHost;
- private FrameLayout mDropTarget;
-
private ScrollView mScrollRoot;
- private FrameLayout mAddTarget;
-
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -78,6 +85,7 @@ public class QsTuner extends Fragment implements Callback {
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
menu.add(0, MENU_RESET, 0, com.android.internal.R.string.reset);
+ menu.add(0, MENU_EDIT, 0, "toggle edit");
}
public void onResume() {
@@ -93,8 +101,11 @@ public class QsTuner extends Fragment implements Callback {
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
+ case MENU_EDIT:
+ mQsPanel.setEditing(!mQsPanel.isEditing());
+ break;
case MENU_RESET:
- mTileHost.reset();
+ mTileHost.resetTiles();
break;
case android.R.id.home:
getFragmentManager().popBackStack();
@@ -105,7 +116,7 @@ public class QsTuner extends Fragment implements Callback {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
- Bundle savedInstanceState) {
+ Bundle savedInstanceState) {
mScrollRoot = (ScrollView) inflater.inflate(R.layout.tuner_qs, container, false);
mQsPanel = new DraggableQsPanel(getContext());
@@ -116,10 +127,6 @@ public class QsTuner extends Fragment implements Callback {
mQsPanel.refreshAllTiles();
((ViewGroup) mScrollRoot.findViewById(R.id.all_details)).addView(mQsPanel, 0);
- mDropTarget = (FrameLayout) mScrollRoot.findViewById(R.id.remove_target);
- setupDropTarget();
- mAddTarget = (FrameLayout) mScrollRoot.findViewById(R.id.add_target);
- setupAddTarget();
return mScrollRoot;
}
@@ -129,78 +136,23 @@ public class QsTuner extends Fragment implements Callback {
super.onDestroyView();
}
- private void setupDropTarget() {
- QSTileView tileView = new QSTileView(getContext());
- QSTile.State state = new QSTile.State();
- state.visible = true;
- state.icon = ResourceIcon.get(R.drawable.ic_delete);
- state.label = getString(com.android.internal.R.string.delete);
- tileView.onStateChanged(state);
- mDropTarget.addView(tileView);
- mDropTarget.setVisibility(View.GONE);
- new DragHelper(tileView, new DropListener() {
- @Override
- public void onDrop(String sourceText) {
- mTileHost.remove(sourceText);
- }
- });
- }
-
- private void setupAddTarget() {
- QSTileView tileView = new QSTileView(getContext());
- QSTile.State state = new QSTile.State();
- state.visible = true;
- state.icon = ResourceIcon.get(R.drawable.ic_add_circle_qs);
- state.label = getString(R.string.add_tile);
- tileView.onStateChanged(state);
- mAddTarget.addView(tileView);
- tileView.setClickable(true);
- tileView.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- mTileHost.showAddDialog();
- }
- });
- }
-
- public void onStartDrag() {
- mDropTarget.post(new Runnable() {
- @Override
- public void run() {
- mDropTarget.setVisibility(View.VISIBLE);
- mAddTarget.setVisibility(View.GONE);
- }
- });
+ @Override
+ public void onTilesChanged() {
+ mQsPanel.setTiles(mTileHost.getTiles());
}
- public void stopDrag() {
- mDropTarget.post(new Runnable() {
- @Override
- public void run() {
- mDropTarget.setVisibility(View.GONE);
- mAddTarget.setVisibility(View.VISIBLE);
- }
- });
+ @Override
+ public void setEditing(boolean editing) {
+ mQsPanel.setEditing(editing);
}
@Override
- public void onTilesChanged() {
- mQsPanel.setTiles(mTileHost.getTiles());
+ public boolean isEditing() {
+ return mTileHost.isEditing();
}
- private static int getLabelResource(String spec) {
- if (spec.equals("wifi")) return R.string.quick_settings_wifi_label;
- else if (spec.equals("bt")) return R.string.quick_settings_bluetooth_label;
- else if (spec.equals("inversion")) return R.string.quick_settings_inversion_label;
- else if (spec.equals("cell")) return R.string.quick_settings_cellular_detail_title;
- else if (spec.equals("airplane")) return R.string.airplane_mode;
- else if (spec.equals("dnd")) return R.string.quick_settings_dnd_label;
- else if (spec.equals("rotation")) return R.string.quick_settings_rotation_locked_label;
- else if (spec.equals("flashlight")) return R.string.quick_settings_flashlight_label;
- else if (spec.equals("location")) return R.string.quick_settings_location_label;
- else if (spec.equals("cast")) return R.string.quick_settings_cast_title;
- else if (spec.equals("hotspot")) return R.string.quick_settings_hotspot_label;
- return 0;
+ @Override
+ public void goToSettingsPage() {
}
private static class CustomHost extends QSTileHost {
@@ -211,7 +163,7 @@ public class QsTuner extends Fragment implements Callback {
}
@Override
- protected QSTile<?> createTile(String tileSpec) {
+ public QSTile<?> createTile(String tileSpec) {
return new DraggableTile(this, tileSpec);
}
@@ -232,97 +184,6 @@ public class QsTuner extends Fragment implements Callback {
setTiles(order);
}
- public void remove(String tile) {
- MetricsLogger.action(getContext(), MetricsLogger.TUNER_QS_REMOVE, tile);
- List<String> tiles = new ArrayList<>(mTileSpecs);
- tiles.remove(tile);
- setTiles(tiles);
- }
-
- public void add(String tile) {
- MetricsLogger.action(getContext(), MetricsLogger.TUNER_QS_ADD, tile);
- List<String> tiles = new ArrayList<>(mTileSpecs);
- tiles.add(tile);
- setTiles(tiles);
- }
-
- public void reset() {
- Secure.putStringForUser(getContext().getContentResolver(),
- TILES_SETTING, "default", ActivityManager.getCurrentUser());
- }
-
- private void setTiles(List<String> tiles) {
- Secure.putStringForUser(getContext().getContentResolver(), TILES_SETTING,
- TextUtils.join(",", tiles), ActivityManager.getCurrentUser());
- }
-
- public void showAddDialog() {
- List<String> tiles = mTileSpecs;
- int numBroadcast = 0;
- for (int i = 0; i < tiles.size(); i++) {
- if (tiles.get(i).startsWith(IntentTile.PREFIX)) {
- numBroadcast++;
- }
- }
- String[] defaults =
- getContext().getString(R.string.quick_settings_tiles_default).split(",");
- final String[] available = new String[defaults.length + 1
- - (tiles.size() - numBroadcast)];
- final String[] availableTiles = new String[available.length];
- int index = 0;
- for (int i = 0; i < defaults.length; i++) {
- if (tiles.contains(defaults[i])) {
- continue;
- }
- int resource = getLabelResource(defaults[i]);
- if (resource != 0) {
- availableTiles[index] = defaults[i];
- available[index++] = getContext().getString(resource);
- } else {
- availableTiles[index] = defaults[i];
- available[index++] = defaults[i];
- }
- }
- available[index++] = getContext().getString(R.string.broadcast_tile);
- new AlertDialog.Builder(getContext())
- .setTitle(R.string.add_tile)
- .setItems(available, new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int which) {
- if (which < available.length - 1) {
- add(availableTiles[which]);
- } else {
- showBroadcastTileDialog();
- }
- }
- }).show();
- }
-
- public void showBroadcastTileDialog() {
- final EditText editText = new EditText(getContext());
- new AlertDialog.Builder(getContext())
- .setTitle(R.string.broadcast_tile)
- .setView(editText)
- .setNegativeButton(android.R.string.cancel, null)
- .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int which) {
- String action = editText.getText().toString();
- if (isValid(action)) {
- add(IntentTile.PREFIX + action + ')');
- }
- }
- }).show();
- }
-
- private boolean isValid(String action) {
- for (int i = 0; i < action.length(); i++) {
- char c = action.charAt(i);
- if (!Character.isAlphabetic(c) && !Character.isDigit(c) && c != '.') {
- return false;
- }
- }
- return true;
- }
-
private static class BlankSecurityController implements SecurityController {
@Override
public boolean hasDeviceOwner() {
@@ -373,8 +234,7 @@ public class QsTuner extends Fragment implements Callback {
}
}
- private static class DraggableTile extends QSTile<QSTile.State>
- implements DropListener {
+ public static class DraggableTile extends QSTile<QSTile.State> {
private String mSpec;
private QSTileView mView;
@@ -391,7 +251,7 @@ public class QsTuner extends Fragment implements Callback {
}
@Override
- public boolean supportsDualTargets() {
+ public boolean hasDualTargetsDetails() {
return "wifi".equals(mSpec) || "bt".equals(mSpec);
}
@@ -416,7 +276,7 @@ public class QsTuner extends Fragment implements Callback {
}
private String getLabel() {
- int resource = getLabelResource(mSpec);
+ int resource = QSTileHost.getLabelResource(mSpec);
if (resource != 0) {
return mContext.getString(resource);
}
@@ -460,81 +320,19 @@ public class QsTuner extends Fragment implements Callback {
}
@Override
- public void onDrop(String sourceText) {
- ((CustomHost) mHost).replace(mSpec, sourceText);
- }
-
- }
-
- private class DragHelper implements OnDragListener {
-
- private final View mView;
- private final DropListener mListener;
-
- public DragHelper(View view, DropListener dropListener) {
- mView = view;
- mListener = dropListener;
- mView.setOnDragListener(this);
- }
-
- @Override
- public boolean onDrag(View v, DragEvent event) {
- switch (event.getAction()) {
- case DragEvent.ACTION_DRAG_ENTERED:
- mView.setBackgroundColor(0x77ffffff);
- break;
- case DragEvent.ACTION_DRAG_ENDED:
- stopDrag();
- case DragEvent.ACTION_DRAG_EXITED:
- mView.setBackgroundColor(0x0);
- break;
- case DragEvent.ACTION_DROP:
- stopDrag();
- String text = event.getClipData().getItemAt(0).getText().toString();
- mListener.onDrop(text);
- break;
- }
- return true;
+ public String toString() {
+ return mSpec;
}
-
}
- public interface DropListener {
- void onDrop(String sourceText);
- }
+ private class DraggableQsPanel extends QSDragPanel {
- private class DraggableQsPanel extends QSPanel implements OnTouchListener {
public DraggableQsPanel(Context context) {
super(context);
- mBrightnessView.setVisibility(View.GONE);
- }
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
- for (TileRecord r : mRecords) {
- new DragHelper(r.tileView, (DraggableTile) r.tile);
- r.tileView.setTag(r.tile);
- r.tileView.setOnTouchListener(this);
-
- for (int i = 0; i < r.tileView.getChildCount(); i++) {
- r.tileView.getChildAt(i).setClickable(false);
- }
- }
+ setEditing(true);
}
- @Override
- public boolean onTouch(View v, MotionEvent event) {
- switch (event.getAction()) {
- case MotionEvent.ACTION_DOWN:
- String tileSpec = (String) ((DraggableTile) v.getTag()).mSpec;
- ClipData data = ClipData.newPlainText(tileSpec, tileSpec);
- v.startDrag(data, new View.DragShadowBuilder(v), null, 0);
- onStartDrag();
- return true;
- }
- return false;
- }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java
index 71b5de5..1ff5cef 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java
@@ -15,8 +15,6 @@
*/
package com.android.systemui.tuner;
-import static com.android.systemui.BatteryMeterView.SHOW_PERCENT_SETTING;
-
import android.app.AlertDialog;
import android.app.FragmentTransaction;
import android.content.DialogInterface;
@@ -105,8 +103,6 @@ public class TunerFragment extends PreferenceFragment {
public void onResume() {
super.onResume();
updateBatteryPct();
- getContext().getContentResolver().registerContentObserver(
- System.getUriFor(SHOW_PERCENT_SETTING), false, mSettingObserver);
registerPrefs(getPreferenceScreen());
MetricsLogger.visibility(getContext(), MetricsLogger.TUNER, true);
@@ -172,8 +168,6 @@ public class TunerFragment extends PreferenceFragment {
private void updateBatteryPct() {
mBatteryPct.setOnPreferenceChangeListener(null);
- mBatteryPct.setChecked(System.getInt(getContext().getContentResolver(),
- SHOW_PERCENT_SETTING, 0) != 0);
mBatteryPct.setOnPreferenceChangeListener(mBatteryPctChange);
}
@@ -194,7 +188,6 @@ public class TunerFragment extends PreferenceFragment {
public boolean onPreferenceChange(Preference preference, Object newValue) {
final boolean v = (Boolean) newValue;
MetricsLogger.action(getContext(), MetricsLogger.TUNER_BATTERY_PERCENTAGE, v);
- System.putInt(getContext().getContentResolver(), SHOW_PERCENT_SETTING, v ? 1 : 0);
return true;
}
};
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java
index 50234b2..b2c90be 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java
@@ -31,6 +31,7 @@ import android.os.Handler;
import android.os.Looper;
import android.os.UserHandle;
import android.provider.Settings;
+import android.text.TextUtils;
import android.util.ArrayMap;
import com.android.systemui.BatteryMeterView;
@@ -40,6 +41,7 @@ import com.android.systemui.SystemUI;
import com.android.systemui.SystemUIApplication;
import com.android.systemui.settings.CurrentUserTracker;
import com.android.systemui.statusbar.phone.SystemUIDialog;
+import cyanogenmod.providers.CMSettings;
import java.util.ArrayList;
import java.util.HashMap;
@@ -84,17 +86,31 @@ public class TunerService extends SystemUI {
}
private void addTunable(Tunable tunable, String key) {
+ addTunableByProvider(tunable, key, false);
+ }
+
+ public void addTunableByProvider(Tunable tunable, String key, boolean cm) {
if (!mTunableLookup.containsKey(key)) {
mTunableLookup.put(key, new ArrayList<Tunable>());
}
mTunableLookup.get(key).add(tunable);
- Uri uri = Settings.Secure.getUriFor(key);
+ Uri uri;
+ if (!cm) {
+ uri = Settings.Secure.getUriFor(key);
+ } else {
+ uri = CMSettings.Secure.getUriFor(key);
+ }
if (!mListeningUris.containsKey(uri)) {
mListeningUris.put(uri, key);
mContentResolver.registerContentObserver(uri, false, mObserver, mCurrentUser);
}
// Send the first state.
- String value = Settings.Secure.getStringForUser(mContentResolver, key, mCurrentUser);
+ String value;
+ if (cm) {
+ value = CMSettings.Secure.getStringForUser(mContentResolver, key, mCurrentUser);
+ } else {
+ value = Settings.Secure.getStringForUser(mContentResolver, key, mCurrentUser);
+ }
tunable.onTuningChanged(key, value);
}
@@ -116,7 +132,12 @@ public class TunerService extends SystemUI {
public void reloadSetting(Uri uri) {
String key = mListeningUris.get(uri);
- String value = Settings.Secure.getStringForUser(mContentResolver, key, mCurrentUser);
+ String value;
+ if (uri.getAuthority().equals(CMSettings.AUTHORITY)) {
+ value = CMSettings.Secure.getStringForUser(mContentResolver, key, mCurrentUser);
+ } else {
+ value = Settings.Secure.getStringForUser(mContentResolver, key, mCurrentUser);
+ }
for (Tunable tunable : mTunableLookup.get(key)) {
tunable.onTuningChanged(key, value);
}
@@ -124,8 +145,14 @@ public class TunerService extends SystemUI {
private void reloadAll() {
for (String key : mTunableLookup.keySet()) {
- String value = Settings.Secure.getStringForUser(mContentResolver, key,
- mCurrentUser);
+ String value;
+ Uri uri = CMSettings.Secure.getUriFor(key);
+ if (uri.getAuthority() != null && uri.getAuthority().equals(CMSettings.AUTHORITY)) {
+ value = CMSettings.Secure.getStringForUser(mContentResolver, key, mCurrentUser);
+ } else {
+ value = Settings.Secure.getStringForUser(mContentResolver, key,
+ mCurrentUser);
+ }
for (Tunable tunable : mTunableLookup.get(key)) {
tunable.onTuningChanged(key, value);
}
@@ -135,13 +162,17 @@ public class TunerService extends SystemUI {
public void clearAll() {
// A couple special cases.
Settings.Global.putString(mContentResolver, DemoMode.DEMO_MODE_ALLOWED, null);
- Settings.System.putString(mContentResolver, BatteryMeterView.SHOW_PERCENT_SETTING, null);
Intent intent = new Intent(DemoMode.ACTION_DEMO);
intent.putExtra(DemoMode.EXTRA_COMMAND, DemoMode.COMMAND_EXIT);
mContext.sendBroadcast(intent);
for (String key : mTunableLookup.keySet()) {
- Settings.Secure.putString(mContentResolver, key, null);
+ Uri uri = CMSettings.Secure.getUriFor(key);
+ if (uri.getAuthority() != null && uri.getAuthority().equals(CMSettings.AUTHORITY)) {
+ CMSettings.Secure.putString(mContentResolver, key, null);
+ } else {
+ Settings.Secure.putString(mContentResolver, key, null);
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java b/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java
index 180d918..7d34cdc 100644
--- a/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java
+++ b/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java
@@ -256,6 +256,11 @@ public class StorageNotification extends SystemUI {
}
private void onPublicVolumeStateChangedInternal(VolumeInfo vol) {
+ // Do not notify for volumes on non-removable disks
+ if (vol.disk.isNonRemovable()) {
+ return;
+ }
+
Log.d(TAG, "Notifying about public volume: " + vol.toString());
final Notification notif;
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java
index 2688813..e49ff50 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java
@@ -27,6 +27,7 @@ import android.content.DialogInterface.OnClickListener;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
+import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.media.AudioManager;
import android.media.session.MediaSessionManager;
@@ -63,6 +64,8 @@ public class VolumeUI extends SystemUI {
private VolumeDialogComponent mVolumeComponent;
+ private Configuration mConfiguration;
+
@Override
public void start() {
mEnabled = mContext.getResources().getBoolean(R.bool.enable_volume_ui);
@@ -80,6 +83,7 @@ public class VolumeUI extends SystemUI {
mContext, Settings.Secure.VOLUME_CONTROLLER_SERVICE_COMPONENT,
new ServiceMonitorCallbacks());
mVolumeControllerService.start();
+ mConfiguration = new Configuration(mContext.getResources().getConfiguration());
}
private VolumeComponent getVolumeComponent() {
@@ -91,6 +95,21 @@ public class VolumeUI extends SystemUI {
super.onConfigurationChanged(newConfig);
if (!mEnabled) return;
getVolumeComponent().onConfigurationChanged(newConfig);
+
+ if (isThemeChange(newConfig)) {
+ // TODO: implement initPanel() if needed
+ //initPanel();
+ mContext.recreateTheme();
+ }
+ mConfiguration.setTo(newConfig);
+ }
+
+ private boolean isThemeChange(Configuration newConfig) {
+ if (mConfiguration != null) {
+ int changes = mConfiguration.updateFrom(newConfig);
+ return (changes & ActivityInfo.CONFIG_THEME_RESOURCE) != 0;
+ }
+ return false;
}
@Override
diff --git a/packages/SystemUI/src/com/viewpagerindicator/CirclePageIndicator.java b/packages/SystemUI/src/com/viewpagerindicator/CirclePageIndicator.java
new file mode 100644
index 0000000..4286983
--- /dev/null
+++ b/packages/SystemUI/src/com/viewpagerindicator/CirclePageIndicator.java
@@ -0,0 +1,527 @@
+/*
+ * Copyright (C) 2011 Patrik Akerfeldt
+ * Copyright (C) 2011 Jake Wharton
+ *
+ * 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.viewpagerindicator;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Paint.Style;
+import android.graphics.drawable.Drawable;
+import android.support.v4.view.MotionEventCompat;
+import android.support.v4.view.ViewConfigurationCompat;
+import android.support.v4.view.ViewPager;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewConfiguration;
+import com.android.systemui.R;
+
+import static android.graphics.Paint.ANTI_ALIAS_FLAG;
+import static android.widget.LinearLayout.HORIZONTAL;
+import static android.widget.LinearLayout.VERTICAL;
+
+/**
+ * Draws circles (one for each view). The current view position is filled and
+ * others are only stroked.
+ */
+public class CirclePageIndicator extends View implements PageIndicator {
+ private static final int INVALID_POINTER = -1;
+
+ private float mRadius;
+ private final Paint mPaintPageFill = new Paint(ANTI_ALIAS_FLAG);
+ private final Paint mPaintStroke = new Paint(ANTI_ALIAS_FLAG);
+ private final Paint mPaintFill = new Paint(ANTI_ALIAS_FLAG);
+ private ViewPager mViewPager;
+ private ViewPager.OnPageChangeListener mListener;
+ private int mCurrentPage;
+ private int mSnapPage;
+ private float mPageOffset;
+ private int mScrollState;
+ private int mOrientation;
+ private boolean mCentered;
+ private boolean mSnap;
+
+ private int mTouchSlop;
+ private float mLastMotionX = -1;
+ private int mActivePointerId = INVALID_POINTER;
+ private boolean mIsDragging;
+
+ private Bitmap mSettingsIcon;
+ private boolean mEditing;
+
+ public CirclePageIndicator(Context context) {
+ this(context, null);
+ }
+
+ public CirclePageIndicator(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public CirclePageIndicator(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ if (isInEditMode()) return;
+
+ //Load defaults from resources
+ final Resources res = getResources();
+ final int defaultPageColor = res.getColor(R.color.default_circle_indicator_page_color);
+ final int defaultFillColor = res.getColor(R.color.default_circle_indicator_fill_color);
+ final int defaultOrientation = res.getInteger(R.integer.default_circle_indicator_orientation);
+ final int defaultStrokeColor = res.getColor(R.color.default_circle_indicator_stroke_color);
+ final float defaultStrokeWidth = res.getDimension(R.dimen.default_circle_indicator_stroke_width);
+ final float defaultRadius = res.getDimension(R.dimen.default_circle_indicator_radius);
+ final boolean defaultCentered = res.getBoolean(R.bool.default_circle_indicator_centered);
+ final boolean defaultSnap = res.getBoolean(R.bool.default_circle_indicator_snap);
+
+ //Retrieve styles attributes
+ TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CirclePageIndicator, defStyle, 0);
+
+ mCentered = a.getBoolean(R.styleable.CirclePageIndicator_centered, defaultCentered);
+ mOrientation = a.getInt(R.styleable.CirclePageIndicator_android_orientation, defaultOrientation);
+ mPaintPageFill.setStyle(Style.FILL);
+ mPaintPageFill.setColor(a.getColor(R.styleable.CirclePageIndicator_pageColor, defaultPageColor));
+ mPaintStroke.setStyle(Style.STROKE);
+ mPaintStroke.setColor(a.getColor(R.styleable.CirclePageIndicator_strokeColor, defaultStrokeColor));
+ mPaintStroke.setStrokeWidth(a.getDimension(R.styleable.CirclePageIndicator_strokeWidth, defaultStrokeWidth));
+ mPaintFill.setStyle(Style.FILL);
+ mPaintFill.setColor(a.getColor(R.styleable.CirclePageIndicator_indicatorFillColor, defaultFillColor));
+ mRadius = a.getDimension(R.styleable.CirclePageIndicator_radius, defaultRadius);
+ mSnap = a.getBoolean(R.styleable.CirclePageIndicator_snap, defaultSnap);
+
+ Drawable background = a.getDrawable(R.styleable.CirclePageIndicator_android_background);
+ if (background != null) {
+ setBackgroundDrawable(background);
+ }
+
+ a.recycle();
+
+ final ViewConfiguration configuration = ViewConfiguration.get(context);
+ mTouchSlop = ViewConfigurationCompat.getScaledPagingTouchSlop(configuration);
+
+ mSettingsIcon = BitmapFactory.decodeResource(res, R.drawable.ic_mini_settings);
+ }
+
+ @Override
+ public boolean hasOverlappingRendering() {
+ return false;
+ }
+
+ public void setCentered(boolean centered) {
+ mCentered = centered;
+ invalidate();
+ }
+
+ public boolean isCentered() {
+ return mCentered;
+ }
+
+ public void setPageColor(int pageColor) {
+ mPaintPageFill.setColor(pageColor);
+ invalidate();
+ }
+
+ public int getPageColor() {
+ return mPaintPageFill.getColor();
+ }
+
+ public void setFillColor(int fillColor) {
+ mPaintFill.setColor(fillColor);
+ invalidate();
+ }
+
+ public int getFillColor() {
+ return mPaintFill.getColor();
+ }
+
+ public void setOrientation(int orientation) {
+ switch (orientation) {
+ case HORIZONTAL:
+ case VERTICAL:
+ mOrientation = orientation;
+ requestLayout();
+ break;
+
+ default:
+ throw new IllegalArgumentException("Orientation must be either HORIZONTAL or VERTICAL.");
+ }
+ }
+
+ public int getOrientation() {
+ return mOrientation;
+ }
+
+ public void setStrokeColor(int strokeColor) {
+ mPaintStroke.setColor(strokeColor);
+ invalidate();
+ }
+
+ public int getStrokeColor() {
+ return mPaintStroke.getColor();
+ }
+
+ public void setStrokeWidth(float strokeWidth) {
+ mPaintStroke.setStrokeWidth(strokeWidth);
+ invalidate();
+ }
+
+ public float getStrokeWidth() {
+ return mPaintStroke.getStrokeWidth();
+ }
+
+ public void setRadius(float radius) {
+ mRadius = radius;
+ invalidate();
+ }
+
+ public float getRadius() {
+ return mRadius;
+ }
+
+ public void setSnap(boolean snap) {
+ mSnap = snap;
+ invalidate();
+ }
+
+ public boolean isSnap() {
+ return mSnap;
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+
+ if (mViewPager == null) {
+ return;
+ }
+ final int count = mViewPager.getAdapter().getCount();
+ if (count == 0) {
+ return;
+ }
+
+ if (mCurrentPage >= count) {
+ setCurrentItem(count - 1);
+ return;
+ }
+
+ int longSize;
+ int longPaddingBefore;
+ int longPaddingAfter;
+ int shortPaddingBefore;
+ if (mOrientation == HORIZONTAL) {
+ longSize = getWidth();
+ longPaddingBefore = getPaddingLeft();
+ longPaddingAfter = getPaddingRight();
+ shortPaddingBefore = getPaddingTop();
+ } else {
+ longSize = getHeight();
+ longPaddingBefore = getPaddingTop();
+ longPaddingAfter = getPaddingBottom();
+ shortPaddingBefore = getPaddingLeft();
+ }
+
+ final float threeRadius = mRadius * 3;
+ final float shortOffset = shortPaddingBefore + mRadius;
+ float longOffset = longPaddingBefore + mRadius;
+ if (mCentered) {
+ longOffset += ((longSize - longPaddingBefore - longPaddingAfter) / 2.0f) - ((count * threeRadius) / 2.0f);
+ }
+
+ float dX;
+ float dY;
+
+ float pageFillRadius = mRadius;
+ if (mPaintStroke.getStrokeWidth() > 0) {
+ pageFillRadius -= mPaintStroke.getStrokeWidth() / 2.0f;
+ }
+
+ //Draw stroked circles
+ for (int iLoop = 0; iLoop < count; iLoop++) {
+ float drawLong = longOffset + (iLoop * threeRadius);
+ if (mOrientation == HORIZONTAL) {
+ dX = drawLong;
+ dY = shortOffset;
+ } else {
+ dX = shortOffset;
+ dY = drawLong;
+ }
+ // Only paint fill if not completely transparent
+ if (mPaintPageFill.getAlpha() > 0) {
+ if (mEditing && iLoop == 0) {
+ canvas.drawBitmap(mSettingsIcon,
+ (int) (dX - mRadius),
+ (int) (dY - mRadius),
+ mPaintPageFill);
+ } else {
+ canvas.drawCircle(dX, dY, (float) (pageFillRadius / 1.5f), mPaintPageFill);
+ }
+ }
+
+ // Only paint stroke if a stroke width was non-zero
+ if (pageFillRadius != mRadius) {
+ canvas.drawCircle(dX, dY, mRadius, mPaintStroke);
+ }
+ }
+
+ //Draw the filled circle according to the current scroll
+ float cx = (mSnap ? mSnapPage : mCurrentPage) * threeRadius;
+ if (!mSnap) {
+ cx += mPageOffset * threeRadius;
+ }
+ if (mOrientation == HORIZONTAL) {
+ dX = longOffset + cx;
+ dY = shortOffset;
+ } else {
+ dX = shortOffset;
+ dY = longOffset + cx;
+ }
+ canvas.drawCircle(dX, dY, mRadius, mPaintFill);
+ }
+
+ public boolean onTouchEvent(MotionEvent ev) {
+ if (super.onTouchEvent(ev)) {
+ return true;
+ }
+ if ((mViewPager == null) || (mViewPager.getAdapter().getCount() == 0)) {
+ return false;
+ }
+
+ final int action = ev.getAction() & MotionEventCompat.ACTION_MASK;
+ switch (action) {
+ case MotionEvent.ACTION_DOWN:
+ mActivePointerId = MotionEventCompat.getPointerId(ev, 0);
+ mLastMotionX = ev.getX();
+ break;
+
+ case MotionEvent.ACTION_MOVE: {
+ final int activePointerIndex = MotionEventCompat.findPointerIndex(ev, mActivePointerId);
+ final float x = MotionEventCompat.getX(ev, activePointerIndex);
+ final float deltaX = x - mLastMotionX;
+
+ if (!mIsDragging) {
+ if (Math.abs(deltaX) > mTouchSlop) {
+ mIsDragging = true;
+ }
+ }
+
+ if (mIsDragging) {
+ mLastMotionX = x;
+ if (mViewPager.isFakeDragging() || mViewPager.beginFakeDrag()) {
+ mViewPager.fakeDragBy(deltaX);
+ }
+ }
+
+ break;
+ }
+
+ case MotionEvent.ACTION_CANCEL:
+ case MotionEvent.ACTION_UP:
+ if (!mIsDragging) {
+ final int count = mViewPager.getAdapter().getCount();
+ final int width = getWidth();
+ final float halfWidth = width / 2f;
+ final float sixthWidth = width / 6f;
+
+ if ((mCurrentPage > 0) && (ev.getX() < halfWidth - sixthWidth)) {
+ if (action != MotionEvent.ACTION_CANCEL) {
+ mViewPager.setCurrentItem(mCurrentPage - 1);
+ }
+ return true;
+ } else if ((mCurrentPage < count - 1) && (ev.getX() > halfWidth + sixthWidth)) {
+ if (action != MotionEvent.ACTION_CANCEL) {
+ mViewPager.setCurrentItem(mCurrentPage + 1);
+ }
+ return true;
+ }
+ }
+
+ mIsDragging = false;
+ mActivePointerId = INVALID_POINTER;
+ if (mViewPager.isFakeDragging()) mViewPager.endFakeDrag();
+ break;
+
+ case MotionEventCompat.ACTION_POINTER_DOWN: {
+ final int index = MotionEventCompat.getActionIndex(ev);
+ mLastMotionX = MotionEventCompat.getX(ev, index);
+ mActivePointerId = MotionEventCompat.getPointerId(ev, index);
+ break;
+ }
+
+ case MotionEventCompat.ACTION_POINTER_UP:
+ final int pointerIndex = MotionEventCompat.getActionIndex(ev);
+ final int pointerId = MotionEventCompat.getPointerId(ev, pointerIndex);
+ if (pointerId == mActivePointerId) {
+ final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
+ mActivePointerId = MotionEventCompat.getPointerId(ev, newPointerIndex);
+ }
+ mLastMotionX = MotionEventCompat.getX(ev, MotionEventCompat.findPointerIndex(ev, mActivePointerId));
+ break;
+ }
+
+ return true;
+ }
+
+ @Override
+ public void setViewPager(ViewPager view) {
+ if (mViewPager == view) {
+ return;
+ }
+ if (mViewPager != null) {
+ mViewPager.setOnPageChangeListener(null);
+ }
+ if (view.getAdapter() == null) {
+ throw new IllegalStateException("ViewPager does not have adapter instance.");
+ }
+ mViewPager = view;
+ mViewPager.setOnPageChangeListener(this);
+ invalidate();
+ }
+
+ @Override
+ public void setViewPager(ViewPager view, int initialPosition) {
+ setViewPager(view);
+ setCurrentItem(initialPosition);
+ }
+
+ @Override
+ public void setCurrentItem(int item) {
+ if (mViewPager == null) {
+ throw new IllegalStateException("ViewPager has not been bound.");
+ }
+ mViewPager.setCurrentItem(item);
+ mCurrentPage = item;
+ invalidate();
+ }
+
+ @Override
+ public void notifyDataSetChanged() {
+ invalidate();
+ }
+
+ @Override
+ public void onPageScrollStateChanged(int state) {
+ mScrollState = state;
+
+ if (mListener != null) {
+ mListener.onPageScrollStateChanged(state);
+ }
+ }
+
+ @Override
+ public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
+ mCurrentPage = position;
+ mPageOffset = positionOffset;
+ invalidate();
+
+ if (mListener != null) {
+ mListener.onPageScrolled(position, positionOffset, positionOffsetPixels);
+ }
+ }
+
+ @Override
+ public void onPageSelected(int position) {
+ if (mSnap || mScrollState == ViewPager.SCROLL_STATE_IDLE) {
+ mCurrentPage = position;
+ mSnapPage = position;
+ invalidate();
+ }
+
+ if (mListener != null) {
+ mListener.onPageSelected(position);
+ }
+ }
+
+ @Override
+ public void setOnPageChangeListener(ViewPager.OnPageChangeListener listener) {
+ mListener = listener;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see android.view.View#onMeasure(int, int)
+ */
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ if (mOrientation == HORIZONTAL) {
+ setMeasuredDimension(measureLong(widthMeasureSpec), measureShort(heightMeasureSpec));
+ } else {
+ setMeasuredDimension(measureShort(widthMeasureSpec), measureLong(heightMeasureSpec));
+ }
+ }
+
+ /**
+ * Determines the width of this view
+ *
+ * @param measureSpec
+ * A measureSpec packed into an int
+ * @return The width of the view, honoring constraints from measureSpec
+ */
+ private int measureLong(int measureSpec) {
+ int result;
+ int specMode = MeasureSpec.getMode(measureSpec);
+ int specSize = MeasureSpec.getSize(measureSpec);
+
+ if ((specMode == MeasureSpec.EXACTLY) || (mViewPager == null)) {
+ //We were told how big to be
+ result = specSize;
+ } else {
+ //Calculate the width according the views count
+ final int count = mViewPager.getAdapter().getCount();
+ result = (int)(getPaddingLeft() + getPaddingRight()
+ + (count * 2 * mRadius) + (count - 1) * mRadius + 1);
+ //Respect AT_MOST value if that was what is called for by measureSpec
+ if (specMode == MeasureSpec.AT_MOST) {
+ result = Math.min(result, specSize);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Determines the height of this view
+ *
+ * @param measureSpec
+ * A measureSpec packed into an int
+ * @return The height of the view, honoring constraints from measureSpec
+ */
+ private int measureShort(int measureSpec) {
+ int result;
+ int specMode = MeasureSpec.getMode(measureSpec);
+ int specSize = MeasureSpec.getSize(measureSpec);
+
+ if (specMode == MeasureSpec.EXACTLY) {
+ //We were told how big to be
+ result = specSize;
+ } else {
+ //Measure the height
+ result = (int)(2 * mRadius + getPaddingTop() + getPaddingBottom() + 1);
+ //Respect AT_MOST value if that was what is called for by measureSpec
+ if (specMode == MeasureSpec.AT_MOST) {
+ result = Math.min(result, specSize);
+ }
+ }
+ return result;
+ }
+
+ public void setEditing(boolean editing) {
+ mEditing = editing;
+ invalidate();
+ }
+}
diff --git a/packages/SystemUI/src/com/viewpagerindicator/PageIndicator.java b/packages/SystemUI/src/com/viewpagerindicator/PageIndicator.java
new file mode 100644
index 0000000..c08c00a
--- /dev/null
+++ b/packages/SystemUI/src/com/viewpagerindicator/PageIndicator.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2011 Patrik Akerfeldt
+ * Copyright (C) 2011 Jake Wharton
+ *
+ * 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.viewpagerindicator;
+
+import android.support.v4.view.ViewPager;
+
+/**
+ * A PageIndicator is responsible to show an visual indicator on the total views
+ * number and the current visible view.
+ */
+public interface PageIndicator extends ViewPager.OnPageChangeListener {
+ /**
+ * Bind the indicator to a ViewPager.
+ *
+ * @param view
+ */
+ void setViewPager(ViewPager view);
+
+ /**
+ * Bind the indicator to a ViewPager.
+ *
+ * @param view
+ * @param initialPosition
+ */
+ void setViewPager(ViewPager view, int initialPosition);
+
+ /**
+ * <p>Set the current page of both the ViewPager and indicator.</p>
+ *
+ * <p>This <strong>must</strong> be used if you need to set the page before
+ * the views are drawn on screen (e.g., default start page).</p>
+ *
+ * @param item
+ */
+ void setCurrentItem(int item);
+
+ /**
+ * Set a page change listener which will receive forwarded events.
+ *
+ * @param listener
+ */
+ void setOnPageChangeListener(ViewPager.OnPageChangeListener listener);
+
+ /**
+ * Notify the indicator that the fragment list has changed.
+ */
+ void notifyDataSetChanged();
+}
diff --git a/packages/SystemUI/tests/Android.mk b/packages/SystemUI/tests/Android.mk
index 6a7201c..51b70c6 100644
--- a/packages/SystemUI/tests/Android.mk
+++ b/packages/SystemUI/tests/Android.mk
@@ -31,6 +31,9 @@ LOCAL_JAVA_LIBRARIES := android.test.runner telephony-common
LOCAL_PACKAGE_NAME := SystemUITests
LOCAL_STATIC_JAVA_LIBRARIES := mockito-target Keyguard
+LOCAL_STATIC_JAVA_LIBRARIES += org.cyanogenmod.platform.sdk \
+ android-support-v7-palette \
+ android-support-v4
# sign this with platform cert, so this test is allowed to inject key events into
# UI it doesn't own. This is necessary to allow screenshots to be taken
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CallbackHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CallbackHandlerTest.java
index 00b8de2..5e840f5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CallbackHandlerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CallbackHandlerTest.java
@@ -104,8 +104,8 @@ public class CallbackHandlerTest extends AndroidTestCase {
int qsType = R.drawable.ic_qs_signal_1x;
boolean wide = true;
int subId = 5;
- mHandler.setMobileDataIndicators(status, qs, type, qsType, in, out, typeDescription,
- description, wide, subId);
+ mHandler.setMobileDataIndicators(status, qs, type, qsType, in, out, 0, 0, 0, 0,
+ typeDescription, description, wide, subId);
waitForCallbacks();
ArgumentCaptor<IconState> statusArg = ArgumentCaptor.forClass(IconState.class);
@@ -120,7 +120,11 @@ public class CallbackHandlerTest extends AndroidTestCase {
ArgumentCaptor<Integer> subIdArg = ArgumentCaptor.forClass(Integer.class);
Mockito.verify(mSignalCallback).setMobileDataIndicators(statusArg.capture(),
qsArg.capture(), typeIconArg.capture(), qsTypeIconArg.capture(), inArg.capture(),
- outArg.capture(), typeContentArg.capture(), descArg.capture(), wideArg.capture(),
+ outArg.capture(), ArgumentCaptor.forClass(Integer.class).capture(),
+ ArgumentCaptor.forClass(Integer.class).capture(),
+ ArgumentCaptor.forClass(Integer.class).capture(),
+ ArgumentCaptor.forClass(Integer.class).capture(),
+ typeContentArg.capture(), descArg.capture(), wideArg.capture(),
subIdArg.capture());
assertEquals(status, statusArg.getValue());
assertEquals(qs, qsArg.getValue());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
index 30c08cd..58cb6ff 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
@@ -276,6 +276,10 @@ public class NetworkControllerBaseTest extends SysuiTestCase {
iconArg.capture(),
ArgumentCaptor.forClass(Integer.class).capture(),
typeIconArg.capture(), dataInArg.capture(), dataOutArg.capture(),
+ ArgumentCaptor.forClass(Integer.class).capture(),
+ ArgumentCaptor.forClass(Integer.class).capture(),
+ ArgumentCaptor.forClass(Integer.class).capture(),
+ ArgumentCaptor.forClass(Integer.class).capture(),
ArgumentCaptor.forClass(String.class).capture(),
ArgumentCaptor.forClass(String.class).capture(),
ArgumentCaptor.forClass(Boolean.class).capture(),
@@ -302,6 +306,10 @@ public class NetworkControllerBaseTest extends SysuiTestCase {
ArgumentCaptor.forClass(Integer.class).capture(),
ArgumentCaptor.forClass(Boolean.class).capture(),
ArgumentCaptor.forClass(Boolean.class).capture(),
+ ArgumentCaptor.forClass(Integer.class).capture(),
+ ArgumentCaptor.forClass(Integer.class).capture(),
+ ArgumentCaptor.forClass(Integer.class).capture(),
+ ArgumentCaptor.forClass(Integer.class).capture(),
ArgumentCaptor.forClass(String.class).capture(),
ArgumentCaptor.forClass(String.class).capture(),
ArgumentCaptor.forClass(Boolean.class).capture(),
diff --git a/services/Android.mk b/services/Android.mk
index 1918db5..b15f575 100644
--- a/services/Android.mk
+++ b/services/Android.mk
@@ -35,6 +35,8 @@ services := \
# The convention is to name each service module 'services.$(module_name)'
LOCAL_STATIC_JAVA_LIBRARIES := $(addprefix services.,$(services))
+LOCAL_JAVA_LIBRARIES += org.cyanogenmod.platform.internal
+
include $(BUILD_JAVA_LIBRARY)
# native library
@@ -48,6 +50,11 @@ LOCAL_SHARED_LIBRARIES :=
# include all the jni subdirs to collect their sources
include $(wildcard $(LOCAL_PATH)/*/jni/Android.mk)
+LOCAL_C_INCLUDES += \
+ $(TOP)/frameworks/base/services/libtvextensions \
+
+LOCAL_WHOLE_STATIC_LIBRARIES := libTvInputHalExtensions
+
LOCAL_CFLAGS += -DEGL_EGLEXT_PROTOTYPES -DGL_GLEXT_PROTOTYPES
LOCAL_MODULE:= libandroid_servers
diff --git a/services/accessibility/Android.mk b/services/accessibility/Android.mk
index d98fc28..39355a7 100644
--- a/services/accessibility/Android.mk
+++ b/services/accessibility/Android.mk
@@ -7,4 +7,6 @@ LOCAL_MODULE := services.accessibility
LOCAL_SRC_FILES += \
$(call all-java-files-under,java)
+LOCAL_JAVA_LIBRARIES += org.cyanogenmod.platform.internal
+
include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/services/accessibility/java/com/android/server/accessibility/DisplayAdjustmentUtils.java b/services/accessibility/java/com/android/server/accessibility/DisplayAdjustmentUtils.java
index d0b5898..1b4182d 100644
--- a/services/accessibility/java/com/android/server/accessibility/DisplayAdjustmentUtils.java
+++ b/services/accessibility/java/com/android/server/accessibility/DisplayAdjustmentUtils.java
@@ -26,11 +26,12 @@ import android.os.ServiceManager;
import android.provider.Settings;
import android.util.Slog;
import android.view.accessibility.AccessibilityManager;
+import cyanogenmod.providers.CMSettings;
/**
* Utility methods for performing accessibility display adjustments.
*/
-class DisplayAdjustmentUtils {
+public class DisplayAdjustmentUtils {
private static final String LOG_TAG = DisplayAdjustmentUtils.class.getSimpleName();
/** Matrix and offset used for converting color to gray-scale. */
@@ -76,6 +77,11 @@ class DisplayAdjustmentUtils {
return true;
}
+ if (CMSettings.Secure.getStringForUser(cr,
+ CMSettings.Secure.LIVE_DISPLAY_COLOR_MATRIX, userId) != null) {
+ return true;
+ }
+
return false;
}
@@ -91,6 +97,23 @@ class DisplayAdjustmentUtils {
colorMatrix = multiply(colorMatrix, INVERSION_MATRIX_VALUE_ONLY);
}
+ String adj = CMSettings.Secure.getStringForUser(cr,
+ CMSettings.Secure.LIVE_DISPLAY_COLOR_MATRIX, userId);
+ if (adj != null) {
+ String[] tmp = adj.split(" ");
+ if (tmp.length == 16) {
+ float[] adjMatrix = new float[16];
+ try {
+ for (int i = 0; i < 16; i++) {
+ adjMatrix[i] = Float.parseFloat(tmp[i]);
+ }
+ colorMatrix = multiply(colorMatrix, adjMatrix);
+ } catch (NumberFormatException e) {
+ Slog.e(LOG_TAG, e.getMessage(), e);
+ }
+ }
+ }
+
if (Settings.Secure.getIntForUser(cr,
Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED, 0, userId) != 0) {
final int daltonizerMode = Settings.Secure.getIntForUser(cr,
diff --git a/services/accessibility/java/com/android/server/accessibility/ScreenMagnifier.java b/services/accessibility/java/com/android/server/accessibility/ScreenMagnifier.java
index b4613d6..9be29c2 100644
--- a/services/accessibility/java/com/android/server/accessibility/ScreenMagnifier.java
+++ b/services/accessibility/java/com/android/server/accessibility/ScreenMagnifier.java
@@ -790,12 +790,7 @@ public final class ScreenMagnifier implements WindowManagerInternal.Magnificatio
while (mDelayedEventQueue != null) {
MotionEventInfo info = mDelayedEventQueue;
mDelayedEventQueue = info.mNext;
- final long offset = SystemClock.uptimeMillis() - info.mCachedTimeMillis;
- MotionEvent event = obtainEventWithOffsetTimeAndDownTime(info.mEvent, offset);
- MotionEvent rawEvent = obtainEventWithOffsetTimeAndDownTime(info.mRawEvent, offset);
- ScreenMagnifier.this.onMotionEvent(event, rawEvent, info.mPolicyFlags);
- event.recycle();
- rawEvent.recycle();
+ ScreenMagnifier.this.onMotionEvent(info.mEvent, info.mRawEvent, info.mPolicyFlags);
info.recycle();
}
}
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index fa87270..bc84676 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -2009,6 +2009,9 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
if (widget.views != null) {
pw.print(" views="); pw.println(widget.views);
}
+ if (widget.options != null) {
+ pw.print(" options="); pw.println(widget.options);
+ }
}
private static void serializeProvider(XmlSerializer out, Provider p) throws IOException {
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index 12003e2..1629a37 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -2218,10 +2218,10 @@ public class BackupManagerService {
// fire off a backup agent, blocking until it attaches or times out
IBackupAgent bindToAgentSynchronous(ApplicationInfo app, int mode) {
IBackupAgent agent = null;
- synchronized(mAgentConnectLock) {
- mConnecting = true;
- mConnectedAgent = null;
- try {
+ try {
+ synchronized(mAgentConnectLock) {
+ mConnecting = true;
+ mConnectedAgent = null;
if (mActivityManager.bindBackupAgent(app, mode)) {
Slog.d(TAG, "awaiting agent for " + app);
@@ -2235,7 +2235,6 @@ public class BackupManagerService {
} catch (InterruptedException e) {
// just bail
Slog.w(TAG, "Interrupted: " + e);
- mActivityManager.clearPendingBackup();
return null;
}
}
@@ -2243,14 +2242,22 @@ public class BackupManagerService {
// if we timed out with no connect, abort and move on
if (mConnecting == true) {
Slog.w(TAG, "Timeout waiting for agent " + app);
- mActivityManager.clearPendingBackup();
return null;
}
if (DEBUG) Slog.i(TAG, "got agent " + mConnectedAgent);
agent = mConnectedAgent;
}
- } catch (RemoteException e) {
+ }
+ } catch (RemoteException e) {
// can't happen - ActivityManager is local
+ } finally {
+ // failed to bind backup agent, clear pending backup
+ if (agent == null) {
+ try {
+ mActivityManager.clearPendingBackup();
+ } catch (RemoteException e) {
+ // can't happen - ActivityManager is local
+ }
}
}
return agent;
@@ -2931,6 +2938,12 @@ public class BackupManagerService {
final String pkgName = mCurrentPackage.packageName;
final long filepos = mBackupDataName.length();
+ if (mBackupData == null) {
+ failAgent(mAgentBinder, "Backup data was null: " + mBackupDataName);
+ addBackupTrace("backup data was null: " + mBackupDataName);
+ agentErrorCleanup();
+ return;
+ }
FileDescriptor fd = mBackupData.getFileDescriptor();
try {
// If it's a 3rd party app, see whether they wrote any protected keys
@@ -7935,6 +7948,11 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF
}
int toCopy = result;
while (toCopy > 0) {
+ if (!mEngine.isRunning() && RestoreEngine.SUCCESS != mEngine.getResult()) {
+ Slog.e(TAG, "RestoreEngine fail");
+ // throw IOException to abandon this package's restore
+ throw new IOException();
+ }
int n = transportIn.read(buffer, 0, toCopy);
engineOut.write(buffer, 0, n);
toCopy -= n;
diff --git a/services/core/Android.mk b/services/core/Android.mk
index 666f2ff..d2ecac9 100644
--- a/services/core/Android.mk
+++ b/services/core/Android.mk
@@ -12,4 +12,8 @@ LOCAL_SRC_FILES += \
LOCAL_JAVA_LIBRARIES := services.net telephony-common
LOCAL_STATIC_JAVA_LIBRARIES := tzdata_update
+LOCAL_JAVA_LIBRARIES += services.accessibility
+
+LOCAL_JAVA_LIBRARIES += org.cyanogenmod.platform.internal
+
include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index 130a234..8607a40 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -75,6 +75,7 @@ import static android.app.AlarmManager.RTC_WAKEUP;
import static android.app.AlarmManager.RTC;
import static android.app.AlarmManager.ELAPSED_REALTIME_WAKEUP;
import static android.app.AlarmManager.ELAPSED_REALTIME;
+import static android.app.AlarmManager.RTC_POWEROFF_WAKEUP;
import com.android.internal.util.LocalLog;
@@ -83,8 +84,10 @@ class AlarmManagerService extends SystemService {
private static final int RTC_MASK = 1 << RTC;
private static final int ELAPSED_REALTIME_WAKEUP_MASK = 1 << ELAPSED_REALTIME_WAKEUP;
private static final int ELAPSED_REALTIME_MASK = 1 << ELAPSED_REALTIME;
+ private static final int RTC_POWEROFF_WAKEUP_MASK = 1 << RTC_POWEROFF_WAKEUP;
static final int TIME_CHANGED_MASK = 1 << 16;
- static final int IS_WAKEUP_MASK = RTC_WAKEUP_MASK|ELAPSED_REALTIME_WAKEUP_MASK;
+ static final int IS_WAKEUP_MASK = RTC_WAKEUP_MASK|ELAPSED_REALTIME_WAKEUP_MASK
+ |RTC_POWEROFF_WAKEUP_MASK;
// Mask for testing whether a given alarm type is wakeup vs non-wakeup
static final int TYPE_NONWAKEUP_MASK = 0x1; // low bit => non-wakeup
@@ -111,8 +114,12 @@ class AlarmManagerService extends SystemService {
final Object mLock = new Object();
+ private final ArrayList<Integer> mTriggeredUids = new ArrayList<Integer>();
+ private final ArrayList<Integer> mBlockedUids = new ArrayList<Integer>();
+
long mNativeData;
private long mNextWakeup;
+ private long mNextRtcWakeup;
private long mNextNonWakeup;
int mBroadcastRefCount = 0;
PowerManager.WakeLock mWakeLock;
@@ -347,6 +354,14 @@ class AlarmManagerService extends SystemService {
return alarms.get(index);
}
+ long getWhenByElapsedTime(long whenElapsed) {
+ for(int i=0;i< alarms.size();i++) {
+ if(alarms.get(i).whenElapsed == whenElapsed)
+ return alarms.get(i).when;
+ }
+ return 0;
+ }
+
boolean canHold(long whenElapsed, long maxWhen) {
return (end >= whenElapsed) && (start <= maxWhen);
}
@@ -496,6 +511,17 @@ class AlarmManagerService extends SystemService {
return false;
}
+ boolean isRtcPowerOffWakeup() {
+ final int N = alarms.size();
+ for (int i = 0; i < N; i++) {
+ Alarm a = alarms.get(i);
+ if (a.type == RTC_POWEROFF_WAKEUP) {
+ return true;
+ }
+ }
+ return false;
+ }
+
@Override
public String toString() {
StringBuilder b = new StringBuilder(40);
@@ -602,7 +628,8 @@ class AlarmManagerService extends SystemService {
}
static long convertToElapsed(long when, int type) {
- final boolean isRtc = (type == RTC || type == RTC_WAKEUP);
+ final boolean isRtc = (type == RTC || type == RTC_WAKEUP
+ || type == RTC_POWEROFF_WAKEUP);
if (isRtc) {
when -= System.currentTimeMillis() - SystemClock.elapsedRealtime();
}
@@ -732,9 +759,10 @@ class AlarmManagerService extends SystemService {
final BroadcastStats mBroadcastStats;
final FilterStats mFilterStats;
final int mAlarmType;
+ final int mUid;
InFlight(AlarmManagerService service, PendingIntent pendingIntent, WorkSource workSource,
- int alarmType, String tag, long nowELAPSED) {
+ int alarmType, String tag, long nowELAPSED, int uid) {
mPendingIntent = pendingIntent;
mWorkSource = workSource;
mTag = tag;
@@ -747,6 +775,7 @@ class AlarmManagerService extends SystemService {
fs.lastTime = nowELAPSED;
mFilterStats = fs;
mAlarmType = alarmType;
+ mUid = uid;
}
}
@@ -794,7 +823,7 @@ class AlarmManagerService extends SystemService {
@Override
public void onStart() {
mNativeData = init();
- mNextWakeup = mNextNonWakeup = 0;
+ mNextWakeup = mNextRtcWakeup = mNextNonWakeup = 0;
// We have to set current TimeZone info to kernel
// because kernel doesn't keep this after reboot
@@ -916,7 +945,7 @@ class AlarmManagerService extends SystemService {
interval = minInterval;
}
- if (type < RTC_WAKEUP || type > ELAPSED_REALTIME) {
+ if (type < RTC_WAKEUP || type > RTC_POWEROFF_WAKEUP) {
throw new IllegalArgumentException("Invalid alarm type " + type);
}
@@ -1174,6 +1203,39 @@ class AlarmManagerService extends SystemService {
dumpImpl(pw);
}
+
+ @Override
+ /* updates the blocked uids, so if a wake lock is acquired to only fire
+ * alarm for it, it can be released.
+ */
+ public void updateBlockedUids(int uid, boolean isBlocked) {
+
+ if (localLOGV) Slog.v(TAG, "UpdateBlockedUids: uid = " + uid +
+ " isBlocked = " + isBlocked);
+
+ if (Binder.getCallingUid() != Process.SYSTEM_UID) {
+ if (localLOGV) Slog.v(TAG, "UpdateBlockedUids is not allowed");
+ return;
+ }
+
+ synchronized(mLock) {
+ if(isBlocked) {
+ mBlockedUids.add(new Integer(uid));
+ if (checkReleaseWakeLock()) {
+ /* all the uids for which the alarms are triggered
+ * are either blocked or have called onSendFinished.
+ */
+ if (mWakeLock.isHeld()) {
+ mWakeLock.release();
+ if (localLOGV)
+ Slog.v(TAG, "AM WakeLock Released Internally in updateBlockedUids");
+ }
+ }
+ } else {
+ mBlockedUids.clear();
+ }
+ }
+ }
};
void dumpImpl(PrintWriter pw) {
@@ -1469,6 +1531,19 @@ class AlarmManagerService extends SystemService {
return null;
}
+ private Batch findFirstRtcWakeupBatchLocked() {
+ long elapsed = SystemClock.elapsedRealtime();
+ final int N = mAlarmBatches.size();
+ for (int i = 0; i < N; i++) {
+ Batch b = mAlarmBatches.get(i);
+ long intervalTime = b.start - elapsed;
+ if (b.isRtcPowerOffWakeup()) {
+ return b;
+ }
+ }
+ return null;
+ }
+
long getNextWakeFromIdleTimeImpl() {
synchronized (mLock) {
return mNextWakeFromIdle != null ? mNextWakeFromIdle.whenElapsed : Long.MAX_VALUE;
@@ -1611,10 +1686,18 @@ class AlarmManagerService extends SystemService {
if (mAlarmBatches.size() > 0) {
final Batch firstWakeup = findFirstWakeupBatchLocked();
final Batch firstBatch = mAlarmBatches.get(0);
+ final Batch firstRtcWakeup = findFirstRtcWakeupBatchLocked();
if (firstWakeup != null && mNextWakeup != firstWakeup.start) {
mNextWakeup = firstWakeup.start;
setLocked(ELAPSED_REALTIME_WAKEUP, firstWakeup.start);
}
+ if (firstRtcWakeup != null && mNextRtcWakeup != firstRtcWakeup.start) {
+ mNextRtcWakeup = firstRtcWakeup.start;
+ long when = firstRtcWakeup.getWhenByElapsedTime(mNextRtcWakeup);
+ if (when != 0) {
+ setLocked(RTC_POWEROFF_WAKEUP, when);
+ }
+ }
if (firstBatch != firstWakeup) {
nextNonWakeup = firstBatch.start;
}
@@ -1630,10 +1713,36 @@ class AlarmManagerService extends SystemService {
}
}
+ boolean checkReleaseWakeLock() {
+ if (mTriggeredUids.size() == 0 || mBlockedUids.size() == 0)
+ return false;
+
+ int uid;
+ for (int i = 0; i < mTriggeredUids.size(); i++) {
+ uid = mTriggeredUids.get(i);
+ if (!mBlockedUids.contains(uid)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
private void removeLocked(PendingIntent operation) {
boolean didRemove = false;
for (int i = mAlarmBatches.size() - 1; i >= 0; i--) {
Batch b = mAlarmBatches.get(i);
+ ArrayList<Alarm> alarmList = b.alarms;
+ Alarm alarm = null;
+ for (int j = alarmList.size() - 1; j >= 0; j--) {
+ alarm = alarmList.get(j);
+ if (alarm.type == RTC_POWEROFF_WAKEUP && alarm.operation.equals(operation)) {
+ long alarmSeconds, alarmNanoseconds;
+ alarmSeconds = alarm.when / 1000;
+ alarmNanoseconds = (alarm.when % 1000) * 1000 * 1000;
+ clear(mNativeData, alarm.type, alarmSeconds, alarmNanoseconds);
+ mNextRtcWakeup = 0;
+ }
+ }
didRemove |= b.remove(operation);
if (b.size() == 0) {
mAlarmBatches.remove(i);
@@ -1804,6 +1913,7 @@ class AlarmManagerService extends SystemService {
case RTC_WAKEUP : return "RTC_WAKEUP";
case ELAPSED_REALTIME : return "ELAPSED";
case ELAPSED_REALTIME_WAKEUP: return "ELAPSED_WAKEUP";
+ case RTC_POWEROFF_WAKEUP : return "RTC_POWEROFF_WAKEUP";
default:
break;
}
@@ -1824,6 +1934,7 @@ class AlarmManagerService extends SystemService {
private native long init();
private native void close(long nativeData);
private native void set(long nativeData, int type, long seconds, long nanoseconds);
+ private native void clear(long nativeData, int type, long seconds, long nanoseconds);
private native int waitForAlarm(long nativeData);
private native int setKernelTime(long nativeData, long millis);
private native int setKernelTimezone(long nativeData, int minuteswest);
@@ -1959,6 +2070,7 @@ class AlarmManagerService extends SystemService {
public long maxWhenElapsed; // also in the elapsed time base
public long repeatInterval;
public PriorityClass priorityClass;
+ public int pid;
public Alarm(int _type, long _when, long _whenElapsed, long _windowLength, long _maxWhen,
long _interval, PendingIntent _op, WorkSource _ws, int _flags,
@@ -1966,7 +2078,8 @@ class AlarmManagerService extends SystemService {
type = _type;
origWhen = _when;
wakeup = _type == AlarmManager.ELAPSED_REALTIME_WAKEUP
- || _type == AlarmManager.RTC_WAKEUP;
+ || _type == AlarmManager.RTC_WAKEUP
+ || _type == AlarmManager.RTC_POWEROFF_WAKEUP;
when = _when;
whenElapsed = _whenElapsed;
windowLength = _windowLength;
@@ -1978,11 +2091,12 @@ class AlarmManagerService extends SystemService {
flags = _flags;
alarmClock = _info;
uid = _uid;
+ pid = Binder.getCallingPid();
}
public static String makeTag(PendingIntent pi, int type) {
return pi.getTag(type == ELAPSED_REALTIME_WAKEUP || type == RTC_WAKEUP
- ? "*walarm*:" : "*alarm*:");
+ || type == RTC_POWEROFF_WAKEUP ? "*walarm*:" : "*alarm*:");
}
@Override
@@ -2002,7 +2116,8 @@ class AlarmManagerService extends SystemService {
public void dump(PrintWriter pw, String prefix, long nowRTC, long nowELAPSED,
SimpleDateFormat sdf) {
- final boolean isRtc = (type == RTC || type == RTC_WAKEUP);
+ final boolean isRtc = (type == RTC || type == RTC_WAKEUP
+ || type == RTC_POWEROFF_WAKEUP);
pw.print(prefix); pw.print("tag="); pw.println(tag);
pw.print(prefix); pw.print("type="); pw.print(type);
pw.print(" whenElapsed="); TimeUtils.formatDuration(whenElapsed,
@@ -2117,15 +2232,19 @@ class AlarmManagerService extends SystemService {
mResultReceiver, mHandler, null, allowWhileIdle ? mIdleOptions : null);
// we have an active broadcast so stay awake.
- if (mBroadcastRefCount == 0) {
+ if (mBroadcastRefCount == 0 || !mWakeLock.isHeld()) {
setWakelockWorkSource(alarm.operation, alarm.workSource,
alarm.type, alarm.tag, true);
mWakeLock.acquire();
}
final InFlight inflight = new InFlight(AlarmManagerService.this,
- alarm.operation, alarm.workSource, alarm.type, alarm.tag, nowELAPSED);
+ alarm.operation,
+ alarm.workSource,
+ alarm.type, alarm.tag,
+ nowELAPSED, alarm.uid);
mInFlight.add(inflight);
mBroadcastRefCount++;
+ mTriggeredUids.add(new Integer(alarm.uid));
if (allowWhileIdle) {
// Record the last time this uid handled an ALLOW_WHILE_IDLE alarm.
@@ -2149,7 +2268,8 @@ class AlarmManagerService extends SystemService {
fs.nesting++;
}
if (alarm.type == ELAPSED_REALTIME_WAKEUP
- || alarm.type == RTC_WAKEUP) {
+ || alarm.type == RTC_WAKEUP
+ || alarm.type == RTC_POWEROFF_WAKEUP) {
bs.numWakeup++;
fs.numWakeup++;
if (alarm.workSource != null && alarm.workSource.size() > 0) {
@@ -2321,11 +2441,10 @@ class AlarmManagerService extends SystemService {
mWakeLock.setWorkSource(new WorkSource(uid));
return;
}
+ // Something went wrong; fall back to attributing the lock to the OS
+ mWakeLock.setWorkSource(null);
} catch (Exception e) {
}
-
- // Something went wrong; fall back to attributing the lock to the OS
- mWakeLock.setWorkSource(null);
}
private class AlarmHandler extends Handler {
@@ -2533,9 +2652,11 @@ class AlarmManagerService extends SystemService {
public void onSendFinished(PendingIntent pi, Intent intent, int resultCode,
String resultData, Bundle resultExtras) {
synchronized (mLock) {
+ int uid = 0;
InFlight inflight = null;
for (int i=0; i<mInFlight.size(); i++) {
if (mInFlight.get(i).mPendingIntent == pi) {
+ uid = mInFlight.get(i).mUid;
inflight = mInFlight.remove(i);
break;
}
@@ -2569,8 +2690,19 @@ class AlarmManagerService extends SystemService {
mLog.w("No in-flight alarm for " + pi + " " + intent);
}
mBroadcastRefCount--;
+ mTriggeredUids.remove(new Integer(uid));
+
+ if (checkReleaseWakeLock()) {
+ if (mWakeLock.isHeld()) {
+ mWakeLock.release();
+ if (localLOGV) Slog.v(TAG, "AM WakeLock Released Internally onSendFinish");
+ }
+ }
+
if (mBroadcastRefCount == 0) {
- mWakeLock.release();
+ if (mWakeLock.isHeld()) {
+ mWakeLock.release();
+ }
if (mInFlight.size() > 0) {
mLog.w("Finished all broadcasts with " + mInFlight.size()
+ " remaining inflights");
diff --git a/services/core/java/com/android/server/AppOpsPolicy.java b/services/core/java/com/android/server/AppOpsPolicy.java
new file mode 100644
index 0000000..75bca05
--- /dev/null
+++ b/services/core/java/com/android/server/AppOpsPolicy.java
@@ -0,0 +1,441 @@
+/* Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.android.server;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import android.app.AppOpsManager;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.util.Slog;
+import android.util.SparseArray;
+import android.util.Xml;
+
+import com.android.internal.util.XmlUtils;
+
+public class AppOpsPolicy {
+ static final String TAG = "AppOpsPolicy";
+ static final boolean DEBUG = false;
+ final File mFile;
+ final Context mContext;
+ public static final int CONTROL_SHOW = 0;
+
+ public static final int CONTROL_NOSHOW = 1;
+
+ public static final int CONTROL_UNKNOWN = 2;
+
+ public static int stringToControl(String show) {
+ if ("true".equalsIgnoreCase(show)) {
+ return CONTROL_SHOW;
+ } else if ("false".equalsIgnoreCase(show)) {
+ return CONTROL_NOSHOW;
+ }
+ return CONTROL_UNKNOWN;
+ }
+
+ HashMap<String, PolicyPkg> mPolicy = new HashMap<String, PolicyPkg>();
+
+ public AppOpsPolicy(File file, Context context) {
+ super();
+ mFile = file;
+ mContext = context;
+ }
+
+ public final static class PolicyPkg extends SparseArray<PolicyOp> {
+ public String packageName;
+ public int mode;
+ public int show;
+ public String type;
+
+ public PolicyPkg(String packageName, int mode, int show, String type) {
+ this.packageName = packageName;
+ this.mode = mode;
+ this.show = show;
+ this.type = type;
+ }
+
+ @Override
+ public String toString() {
+ return "PolicyPkg [packageName=" + packageName + ", mode=" + mode
+ + ", show=" + show + ", type=" + type + "]";
+ }
+
+ }
+
+ public final static class PolicyOp {
+ public int op;
+ public int mode;
+ public int show;
+
+ public PolicyOp(int op, int mode, int show) {
+ this.op = op;
+ this.mode = mode;
+ this.show = show;
+ }
+
+ @Override
+ public String toString() {
+ return "PolicyOp [op=" + op + ", mode=" + mode + ", show=" + show
+ + "]";
+ }
+ }
+
+ void readPolicy() {
+ FileInputStream stream;
+ synchronized (mFile) {
+ try {
+ stream = new FileInputStream(mFile);
+ } catch (FileNotFoundException e) {
+ Slog.i(TAG, "App ops policy file (" + mFile.getPath()
+ + ") not found; Skipping.");
+ return;
+ }
+ boolean success = false;
+ try {
+ XmlPullParser parser = Xml.newPullParser();
+ parser.setInput(stream, null);
+ int type;
+ success = true;
+ while ((type = parser.next()) != XmlPullParser.START_TAG
+ && type != XmlPullParser.END_DOCUMENT) {
+ ;
+ }
+ if (type != XmlPullParser.START_TAG) {
+ throw new IllegalStateException("no start tag found");
+ }
+
+ int outerDepth = parser.getDepth();
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+ if (type == XmlPullParser.END_TAG
+ || type == XmlPullParser.TEXT) {
+ continue;
+ }
+
+ String tagName = parser.getName();
+ if (tagName.equals("user-app")
+ || tagName.equals("system-app")) {
+ readDefaultPolicy(parser, tagName);
+ } else if (tagName.equals("application")) {
+ readApplicationPolicy(parser);
+ } else {
+ Slog.w(TAG, "Unknown element under <appops-policy>: "
+ + parser.getName());
+ XmlUtils.skipCurrentTag(parser);
+ }
+ }
+ } catch (IllegalStateException e) {
+ Slog.w(TAG, "Failed parsing " + e);
+ } catch (NullPointerException e) {
+ Slog.w(TAG, "Failed parsing " + e);
+ } catch (NumberFormatException e) {
+ Slog.w(TAG, "Failed parsing " + e);
+ } catch (XmlPullParserException e) {
+ Slog.w(TAG, "Failed parsing " + e);
+ } catch (IOException e) {
+ Slog.w(TAG, "Failed parsing " + e);
+ } catch (IndexOutOfBoundsException e) {
+ Slog.w(TAG, "Failed parsing " + e);
+ } finally {
+ if (!success) {
+ mPolicy.clear();
+ }
+ try {
+ stream.close();
+ } catch (IOException e) {
+ }
+ }
+ }
+ }
+
+ private void readDefaultPolicy(XmlPullParser parser, String packageName)
+ throws NumberFormatException, XmlPullParserException, IOException {
+ if (!"user-app".equalsIgnoreCase(packageName)
+ && !"system-app".equalsIgnoreCase(packageName)) {
+ return;
+ }
+ int mode = AppOpsManager.stringToMode(parser.getAttributeValue(null,
+ "permission"));
+ int show = stringToControl(parser.getAttributeValue(null, "show"));
+ if (mode == AppOpsManager.MODE_ERRORED && show == CONTROL_UNKNOWN) {
+ return;
+ }
+ PolicyPkg pkg = this.mPolicy.get(packageName);
+ if (pkg == null) {
+ pkg = new PolicyPkg(packageName, mode, show, packageName);
+ this.mPolicy.put(packageName, pkg);
+ } else {
+ Slog.w(TAG, "Duplicate policy found for package: " + packageName
+ + " of type: " + packageName);
+ pkg.mode = mode;
+ pkg.show = show;
+ }
+ }
+
+ private void readApplicationPolicy(XmlPullParser parser)
+ throws NumberFormatException, XmlPullParserException, IOException {
+ int outerDepth = parser.getDepth();
+ int type;
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+ if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+ continue;
+ }
+ String tagName = parser.getName();
+ if (tagName.equals("pkg")) {
+ readPkgPolicy(parser);
+ } else {
+ Slog.w(TAG,
+ "Unknown element under <application>: "
+ + parser.getName());
+ XmlUtils.skipCurrentTag(parser);
+ }
+ }
+ }
+
+ private void readPkgPolicy(XmlPullParser parser)
+ throws NumberFormatException, XmlPullParserException, IOException {
+ String packageName = parser.getAttributeValue(null, "name");
+ if (packageName == null)
+ return;
+ String appType = parser.getAttributeValue(null, "type");
+ if (appType == null)
+ return;
+ int mode = AppOpsManager.stringToMode(parser.getAttributeValue(null,
+ "permission"));
+ int show = stringToControl(parser.getAttributeValue(null, "show"));
+ String key = packageName + "." + appType;
+ PolicyPkg pkg = this.mPolicy.get(key);
+ if (pkg == null) {
+ pkg = new PolicyPkg(packageName, mode, show, appType);
+ this.mPolicy.put(key, pkg);
+ } else {
+ Slog.w(TAG, "Duplicate policy found for package: " + packageName
+ + " of type: " + appType);
+ pkg.mode = mode;
+ pkg.show = show;
+ }
+
+ int outerDepth = parser.getDepth();
+ int type;
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+ if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+ continue;
+ }
+ String tagName = parser.getName();
+ if (tagName.equals("op")) {
+ readOpPolicy(parser, pkg);
+ } else {
+ Slog.w(TAG, "Unknown element under <pkg>: " + parser.getName());
+ XmlUtils.skipCurrentTag(parser);
+ }
+ }
+ }
+
+ private void readOpPolicy(XmlPullParser parser, PolicyPkg pkg)
+ throws NumberFormatException, XmlPullParserException, IOException {
+ if (pkg == null) {
+ return;
+ }
+ String opName = parser.getAttributeValue(null, "name");
+ if (opName == null) {
+ Slog.w(TAG, "Op name is null");
+ return;
+ }
+ int code = AppOpsManager.stringOpToOp(opName);
+ if (code == AppOpsManager.OP_NONE) {
+ Slog.w(TAG, "Unknown Op: " + opName);
+ return;
+ }
+ int mode = AppOpsManager.stringToMode(parser.getAttributeValue(null,
+ "permission"));
+ int show = stringToControl(parser.getAttributeValue(null, "show"));
+ if (mode == AppOpsManager.MODE_ERRORED && show == CONTROL_UNKNOWN) {
+ return;
+ }
+ PolicyOp op = pkg.get(code);
+ if (op == null) {
+ op = new PolicyOp(code, mode, show);
+ pkg.put(code, op);
+ } else {
+ Slog.w(TAG, "Duplicate policy found for package: "
+ + pkg.packageName + " type: " + pkg.type + " op: " + op.op);
+ op.mode = mode;
+ op.show = show;
+ }
+ }
+
+ void debugPoilcy() {
+ Iterator<Map.Entry<String, PolicyPkg>> iterator = mPolicy.entrySet()
+ .iterator();
+ while (iterator.hasNext()) {
+ String key = iterator.next().getKey();
+ if (DEBUG)
+ Slog.d(TAG, "Key: " + key);
+ PolicyPkg pkg = mPolicy.get(key);
+ if (pkg == null) {
+ if (DEBUG)
+ Slog.d(TAG, "Pkg is null for key: " + key);
+ continue;
+ }
+ if (DEBUG)
+ Slog.d(TAG, pkg.toString());
+ for (int i = 0; i < pkg.size(); i++) {
+ PolicyOp op = pkg.valueAt(i);
+ if (DEBUG)
+ Slog.d(TAG, op.toString());
+ }
+ }
+ }
+
+ private String getAppType(String packageName) {
+ String appType = null;
+ ApplicationInfo appInfo = null;
+ if (mContext != null) {
+ try {
+ appInfo = mContext.getPackageManager().getApplicationInfo(
+ packageName, 0);
+ } catch (NameNotFoundException e) {
+ appInfo = null;
+ }
+ if (appInfo != null) {
+ if ((appInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
+ appType = "system-app";
+ } else {
+ appType = "user-app";
+ }
+ }
+ } else {
+ Slog.e(TAG, "Context is null");
+ }
+ return appType;
+ }
+
+ public boolean isControlAllowed(int code, String packageName) {
+ boolean isShow = true;
+ int show = CONTROL_UNKNOWN;
+ PolicyPkg pkg;
+ String key;
+ String type;
+
+ if (mPolicy == null) {
+ return isShow;
+ }
+
+ type = getAppType(packageName);
+ if (type != null) {
+ key = type;
+ pkg = mPolicy.get(key);
+ if (pkg != null && pkg.show != CONTROL_UNKNOWN) {
+ show = pkg.show;
+ }
+ }
+ key = packageName;
+ if (type != null) {
+ key = key + "." + type;
+ }
+ pkg = mPolicy.get(key);
+ if (pkg != null) {
+ if (pkg.show != CONTROL_UNKNOWN) {
+ show = pkg.show;
+ }
+ PolicyOp op = pkg.get(code);
+ if (op != null) {
+ if (op.show != CONTROL_UNKNOWN) {
+ show = op.show;
+ }
+ }
+ }
+ if (show == CONTROL_NOSHOW) {
+ isShow = false;
+ }
+ return isShow;
+ }
+
+ public int getDefualtMode(int code, String packageName) {
+ int mode = AppOpsManager.MODE_ERRORED;
+ PolicyPkg pkg;
+ String key;
+ String type;
+
+ if (mPolicy == null) {
+ return mode;
+ }
+ if (DEBUG)
+ Slog.d(TAG, "Default mode requested for op=" + code + " package="
+ + packageName);
+ type = getAppType(packageName);
+ if (type != null) {
+ // Get value based on 'type'
+ key = type;
+ pkg = mPolicy.get(key);
+ if (pkg != null && pkg.mode != AppOpsManager.MODE_ERRORED) {
+ if (DEBUG)
+ Slog.d(TAG, "Setting value based on type: " + pkg);
+ mode = pkg.mode;
+ }
+ }
+ // Get value based on 'pkg'.
+ key = packageName;
+ if (type != null) {
+ key = key + "." + type;
+ }
+ pkg = mPolicy.get(key);
+ if (pkg != null) {
+ if (pkg.mode != AppOpsManager.MODE_ERRORED) {
+ if (DEBUG)
+ Slog.d(TAG, "Setting value based on packageName: " + pkg);
+ mode = pkg.mode;
+ }
+ // Get value base on 'op'
+ PolicyOp op = pkg.get(code);
+ if (op != null) {
+ if (op.mode != AppOpsManager.MODE_ERRORED) {
+ if (DEBUG)
+ Slog.d(TAG, "Setting value based on op: " + op);
+ mode = op.mode;
+ }
+ }
+ }
+ if (DEBUG)
+ Slog.d(TAG, "Returning mode=" + mode);
+ return mode;
+ }
+} \ No newline at end of file
diff --git a/services/core/java/com/android/server/AppOpsService.java b/services/core/java/com/android/server/AppOpsService.java
index 96c1e2a..b5bf12c 100644
--- a/services/core/java/com/android/server/AppOpsService.java
+++ b/services/core/java/com/android/server/AppOpsService.java
@@ -1,4 +1,7 @@
/*
+ * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ *
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -35,7 +38,9 @@ import android.app.ActivityManager;
import android.app.ActivityThread;
import android.app.AppGlobals;
import android.app.AppOpsManager;
+import android.app.Dialog;
import android.content.Context;
+import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
@@ -45,6 +50,7 @@ import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
+import android.os.Looper;
import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
@@ -67,6 +73,7 @@ import com.android.internal.os.Zygote;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.XmlUtils;
+import com.android.server.PermissionDialogReqQueue.PermissionDialogReq;
import libcore.util.EmptyArray;
import org.xmlpull.v1.XmlPullParser;
@@ -80,9 +87,23 @@ public class AppOpsService extends IAppOpsService.Stub {
// Write at most every 30 minutes.
static final long WRITE_DELAY = DEBUG ? 1000 : 30*60*1000;
+ // Location of policy file.
+ static final String DEFAULT_POLICY_FILE = "/system/etc/appops_policy.xml";
+
Context mContext;
final AtomicFile mFile;
final Handler mHandler;
+ final Looper mLooper;
+ final boolean mStrictEnable;
+ AppOpsPolicy mPolicy;
+
+ private static final int[] PRIVACY_GUARD_OP_STATES = new int[] {
+ AppOpsManager.OP_COARSE_LOCATION,
+ AppOpsManager.OP_READ_CALL_LOG,
+ AppOpsManager.OP_READ_CONTACTS,
+ AppOpsManager.OP_READ_CALENDAR,
+ AppOpsManager.OP_READ_SMS
+ };
boolean mWriteScheduled;
boolean mFastWriteScheduled;
@@ -104,6 +125,14 @@ public class AppOpsService extends IAppOpsService.Stub {
final SparseArray<UidState> mUidStates = new SparseArray<>();
+ private Runnable mSuSessionChangedRunner = new Runnable() {
+ @Override
+ public void run() {
+ mContext.sendBroadcastAsUser(new Intent(AppOpsManager.ACTION_SU_SESSION_CHANGED),
+ UserHandle.ALL);
+ }
+ };
+
private final SparseArray<boolean[]> mOpRestrictions = new SparseArray<boolean[]>();
private static final class UidState {
@@ -149,12 +178,20 @@ public class AppOpsService extends IAppOpsService.Stub {
public long time;
public long rejectTime;
public int nesting;
-
- public Op(int _uid, String _packageName, int _op) {
+ public int noteOpCount;
+ public int startOpCount;
+ public PermissionDialogReqQueue dialogReqQueue;
+ final ArrayList<IBinder> clientTokens;
+ public int allowedCount;
+ public int ignoredCount;
+
+ public Op(int _uid, String _packageName, int _op, int _mode) {
uid = _uid;
packageName = _packageName;
op = _op;
- mode = AppOpsManager.opToDefaultMode(op);
+ mode = _mode;
+ dialogReqQueue = new PermissionDialogReqQueue();
+ clientTokens = new ArrayList<IBinder>();
}
}
@@ -226,17 +263,27 @@ public class AppOpsService extends IAppOpsService.Stub {
}
mClients.remove(mAppToken);
}
+
+ // We cannot broadcast on the synchronized block above because the broadcast might
+ // trigger another appop call that eventually arrives here from a different thread,
+ // causing a deadlock.
+ for (int i=mStartedOps.size()-1; i>=0; i--) {
+ broadcastOpIfNeeded(mStartedOps.get(i).op);
+ }
}
}
public AppOpsService(File storagePath, Handler handler) {
mFile = new AtomicFile(storagePath);
mHandler = handler;
+ mLooper = Looper.myLooper();
+ mStrictEnable = AppOpsManager.isStrictEnable();
readState();
}
public void publish(Context context) {
mContext = context;
+ readPolicy();
ServiceManager.addService(Context.APP_OPS_SERVICE, asBinder());
}
@@ -372,7 +419,7 @@ public class AppOpsService extends IAppOpsService.Stub {
Op curOp = pkgOps.valueAt(j);
resOps.add(new AppOpsManager.OpEntry(curOp.op, curOp.mode, curOp.time,
curOp.rejectTime, curOp.duration, curOp.proxyUid,
- curOp.proxyPackageName));
+ curOp.proxyPackageName, curOp.allowedCount, curOp.ignoredCount));
}
} else {
for (int j=0; j<ops.length; j++) {
@@ -383,7 +430,7 @@ public class AppOpsService extends IAppOpsService.Stub {
}
resOps.add(new AppOpsManager.OpEntry(curOp.op, curOp.mode, curOp.time,
curOp.rejectTime, curOp.duration, curOp.proxyUid,
- curOp.proxyPackageName));
+ curOp.proxyPackageName, curOp.allowedCount, curOp.ignoredCount));
}
}
}
@@ -475,7 +522,8 @@ public class AppOpsService extends IAppOpsService.Stub {
code = AppOpsManager.opToSwitch(code);
synchronized (this) {
- final int defaultMode = AppOpsManager.opToDefaultMode(code);
+ final int defaultMode = AppOpsManager.opToDefaultMode(code,
+ AppOpsManager.isStrictOp(code));
UidState uidState = getUidStateLocked(uid, false);
if (uidState == null) {
@@ -603,7 +651,7 @@ public class AppOpsService extends IAppOpsService.Stub {
}
repCbs.addAll(cbs);
}
- if (mode == AppOpsManager.opToDefaultMode(op.op)) {
+ if (mode == getDefaultMode(code, uid, packageName)) {
// If going into the default mode, prune this op
// if there is nothing else interesting in it.
pruneOp(op, uid, packageName);
@@ -730,9 +778,11 @@ public class AppOpsService extends IAppOpsService.Stub {
Ops pkgOps = ent.getValue();
for (int j=pkgOps.size()-1; j>=0; j--) {
Op curOp = pkgOps.valueAt(j);
+ int defaultMode = getDefaultMode(curOp.op, curOp.uid,
+ curOp.packageName);
if (AppOpsManager.opAllowsReset(curOp.op)
- && curOp.mode != AppOpsManager.opToDefaultMode(curOp.op)) {
- curOp.mode = AppOpsManager.opToDefaultMode(curOp.op);
+ && curOp.mode != defaultMode) {
+ curOp.mode = defaultMode;
changed = true;
callbacks = addCallbacks(callbacks, packageName, curOp.op,
mOpModeWatchers.get(curOp.op));
@@ -853,7 +903,7 @@ public class AppOpsService extends IAppOpsService.Stub {
}
Op op = getOpLocked(code, uid, packageName, false);
if (op == null) {
- return AppOpsManager.opToDefaultMode(code);
+ return getDefaultMode(code, uid, packageName);
}
return op.mode;
}
@@ -944,6 +994,7 @@ public class AppOpsService extends IAppOpsService.Stub {
private int noteOperationUnchecked(int code, int uid, String packageName,
int proxyUid, String proxyPackageName) {
+ final PermissionDialogReq req;
synchronized (this) {
Ops ops = getOpsLocked(uid, packageName, true);
if (ops == null) {
@@ -953,6 +1004,7 @@ public class AppOpsService extends IAppOpsService.Stub {
}
Op op = getOpLocked(ops, code, true);
if (isOpRestricted(uid, code, packageName)) {
+ op.ignoredCount++;
return AppOpsManager.MODE_IGNORED;
}
if (op.duration == -1) {
@@ -973,24 +1025,51 @@ public class AppOpsService extends IAppOpsService.Stub {
}
}
final Op switchOp = switchCode != code ? getOpLocked(ops, switchCode, true) : op;
- if (switchOp.mode != AppOpsManager.MODE_ALLOWED) {
- if (DEBUG) Log.d(TAG, "noteOperation: reject #" + op.mode + " for code "
- + switchCode + " (" + code + ") uid " + uid + " package " + packageName);
+ if (switchOp.mode != AppOpsManager.MODE_ALLOWED
+ && switchOp.mode != AppOpsManager.MODE_ASK) {
+ if (DEBUG)
+ Log.d(TAG, "noteOperation: reject #" + op.mode
+ + " for code " + switchCode + " (" + code
+ + ") uid " + uid + " package " + packageName);
op.rejectTime = System.currentTimeMillis();
+ op.ignoredCount++;
return switchOp.mode;
+ } else if (switchOp.mode == AppOpsManager.MODE_ALLOWED) {
+ if (DEBUG) Log.d(TAG, "noteOperation: allowing code " + code + " uid " + uid
+ + " package " + packageName);
+ op.time = System.currentTimeMillis();
+ op.rejectTime = 0;
+ op.proxyUid = proxyUid;
+ op.proxyPackageName = proxyPackageName;
+ op.allowedCount++;
+ broadcastOpIfNeeded(code);
+ return AppOpsManager.MODE_ALLOWED;
+
+ } else {
+ if (Looper.myLooper() == mLooper) {
+ Log.e(TAG,
+ "noteOperation: This method will deadlock if called from the main thread. (Code: "
+ + code
+ + " uid: "
+ + uid
+ + " package: "
+ + packageName + ")");
+ return switchOp.mode;
+ }
+ op.noteOpCount++;
+ req = askOperationLocked(code, uid, packageName, switchOp);
}
- if (DEBUG) Log.d(TAG, "noteOperation: allowing code " + code + " uid " + uid
- + " package " + packageName);
- op.time = System.currentTimeMillis();
- op.rejectTime = 0;
- op.proxyUid = proxyUid;
- op.proxyPackageName = proxyPackageName;
- return AppOpsManager.MODE_ALLOWED;
}
+
+ int result = req.get();
+ broadcastOpIfNeeded(code);
+ return result;
}
@Override
- public int startOperation(IBinder token, int code, int uid, String packageName) {
+ public int startOperation(IBinder token, int code, int uid,
+ String packageName) {
+ final PermissionDialogReq req;
verifyIncomingUid(uid);
verifyIncomingOp(code);
ClientState client = (ClientState)token;
@@ -1003,6 +1082,7 @@ public class AppOpsService extends IAppOpsService.Stub {
}
Op op = getOpLocked(ops, code, true);
if (isOpRestricted(uid, code, packageName)) {
+ op.ignoredCount++;
return AppOpsManager.MODE_IGNORED;
}
final int switchCode = AppOpsManager.opToSwitch(code);
@@ -1018,25 +1098,51 @@ public class AppOpsService extends IAppOpsService.Stub {
}
}
final Op switchOp = switchCode != code ? getOpLocked(ops, switchCode, true) : op;
- if (switchOp.mode != AppOpsManager.MODE_ALLOWED) {
- if (DEBUG) Log.d(TAG, "startOperation: reject #" + op.mode + " for code "
- + switchCode + " (" + code + ") uid " + uid + " package " + packageName);
+ if (switchOp.mode != AppOpsManager.MODE_ALLOWED
+ && switchOp.mode != AppOpsManager.MODE_ASK) {
+ if (DEBUG)
+ Log.d(TAG, "startOperation: reject #" + op.mode
+ + " for code " + switchCode + " (" + code
+ + ") uid " + uid + " package " + packageName);
op.rejectTime = System.currentTimeMillis();
+ op.ignoredCount++;
return switchOp.mode;
+ } else if (switchOp.mode == AppOpsManager.MODE_ALLOWED) {
+ if (DEBUG)
+ Log.d(TAG, "startOperation: allowing code " + code
+ + " uid " + uid + " package " + packageName);
+ if (op.nesting == 0) {
+ op.time = System.currentTimeMillis();
+ op.rejectTime = 0;
+ op.duration = -1;
+ op.allowedCount++;
+ }
+ op.nesting++;
+ if (client.mStartedOps != null) {
+ client.mStartedOps.add(op);
+ }
+ broadcastOpIfNeeded(code);
+ return AppOpsManager.MODE_ALLOWED;
+ } else {
+ if (Looper.myLooper() == mLooper) {
+ Log.e(TAG,
+ "startOperation: This method will deadlock if called from the main thread. (Code: "
+ + code
+ + " uid: "
+ + uid
+ + " package: "
+ + packageName + ")");
+ return switchOp.mode;
+ }
+ op.startOpCount++;
+ IBinder clientToken = client.mAppToken;
+ op.clientTokens.add(clientToken);
+ req = askOperationLocked(code, uid, packageName, switchOp);
}
- if (DEBUG) Log.d(TAG, "startOperation: allowing code " + code + " uid " + uid
- + " package " + packageName);
- if (op.nesting == 0) {
- op.time = System.currentTimeMillis();
- op.rejectTime = 0;
- op.duration = -1;
- }
- op.nesting++;
- if (client.mStartedOps != null) {
- client.mStartedOps.add(op);
- }
- return AppOpsManager.MODE_ALLOWED;
}
+ int result = req.get();
+ broadcastOpIfNeeded(code);
+ return result;
}
@Override
@@ -1057,6 +1163,7 @@ public class AppOpsService extends IAppOpsService.Stub {
}
finishOperationLocked(op);
}
+ broadcastOpIfNeeded(code);
}
@Override
@@ -1081,6 +1188,10 @@ public class AppOpsService extends IAppOpsService.Stub {
}
private void verifyIncomingUid(int uid) {
+ if (Binder.getCallingUid() == 0) {
+ // Allow root to delegate uid operations.
+ return;
+ }
if (uid == Binder.getCallingUid()) {
return;
}
@@ -1115,6 +1226,9 @@ public class AppOpsService extends IAppOpsService.Stub {
packageName = "root";
} else if (uid == Process.SHELL_UID) {
packageName = "com.android.shell";
+ } else if (uid == Process.SYSTEM_UID) {
+ if (packageName == null)
+ packageName = "android";
}
return getOpsRawLocked(uid, packageName, edit);
}
@@ -1202,12 +1316,14 @@ public class AppOpsService extends IAppOpsService.Stub {
}
private Op getOpLocked(Ops ops, int code, boolean edit) {
+ int mode;
Op op = ops.get(code);
if (op == null) {
if (!edit) {
return null;
}
- op = new Op(ops.uidState.uid, ops.packageName, code);
+ mode = getDefaultMode(code, ops.uidState.uid, ops.packageName);
+ op = new Op(ops.uidState.uid, ops.packageName, code, mode);
ops.put(code, op);
}
if (edit) {
@@ -1387,10 +1503,32 @@ public class AppOpsService extends IAppOpsService.Stub {
String tagName = parser.getName();
if (tagName.equals("op")) {
- Op op = new Op(uid, pkgName, Integer.parseInt(parser.getAttributeValue(null, "n")));
+ int code = Integer
+ .parseInt(parser.getAttributeValue(null, "n"));
+ // use op name string if it exists
+ String codeNameStr = parser.getAttributeValue(null, "ns");
+ if (codeNameStr != null) {
+ // returns OP_NONE if it could not be mapped
+ code = AppOpsManager.nameToOp(codeNameStr);
+ }
+ // skip op codes that are out of bounds
+ if (code == AppOpsManager.OP_NONE
+ || code >= AppOpsManager._NUM_OP) {
+ continue;
+ }
+ Op op = new Op(uid, pkgName, code, AppOpsManager.MODE_ERRORED);
String mode = parser.getAttributeValue(null, "m");
if (mode != null) {
op.mode = Integer.parseInt(mode);
+ } else {
+ String sDefualtMode = parser.getAttributeValue(null, "dm");
+ int defaultMode;
+ if (sDefualtMode != null) {
+ defaultMode = Integer.parseInt(sDefualtMode);
+ } else {
+ defaultMode = getDefaultMode(code, uid, pkgName);
+ }
+ op.mode = defaultMode;
}
String time = parser.getAttributeValue(null, "t");
if (time != null) {
@@ -1412,7 +1550,14 @@ public class AppOpsService extends IAppOpsService.Stub {
if (proxyPackageName != null) {
op.proxyPackageName = proxyPackageName;
}
-
+ String allowed = parser.getAttributeValue(null, "ac");
+ if (allowed != null) {
+ op.allowedCount = Integer.parseInt(allowed);
+ }
+ String ignored = parser.getAttributeValue(null, "ic");
+ if (ignored != null) {
+ op.ignoredCount = Integer.parseInt(ignored);
+ }
UidState uidState = getUidStateLocked(uid, true);
if (uidState.pkgOps == null) {
uidState.pkgOps = new ArrayMap<>();
@@ -1499,8 +1644,13 @@ public class AppOpsService extends IAppOpsService.Stub {
AppOpsManager.OpEntry op = ops.get(j);
out.startTag(null, "op");
out.attribute(null, "n", Integer.toString(op.getOp()));
- if (op.getMode() != AppOpsManager.opToDefaultMode(op.getOp())) {
+ out.attribute(null, "ns", AppOpsManager.opToName(op.getOp()));
+ int defaultMode = getDefaultMode(op.getOp(),
+ pkg.getUid(), pkg.getPackageName());
+ if (op.getMode() != defaultMode) {
out.attribute(null, "m", Integer.toString(op.getMode()));
+ } else {
+ out.attribute(null, "dm", Integer.toString(defaultMode));
}
long time = op.getTime();
if (time != 0) {
@@ -1522,6 +1672,14 @@ public class AppOpsService extends IAppOpsService.Stub {
if (proxyPackageName != null) {
out.attribute(null, "pp", proxyPackageName);
}
+ int allowed = op.getAllowedCount();
+ if (allowed != 0) {
+ out.attribute(null, "ac", Integer.toString(allowed));
+ }
+ int ignored = op.getIgnoredCount();
+ if (ignored != 0) {
+ out.attribute(null, "ic", Integer.toString(ignored));
+ }
out.endTag(null, "op");
}
out.endTag(null, "uid");
@@ -1765,14 +1923,181 @@ public class AppOpsService extends IAppOpsService.Stub {
private void checkSystemUid(String function) {
int uid = Binder.getCallingUid();
if (uid != Process.SYSTEM_UID) {
- throw new SecurityException(function + " must by called by the system");
+ throw new SecurityException(function
+ + " must by called by the system");
+ }
+ }
+
+ final class AskRunnable implements Runnable {
+ final int code;
+ final int uid;
+ final String packageName;
+ final Op op;
+ final PermissionDialogReq request;
+
+ public AskRunnable(int code, int uid, String packageName, Op op,
+ PermissionDialogReq request) {
+ super();
+ this.code = code;
+ this.uid = uid;
+ this.packageName = packageName;
+ this.op = op;
+ this.request = request;
+ }
+
+ @Override
+ public void run() {
+ PermissionDialog permDialog = null;
+ synchronized (AppOpsService.this) {
+ Log.e(TAG, "Creating dialog box");
+ op.dialogReqQueue.register(request);
+ if (op.dialogReqQueue.getDialog() == null) {
+ permDialog = new PermissionDialog(mContext,
+ AppOpsService.this, code, uid, packageName);
+ op.dialogReqQueue.setDialog(permDialog);
+ }
+ }
+ if (permDialog != null) {
+ permDialog.show();
+ }
+ }
+ }
+
+ private PermissionDialogReq askOperationLocked(int code, int uid,
+ String packageName, Op op) {
+ PermissionDialogReq request = new PermissionDialogReq();
+ mHandler.post(new AskRunnable(code, uid, packageName, op, request));
+ return request;
+ }
+
+ private int getDefaultMode(int code, int uid, String packageName) {
+ int mode = AppOpsManager.opToDefaultMode(code,
+ isStrict(code, uid, packageName));
+ if (AppOpsManager.isStrictOp(code) && mPolicy != null) {
+ int policyMode = mPolicy.getDefualtMode(code, packageName);
+ if (policyMode != AppOpsManager.MODE_ERRORED) {
+ mode = policyMode;
+ }
+ }
+ return mode;
+ }
+
+ private boolean isStrict(int code, int uid, String packageName) {
+ if (!mStrictEnable)
+ return false;
+
+ return UserHandle.isApp(uid);
+ }
+
+ private void printOperationLocked(Op op, int mode, String operation) {
+ if(op != null) {
+ int switchCode = AppOpsManager.opToSwitch(op.op);
+ if (mode == AppOpsManager.MODE_IGNORED) {
+ if (DEBUG) Log.d(TAG, operation + ": reject #" + mode + " for code "
+ + switchCode + " (" + op.op + ") uid " + op.uid + " package "
+ + op.packageName);
+ } else if (mode == AppOpsManager.MODE_ALLOWED) {
+ if (DEBUG) Log.d(TAG, operation + ": allowing code " + op.op + " uid "
+ + op.uid
+ + " package " + op.packageName);
+ }
+ }
+ }
+
+ private void recordOperationLocked(int code, int uid, String packageName,
+ int mode) {
+ Op op = getOpLocked(code, uid, packageName, false);
+ if(op != null) {
+ if(op.noteOpCount != 0)
+ printOperationLocked(op, mode, "noteOperartion");
+ if(op.startOpCount != 0)
+ printOperationLocked(op, mode, "startOperation");
+ if (mode == AppOpsManager.MODE_IGNORED) {
+ op.rejectTime = System.currentTimeMillis();
+ } else if (mode == AppOpsManager.MODE_ALLOWED) {
+ if(op.noteOpCount != 0) {
+ op.time = System.currentTimeMillis();
+ op.rejectTime = 0;
+ }
+ if(op.startOpCount != 0) {
+ if(op.nesting == 0) {
+ op.time = System.currentTimeMillis();
+ op.rejectTime = 0;
+ op.duration = -1;
+ }
+ op.nesting = op.nesting + op.startOpCount;
+ while(op.clientTokens.size() != 0) {
+ IBinder clientToken = op.clientTokens.get(0);
+ ClientState client = mClients.get(clientToken);
+ if (client != null) {
+ if (client.mStartedOps != null) {
+ client.mStartedOps.add(op);
+ }
+ }
+ op.clientTokens.remove(0);
+ }
+ }
+ }
+ op.clientTokens.clear();
+ op.startOpCount = 0;
+ op.noteOpCount = 0;
+ }
+ }
+
+ public void notifyOperation(int code, int uid, String packageName,
+ int mode, boolean remember) {
+ verifyIncomingUid(uid);
+ verifyIncomingOp(code);
+ ArrayList<Callback> repCbs = null;
+ int switchCode = AppOpsManager.opToSwitch(code);
+ synchronized (this) {
+ recordOperationLocked(code, uid, packageName, mode);
+ Op op = getOpLocked(switchCode, uid, packageName, true);
+ if (op != null) {
+ // Send result to all waiting client
+ if (op.dialogReqQueue.getDialog() != null) {
+ op.dialogReqQueue.notifyAll(mode);
+ op.dialogReqQueue.setDialog(null);
+ }
+ if (remember && op.mode != mode) {
+ op.mode = mode;
+ ArrayList<Callback> cbs = mOpModeWatchers.get(switchCode);
+ if (cbs != null) {
+ if (repCbs == null) {
+ repCbs = new ArrayList<Callback>();
+ }
+ repCbs.addAll(cbs);
+ }
+ cbs = mPackageModeWatchers.get(packageName);
+ if (cbs != null) {
+ if (repCbs == null) {
+ repCbs = new ArrayList<Callback>();
+ }
+ repCbs.addAll(cbs);
+ }
+ if (mode == getDefaultMode(op.op, op.uid, op.packageName)) {
+ // If going into the default mode, prune this op
+ // if there is nothing else interesting in it.
+ pruneOp(op, uid, packageName);
+ }
+ scheduleWriteLocked();
+ }
+ }
+ }
+ if (repCbs != null) {
+ for (int i = 0; i < repCbs.size(); i++) {
+ try {
+ repCbs.get(i).mCallback.opChanged(switchCode, packageName);
+ } catch (RemoteException e) {
+ }
+ }
}
}
private static String[] getPackagesForUid(int uid) {
String[] packageNames = null;
try {
- packageNames= AppGlobals.getPackageManager().getPackagesForUid(uid);
+ packageNames = AppGlobals.getPackageManager().getPackagesForUid(uid);
} catch (RemoteException e) {
/* ignore - local call */
}
@@ -1781,4 +2106,75 @@ public class AppOpsService extends IAppOpsService.Stub {
}
return packageNames;
}
+
+ private void broadcastOpIfNeeded(int op) {
+ switch (op) {
+ case AppOpsManager.OP_SU:
+ mHandler.post(mSuSessionChangedRunner);
+ break;
+ default:
+ break;
+ }
+ }
+
+ private void readPolicy() {
+ if (mStrictEnable) {
+ mPolicy = new AppOpsPolicy(new File(DEFAULT_POLICY_FILE), mContext);
+ mPolicy.readPolicy();
+ mPolicy.debugPoilcy();
+ } else {
+ mPolicy = null;
+ }
+ }
+
+ public boolean isControlAllowed(int code, String packageName) {
+ boolean isShow = true;
+ if (mPolicy != null) {
+ isShow = mPolicy.isControlAllowed(code, packageName);
+ }
+ return isShow;
+ }
+
+ @Override
+ public boolean getPrivacyGuardSettingForPackage(int uid, String packageName) {
+ for (int op : PRIVACY_GUARD_OP_STATES) {
+ int switchOp = AppOpsManager.opToSwitch(op);
+ int mode = checkOperation(op, uid, packageName);
+ if (mode != AppOpsManager.MODE_ALLOWED && mode != AppOpsManager.MODE_IGNORED) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public void setPrivacyGuardSettingForPackage(int uid, String packageName, boolean state) {
+ for (int op : PRIVACY_GUARD_OP_STATES) {
+ int switchOp = AppOpsManager.opToSwitch(op);
+ setMode(switchOp, uid, packageName, state
+ ? AppOpsManager.MODE_ASK : AppOpsManager.MODE_ALLOWED);
+ }
+ }
+
+ @Override
+ public void resetCounters() {
+ mContext.enforcePermission(android.Manifest.permission.UPDATE_APP_OPS_STATS,
+ Binder.getCallingPid(), Binder.getCallingUid(), null);
+ synchronized (this) {
+ for (int i=0; i<mUidStates.size(); i++) {
+ final UidState uidState = mUidStates.valueAt(i);
+ for (Map.Entry<String, Ops> ent : uidState.pkgOps.entrySet()) {
+ String packageName = ent.getKey();
+ Ops pkgOps = ent.getValue();
+ for (int j=0; j<pkgOps.size(); j++) {
+ Op curOp = pkgOps.valueAt(j);
+ curOp.allowedCount = 0;
+ curOp.ignoredCount = 0;
+ }
+ }
+ }
+ // ensure the counter reset persists
+ scheduleWriteLocked();
+ }
+ }
}
diff --git a/services/core/java/com/android/server/AssetAtlasService.java b/services/core/java/com/android/server/AssetAtlasService.java
index 4569dae..ff4456e 100644
--- a/services/core/java/com/android/server/AssetAtlasService.java
+++ b/services/core/java/com/android/server/AssetAtlasService.java
@@ -391,6 +391,11 @@ public class AssetAtlasService extends IAssetAtlas.Stub {
}
}
+ if (results.size() == 0) {
+ if (DEBUG_ATLAS) Log.w(LOG_TAG, "No atlas configuration found!");
+ return null;
+ }
+
// Maximize the number of packed bitmaps, minimize the texture size
Collections.sort(results, new Comparator<WorkerResult>() {
@Override
diff --git a/services/core/java/com/android/server/BasePermissionDialog.java b/services/core/java/com/android/server/BasePermissionDialog.java
new file mode 100644
index 0000000..e3dbcda
--- /dev/null
+++ b/services/core/java/com/android/server/BasePermissionDialog.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ *
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+import android.app.AlertDialog;
+import android.content.Context;
+import android.os.Handler;
+import android.os.Message;
+import android.view.KeyEvent;
+import android.view.WindowManager;
+import android.widget.Button;
+
+import com.android.internal.R;
+
+public class BasePermissionDialog extends AlertDialog {
+ public BasePermissionDialog(Context context) {
+ super(context, com.android.internal.R.style.Theme_Dialog_AppError);
+ getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
+ getWindow().setFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
+ WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
+ WindowManager.LayoutParams attrs = getWindow().getAttributes();
+ attrs.setTitle("Permission Dialog");
+ getWindow().setAttributes(attrs);
+ setIconAttribute(R.attr.alertDialogIcon);
+ }
+
+ public void onStart() {
+ super.onStart();
+ setEnabled(false);
+ mHandler.sendMessage(mHandler.obtainMessage(0));
+ }
+
+ public boolean dispatchKeyEvent(KeyEvent event) {
+ if (mConsuming) {
+ // Slog.i(TAG, "Consuming: " + event);
+ return true;
+ }
+ // Slog.i(TAG, "Dispatching: " + event);
+ return super.dispatchKeyEvent(event);
+ }
+
+ private void setEnabled(boolean enabled) {
+ Button b = (Button) findViewById(R.id.button1);
+ if (b != null) {
+ b.setEnabled(enabled);
+ }
+ b = (Button) findViewById(R.id.button2);
+ if (b != null) {
+ b.setEnabled(enabled);
+ }
+ b = (Button) findViewById(R.id.button3);
+ if (b != null) {
+ b.setEnabled(enabled);
+ }
+ }
+
+ private Handler mHandler = new Handler() {
+ public void handleMessage(Message msg) {
+ if (msg.what == 0) {
+ mConsuming = false;
+ setEnabled(true);
+ }
+ }
+ };
+
+ private boolean mConsuming = true;
+}
diff --git a/services/core/java/com/android/server/BatteryService.java b/services/core/java/com/android/server/BatteryService.java
index 2eeaec9..238e9c9 100644
--- a/services/core/java/com/android/server/BatteryService.java
+++ b/services/core/java/com/android/server/BatteryService.java
@@ -29,6 +29,8 @@ 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.os.BatteryManager;
import android.os.BatteryManagerInternal;
import android.os.BatteryProperties;
@@ -47,13 +49,20 @@ import android.os.UserHandle;
import android.provider.Settings;
import android.util.EventLog;
import android.util.Slog;
+import cyanogenmod.providers.CMSettings;
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.io.BufferedInputStream;
+import java.io.BufferedReader;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintWriter;
+import cyanogenmod.providers.CMSettings;
/**
* <p>BatteryService monitors the charging status, and charge level of the device
@@ -92,6 +101,9 @@ public final class BatteryService extends SystemService {
private static final int BATTERY_SCALE = 100; // battery capacity is a percentage
+ // notification light maximum brightness value to use
+ private static final int LIGHT_BRIGHTNESS_MAXIMUM = 255;
+
// Used locally for determining when to make a last ditch effort to log
// discharge stats before the device dies.
private int mCriticalBatteryLevel;
@@ -125,6 +137,12 @@ public final class BatteryService extends SystemService {
private int mInvalidCharger;
private int mLastInvalidCharger;
+ private boolean mAdjustableNotificationLedBrightness;
+ private int mNotificationLedBrightnessLevel = LIGHT_BRIGHTNESS_MAXIMUM;
+
+ private boolean mMultipleNotificationLeds;
+ private boolean mMultipleLedsEnabled = false;
+
private int mLowBatteryWarningLevel;
private int mLowBatteryCloseWarningLevel;
private int mShutdownBatteryTemperature;
@@ -140,6 +158,13 @@ public final class BatteryService extends SystemService {
private boolean mUpdatesStopped;
private Led mLed;
+ // Disable LED until SettingsObserver can be started
+ private boolean mLightEnabled = false;
+ private boolean mLedPulseEnabled;
+ private int mBatteryLowARGB;
+ private int mBatteryMediumARGB;
+ private int mBatteryFullARGB;
+ private boolean mMultiColorLed;
private boolean mSentLowBatteryBroadcast = false;
@@ -201,6 +226,9 @@ public final class BatteryService extends SystemService {
false, obs, UserHandle.USER_ALL);
updateBatteryWarningLevelLocked();
}
+ } else if (phase == PHASE_BOOT_COMPLETED) {
+ SettingsObserver observer = new SettingsObserver(new Handler());
+ observer.observe();
}
}
@@ -257,8 +285,10 @@ public final class BatteryService extends SystemService {
private void shutdownIfNoPowerLocked() {
// shut down gracefully if our battery is critically low and we are not powered.
+ // or the battery voltage is decreasing (consumption rate higher than charging rate)
// wait until the system has booted before attempting to display the shutdown dialog.
- if (mBatteryProps.batteryLevel == 0 && !isPoweredLocked(BatteryManager.BATTERY_PLUGGED_ANY)) {
+ if (mBatteryProps.batteryLevel == 0 && (!isPoweredLocked(BatteryManager.BATTERY_PLUGGED_ANY) ||
+ mBatteryProps.batteryVoltage < mLastBatteryVoltage) ) {
mHandler.post(new Runnable() {
@Override
public void run() {
@@ -720,53 +750,110 @@ public final class BatteryService extends SystemService {
}
};
+ private synchronized void updateLedPulse() {
+ mLed.updateLightsLocked();
+ }
+
private final class Led {
private final Light mBatteryLight;
- private final int mBatteryLowARGB;
- private final int mBatteryMediumARGB;
- private final int mBatteryFullARGB;
private final int mBatteryLedOn;
private final int mBatteryLedOff;
public Led(Context context, LightsManager lights) {
mBatteryLight = lights.getLight(LightsManager.LIGHT_ID_BATTERY);
- mBatteryLowARGB = context.getResources().getInteger(
- com.android.internal.R.integer.config_notificationsBatteryLowARGB);
- mBatteryMediumARGB = context.getResources().getInteger(
- com.android.internal.R.integer.config_notificationsBatteryMediumARGB);
- mBatteryFullARGB = context.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);
+
+ // Is the notification LED brightness changeable ?
+ mAdjustableNotificationLedBrightness = context.getResources().getBoolean(
+ org.cyanogenmod.platform.internal.R.bool.config_adjustableNotificationLedBrightness);
+
+ // Does the Device have multiple LEDs ?
+ mMultipleNotificationLeds = context.getResources().getBoolean(
+ org.cyanogenmod.platform.internal.R.bool.config_multipleNotificationLeds);
+
mBatteryLedOn = context.getResources().getInteger(
com.android.internal.R.integer.config_notificationsBatteryLedOn);
mBatteryLedOff = context.getResources().getInteger(
com.android.internal.R.integer.config_notificationsBatteryLedOff);
}
+ private boolean isHvdcpPresent() {
+ File mChargerTypeFile = new File("/sys/class/power_supply/usb/type");
+ FileReader fileReader;
+ BufferedReader br;
+ String type;
+ boolean ret;
+
+ try {
+ fileReader = new FileReader(mChargerTypeFile);
+ br = new BufferedReader(fileReader);
+ type = br.readLine();
+ if (type.regionMatches(true, 0, "USB_HVDCP", 0, 9))
+ ret = true;
+ else
+ ret = false;
+ br.close();
+ fileReader.close();
+ } catch (FileNotFoundException e) {
+ ret = false;
+ Slog.e(TAG, "Failure in reading charger type", e);
+ } catch (IOException e) {
+ ret = false;
+ Slog.e(TAG, "Failure in reading charger type", e);
+ }
+
+ return ret;
+ }
+
/**
* Synchronize on BatteryService.
*/
public void updateLightsLocked() {
+ // mBatteryProps could be null on startup (called by SettingsObserver)
+ if (mBatteryProps == null) {
+ Slog.w(TAG, "updateLightsLocked: mBatteryProps is null; skipping");
+ return;
+ }
+
final int level = mBatteryProps.batteryLevel;
final int status = mBatteryProps.batteryStatus;
- if (level < mLowBatteryWarningLevel) {
+ if (!mLightEnabled) {
+ // No lights if explicitly disabled
+ mBatteryLight.turnOff();
+ } else if (level < mLowBatteryWarningLevel) {
+ mBatteryLight.setModes(mNotificationLedBrightnessLevel,
+ mMultipleLedsEnabled);
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, Light.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) {
+ mBatteryLight.setModes(mNotificationLedBrightnessLevel,
+ mMultipleLedsEnabled);
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
- mBatteryLight.setColor(mBatteryMediumARGB);
+ if (isHvdcpPresent()) {
+ // Blinking orange if HVDCP charger
+ mBatteryLight.setFlashing(mBatteryMediumARGB, Light.LIGHT_FLASH_TIMED,
+ mBatteryLedOn, mBatteryLedOn);
+ } else {
+ // Battery is charging and halfway full
+ mBatteryLight.setColor(mBatteryMediumARGB);
+ }
}
} else {
// No lights if not charging and not low
@@ -839,4 +926,96 @@ public final class BatteryService extends SystemService {
}
}
}
+
+ class SettingsObserver extends ContentObserver {
+ SettingsObserver(Handler handler) {
+ super(handler);
+ }
+
+ void observe() {
+ ContentResolver resolver = mContext.getContentResolver();
+
+ // Battery light enabled
+ resolver.registerContentObserver(CMSettings.System.getUriFor(
+ CMSettings.System.BATTERY_LIGHT_ENABLED), false, this, UserHandle.USER_ALL);
+
+ // Low battery pulse
+ resolver.registerContentObserver(CMSettings.System.getUriFor(
+ CMSettings.System.BATTERY_LIGHT_PULSE), false, this, UserHandle.USER_ALL);
+
+ // Notification LED brightness
+ if (mAdjustableNotificationLedBrightness) {
+ resolver.registerContentObserver(CMSettings.System.getUriFor(
+ CMSettings.System.NOTIFICATION_LIGHT_BRIGHTNESS_LEVEL),
+ false, this, UserHandle.USER_ALL);
+ }
+
+ // Multiple LEDs enabled
+ if (mMultipleNotificationLeds) {
+ resolver.registerContentObserver(CMSettings.System.getUriFor(
+ CMSettings.System.NOTIFICATION_LIGHT_MULTIPLE_LEDS_ENABLE),
+ false, this, UserHandle.USER_ALL);
+ }
+
+ // Light colors
+ if (mMultiColorLed) {
+ // Register observer if we have a multi color led
+ resolver.registerContentObserver(
+ CMSettings.System.getUriFor(CMSettings.System.BATTERY_LIGHT_LOW_COLOR),
+ false, this, UserHandle.USER_ALL);
+ resolver.registerContentObserver(
+ CMSettings.System.getUriFor(CMSettings.System.BATTERY_LIGHT_MEDIUM_COLOR),
+ false, this, UserHandle.USER_ALL);
+ resolver.registerContentObserver(
+ CMSettings.System.getUriFor(CMSettings.System.BATTERY_LIGHT_FULL_COLOR),
+ false, this, UserHandle.USER_ALL);
+ }
+
+ update();
+ }
+
+ @Override public void onChange(boolean selfChange) {
+ update();
+ }
+
+ public void update() {
+ ContentResolver resolver = mContext.getContentResolver();
+ Resources res = mContext.getResources();
+
+ // Battery light enabled
+ mLightEnabled = CMSettings.System.getInt(resolver,
+ CMSettings.System.BATTERY_LIGHT_ENABLED, 1) != 0;
+
+ // Low battery pulse
+ mLedPulseEnabled = CMSettings.System.getInt(resolver,
+ CMSettings.System.BATTERY_LIGHT_PULSE, 1) != 0;
+
+ // Light colors
+ mBatteryLowARGB = CMSettings.System.getInt(resolver,
+ CMSettings.System.BATTERY_LIGHT_LOW_COLOR, res.getInteger(
+ com.android.internal.R.integer.config_notificationsBatteryLowARGB));
+ mBatteryMediumARGB = CMSettings.System.getInt(resolver,
+ CMSettings.System.BATTERY_LIGHT_MEDIUM_COLOR, res.getInteger(
+ com.android.internal.R.integer.config_notificationsBatteryMediumARGB));
+ mBatteryFullARGB = CMSettings.System.getInt(resolver,
+ CMSettings.System.BATTERY_LIGHT_FULL_COLOR, res.getInteger(
+ com.android.internal.R.integer.config_notificationsBatteryFullARGB));
+
+ // Notification LED brightness
+ if (mAdjustableNotificationLedBrightness) {
+ mNotificationLedBrightnessLevel = CMSettings.System.getInt(resolver,
+ CMSettings.System.NOTIFICATION_LIGHT_BRIGHTNESS_LEVEL,
+ LIGHT_BRIGHTNESS_MAXIMUM);
+ }
+
+ // Multiple LEDs enabled
+ if (mMultipleNotificationLeds) {
+ mMultipleLedsEnabled = CMSettings.System.getInt(resolver,
+ CMSettings.System.NOTIFICATION_LIGHT_MULTIPLE_LEDS_ENABLE,
+ mMultipleNotificationLeds ? 1 : 0) != 0;
+ }
+
+ updateLedPulse();
+ }
+ }
}
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index 50bd544..6067bd2 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -1,4 +1,7 @@
/*
+ * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ *
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,16 +21,14 @@ package com.android.server;
import android.Manifest;
import android.app.ActivityManager;
+import android.app.AppOpsManager;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
-import android.bluetooth.BluetoothProfile;
import android.bluetooth.IBluetooth;
import android.bluetooth.IBluetoothCallback;
import android.bluetooth.IBluetoothGatt;
-import android.bluetooth.IBluetoothHeadset;
import android.bluetooth.IBluetoothManager;
import android.bluetooth.IBluetoothManagerCallback;
-import android.bluetooth.IBluetoothProfileServiceConnection;
import android.bluetooth.IBluetoothStateChangeCallback;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
@@ -63,7 +64,7 @@ import java.util.Map;
class BluetoothManagerService extends IBluetoothManager.Stub {
private static final String TAG = "BluetoothManagerService";
- private static final boolean DBG = false;
+ private static final boolean DBG = true;
private static final String BLUETOOTH_ADMIN_PERM = android.Manifest.permission.BLUETOOTH_ADMIN;
private static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH;
@@ -80,8 +81,6 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
private static final int ERROR_RESTART_TIME_MS = 3000;
//Maximum msec to delay MESSAGE_USER_SWITCHED
private static final int USER_SWITCHED_TIME_MS = 200;
- // Delay for the addProxy function in msec
- private static final int ADD_PROXY_DELAY_MS = 100;
private static final int MESSAGE_ENABLE = 1;
private static final int MESSAGE_DISABLE = 2;
@@ -98,8 +97,6 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
private static final int MESSAGE_GET_NAME_AND_ADDRESS=200;
private static final int MESSAGE_SAVE_NAME_AND_ADDRESS=201;
private static final int MESSAGE_USER_SWITCHED = 300;
- private static final int MESSAGE_ADD_PROXY_DELAYED = 400;
- private static final int MESSAGE_BIND_PROFILE_SERVICE = 401;
private static final int MAX_SAVE_RETRIES=3;
private static final int MAX_ERROR_RESTART_RETRIES=6;
@@ -151,11 +148,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
private final BluetoothHandler mHandler;
private int mErrorRecoveryRetryCounter;
private final int mSystemUiUid;
-
- // Save a ProfileServiceConnections object for each of the bound
- // bluetooth profile services
- private final Map <Integer, ProfileServiceConnections> mProfileServices =
- new HashMap <Integer, ProfileServiceConnections>();
+ private boolean mIntentPending = false;
private void registerForAirplaneMode(IntentFilter filter) {
final ContentResolver resolver = mContext.getContentResolver();
@@ -618,7 +611,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
return true;
}
- public boolean enable() {
+ public boolean enable(String callingPackage) {
if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
(!checkIfCallerIsForegroundUser())) {
Log.w(TAG,"enable(): not allowed for non-active and non system user");
@@ -632,6 +625,13 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
" mBinding = " + mBinding);
}
+ AppOpsManager appOps = (AppOpsManager) mContext
+ .getSystemService(Context.APP_OPS_SERVICE);
+ int callingUid = Binder.getCallingUid();
+ if (appOps.noteOp(AppOpsManager.OP_BLUETOOTH_CHANGE, callingUid,
+ callingPackage) != AppOpsManager.MODE_ALLOWED)
+ return false;
+
synchronized(mReceiver) {
mQuietEnableExternal = false;
mEnableExternal = true;
@@ -706,69 +706,6 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
return mBluetoothGatt;
}
- @Override
- public boolean bindBluetoothProfileService(int bluetoothProfile,
- IBluetoothProfileServiceConnection proxy) {
- if (!mEnable) {
- if (DBG) {
- Log.d(TAG, "Trying to bind to profile: " + bluetoothProfile +
- ", while Bluetooth was disabled");
- }
- return false;
- }
- synchronized (mProfileServices) {
- ProfileServiceConnections psc = mProfileServices.get(new Integer(bluetoothProfile));
- if (psc == null) {
- if (DBG) {
- Log.d(TAG, "Creating new ProfileServiceConnections object for"
- + " profile: " + bluetoothProfile);
- }
-
- if (bluetoothProfile != BluetoothProfile.HEADSET) return false;
-
- Intent intent = new Intent(IBluetoothHeadset.class.getName());
- psc = new ProfileServiceConnections(intent);
- if (!psc.bindService()) return false;
-
- mProfileServices.put(new Integer(bluetoothProfile), psc);
- }
- }
-
- // Introducing a delay to give the client app time to prepare
- Message addProxyMsg = mHandler.obtainMessage(MESSAGE_ADD_PROXY_DELAYED);
- addProxyMsg.arg1 = bluetoothProfile;
- addProxyMsg.obj = proxy;
- mHandler.sendMessageDelayed(addProxyMsg, ADD_PROXY_DELAY_MS);
- return true;
- }
-
- @Override
- public void unbindBluetoothProfileService(int bluetoothProfile,
- IBluetoothProfileServiceConnection proxy) {
- synchronized (mProfileServices) {
- ProfileServiceConnections psc = mProfileServices.get(new Integer(bluetoothProfile));
- if (psc == null) {
- return;
- }
- psc.removeProxy(proxy);
- }
- }
-
- private void unbindAllBluetoothProfileServices() {
- synchronized (mProfileServices) {
- for (Integer i : mProfileServices.keySet()) {
- ProfileServiceConnections psc = mProfileServices.get(i);
- try {
- mContext.unbindService(psc);
- } catch (IllegalArgumentException e) {
- Log.e(TAG, "Unable to unbind service with intent: " + psc.mIntent, e);
- }
- psc.removeAllProxies();
- }
- mProfileServices.clear();
- }
- }
-
/**
* Send enable message and set adapter name and address. Called when the boot phase becomes
* PHASE_SYSTEM_SERVICES_READY.
@@ -794,148 +731,6 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_USER_SWITCHED, userHandle, 0));
}
- /**
- * This class manages the clients connected to a given ProfileService
- * and maintains the connection with that service.
- */
- final private class ProfileServiceConnections implements ServiceConnection,
- IBinder.DeathRecipient {
- final RemoteCallbackList<IBluetoothProfileServiceConnection> mProxies =
- new RemoteCallbackList <IBluetoothProfileServiceConnection>();
- IBinder mService;
- ComponentName mClassName;
- Intent mIntent;
- boolean mInvokingProxyCallbacks = false;
-
- ProfileServiceConnections(Intent intent) {
- mService = null;
- mClassName = null;
- mIntent = intent;
- }
-
- private boolean bindService() {
- if (mIntent != null && mService == null &&
- doBind(mIntent, this, 0, UserHandle.CURRENT_OR_SELF)) {
- Message msg = mHandler.obtainMessage(MESSAGE_BIND_PROFILE_SERVICE);
- msg.obj = this;
- mHandler.sendMessageDelayed(msg, TIMEOUT_BIND_MS);
- return true;
- }
- Log.w(TAG, "Unable to bind with intent: " + mIntent);
- return false;
- }
-
- private void addProxy(IBluetoothProfileServiceConnection proxy) {
- mProxies.register(proxy);
- if (mService != null) {
- try{
- proxy.onServiceConnected(mClassName, mService);
- } catch (RemoteException e) {
- Log.e(TAG, "Unable to connect to proxy", e);
- }
- } else {
- if (!mHandler.hasMessages(MESSAGE_BIND_PROFILE_SERVICE, this)) {
- Message msg = mHandler.obtainMessage(MESSAGE_BIND_PROFILE_SERVICE);
- msg.obj = this;
- mHandler.sendMessage(msg);
- }
- }
- }
-
- private void removeProxy(IBluetoothProfileServiceConnection proxy) {
- if (proxy != null) {
- if (mProxies.unregister(proxy)) {
- try {
- proxy.onServiceDisconnected(mClassName);
- } catch (RemoteException e) {
- Log.e(TAG, "Unable to disconnect proxy", e);
- }
- }
- } else {
- Log.w(TAG, "Trying to remove a null proxy");
- }
- }
-
- private void removeAllProxies() {
- onServiceDisconnected(mClassName);
- mProxies.kill();
- }
-
- @Override
- public void onServiceConnected(ComponentName className, IBinder service) {
- // remove timeout message
- mHandler.removeMessages(MESSAGE_BIND_PROFILE_SERVICE, this);
- mService = service;
- mClassName = className;
- try {
- mService.linkToDeath(this, 0);
- } catch (RemoteException e) {
- Log.e(TAG, "Unable to linkToDeath", e);
- }
-
- if (mInvokingProxyCallbacks) {
- Log.e(TAG, "Proxy callbacks already in progress.");
- return;
- }
- mInvokingProxyCallbacks = true;
-
- final int n = mProxies.beginBroadcast();
- try {
- for (int i = 0; i < n; i++) {
- try {
- mProxies.getBroadcastItem(i).onServiceConnected(className, service);
- } catch (RemoteException e) {
- Log.e(TAG, "Unable to connect to proxy", e);
- }
- }
- } finally {
- mProxies.finishBroadcast();
- mInvokingProxyCallbacks = false;
- }
- }
-
- @Override
- public void onServiceDisconnected(ComponentName className) {
- if (mService == null) return;
- mService.unlinkToDeath(this, 0);
- mService = null;
- mClassName = null;
-
- if (mInvokingProxyCallbacks) {
- Log.e(TAG, "Proxy callbacks already in progress.");
- return;
- }
- mInvokingProxyCallbacks = true;
-
- final int n = mProxies.beginBroadcast();
- try {
- for (int i = 0; i < n; i++) {
- try {
- mProxies.getBroadcastItem(i).onServiceDisconnected(className);
- } catch (RemoteException e) {
- Log.e(TAG, "Unable to disconnect from proxy", e);
- }
- }
- } finally {
- mProxies.finishBroadcast();
- mInvokingProxyCallbacks = false;
- }
- }
-
- @Override
- public void binderDied() {
- if (DBG) {
- Log.w(TAG, "Profile service for profile: " + mClassName
- + " died.");
- }
- onServiceDisconnected(mClassName);
- // Trigger rebind
- Message msg = mHandler.obtainMessage(MESSAGE_BIND_PROFILE_SERVICE);
- msg.obj = this;
- mHandler.sendMessageDelayed(msg, TIMEOUT_BIND_MS);
- }
- }
-
private void sendBluetoothStateCallback(boolean isUp) {
try {
int n = mStateChangeCallbacks.beginBroadcast();
@@ -1257,28 +1052,6 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
}
break;
}
- case MESSAGE_ADD_PROXY_DELAYED:
- {
- ProfileServiceConnections psc = mProfileServices.get(
- new Integer(msg.arg1));
- if (psc == null) {
- break;
- }
- IBluetoothProfileServiceConnection proxy =
- (IBluetoothProfileServiceConnection) msg.obj;
- psc.addProxy(proxy);
- break;
- }
- case MESSAGE_BIND_PROFILE_SERVICE:
- {
- ProfileServiceConnections psc = (ProfileServiceConnections) msg.obj;
- removeMessages(MESSAGE_BIND_PROFILE_SERVICE, msg.obj);
- if (psc == null) {
- break;
- }
- psc.bindService();
- break;
- }
case MESSAGE_BLUETOOTH_SERVICE_CONNECTED:
{
if (DBG) Log.d(TAG,"MESSAGE_BLUETOOTH_SERVICE_CONNECTED: " + msg.arg1);
@@ -1482,20 +1255,19 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
mState = BluetoothAdapter.STATE_TURNING_ON;
}
- waitForOnOff(true, false);
+ waitForMonitoredOnOff(true, false);
if (mState == BluetoothAdapter.STATE_TURNING_ON) {
bluetoothStateChangeHandler(mState, BluetoothAdapter.STATE_ON);
}
- unbindAllBluetoothProfileServices();
// disable
handleDisable();
// Pbap service need receive STATE_TURNING_OFF intent to close
bluetoothStateChangeHandler(BluetoothAdapter.STATE_ON,
BluetoothAdapter.STATE_TURNING_OFF);
- waitForOnOff(false, true);
+ waitForMonitoredOnOff(false, true);
bluetoothStateChangeHandler(BluetoothAdapter.STATE_TURNING_OFF,
BluetoothAdapter.STATE_OFF);
@@ -1665,7 +1437,11 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
unbindAndFinish();
sendBleStateChanged(prevState, newState);
// Don't broadcast as it has already been broadcast before
- isStandardBroadcast = false;
+ if(!mIntentPending) {
+ isStandardBroadcast = false;
+ } else {
+ mIntentPending = false;
+ }
}
} else if (!intermediate_off) {
@@ -1694,6 +1470,13 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
// Broadcast as STATE_OFF
newState = BluetoothAdapter.STATE_OFF;
sendBrEdrDownCallback();
+ if(!isBleAppPresent()){
+ isStandardBroadcast = false;
+ mIntentPending = true;
+ } else {
+ mIntentPending = false;
+ isStandardBroadcast = true;
+ }
}
} else if (newState == BluetoothAdapter.STATE_ON) {
boolean isUp = (newState==BluetoothAdapter.STATE_ON);
@@ -1710,15 +1493,25 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
sendBleStateChanged(prevState, newState);
}
+ if( newState == BluetoothAdapter.STATE_TURNING_ON
+ && prevState == BluetoothAdapter.STATE_BLE_ON) {
+ mEnable = true;
+ }
+
if (isStandardBroadcast) {
if (prevState == BluetoothAdapter.STATE_BLE_ON) {
// Show prevState of BLE_ON as OFF to standard users
prevState = BluetoothAdapter.STATE_OFF;
}
+ else if (prevState == BluetoothAdapter.STATE_BLE_TURNING_OFF) {
+ // show prevState to TURNING_OFF
+ prevState = BluetoothAdapter.STATE_TURNING_OFF;
+ }
Intent intent = new Intent(BluetoothAdapter.ACTION_STATE_CHANGED);
intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, prevState);
intent.putExtra(BluetoothAdapter.EXTRA_STATE, newState);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+ intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
mContext.sendBroadcastAsUser(intent, UserHandle.ALL, BLUETOOTH_PERM);
}
}
@@ -1758,6 +1551,48 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
return false;
}
+ /**
+ * if on is true, wait for state become ON
+ * if off is true, wait for state become OFF
+ * if both on and off are false, wait for state not ON
+ */
+ private boolean waitForMonitoredOnOff(boolean on, boolean off) {
+ int i = 0;
+ while (i < 10) {
+ synchronized(mConnection) {
+ try {
+ if (mBluetooth == null) break;
+ if (on) {
+ if (mBluetooth.getState() == BluetoothAdapter.STATE_ON) return true;
+ if (mBluetooth.getState() == BluetoothAdapter.STATE_BLE_ON) {
+ bluetoothStateChangeHandler(BluetoothAdapter.STATE_BLE_TURNING_ON,
+ BluetoothAdapter.STATE_BLE_ON);
+ }
+ } else if (off) {
+ if (mBluetooth.getState() == BluetoothAdapter.STATE_OFF) return true;
+ if (mBluetooth.getState() == BluetoothAdapter.STATE_BLE_ON) {
+ bluetoothStateChangeHandler(BluetoothAdapter.STATE_TURNING_OFF,
+ BluetoothAdapter.STATE_BLE_ON);
+ }
+ } else {
+ if (mBluetooth.getState() != BluetoothAdapter.STATE_ON) return true;
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "getState()", e);
+ break;
+ }
+ }
+ if (on || off) {
+ SystemClock.sleep(800);
+ } else {
+ SystemClock.sleep(50);
+ }
+ i++;
+ }
+ Log.e(TAG,"waitForOnOff time out");
+ return false;
+ }
+
private void sendDisableMsg() {
mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_DISABLE));
}
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 327fb8a..bc356da 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -71,6 +71,7 @@ import android.net.ProxyInfo;
import android.net.RouteInfo;
import android.net.UidRange;
import android.net.Uri;
+import android.net.wifi.WifiDevice;
import android.os.Binder;
import android.os.Bundle;
import android.os.FileUtils;
@@ -132,6 +133,7 @@ import com.android.server.net.LockdownVpnTracker;
import com.google.android.collect.Lists;
import com.google.android.collect.Sets;
+import cyanogenmod.providers.CMSettings;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -641,13 +643,18 @@ public class ConnectivityService extends IConnectivityManager.Stub
mTrackerHandler = new NetworkStateTrackerHandler(mHandlerThread.getLooper());
// setup our unique device name
- if (TextUtils.isEmpty(SystemProperties.get("net.hostname"))) {
+ String hostname = CMSettings.Secure.getString(context.getContentResolver(),
+ CMSettings.Secure.DEVICE_HOSTNAME);
+ if (TextUtils.isEmpty(hostname) &&
+ TextUtils.isEmpty(SystemProperties.get("net.hostname"))) {
String id = Settings.Secure.getString(context.getContentResolver(),
Settings.Secure.ANDROID_ID);
if (id != null && id.length() > 0) {
String name = new String("android-").concat(id);
SystemProperties.set("net.hostname", name);
}
+ } else {
+ SystemProperties.set("net.hostname", hostname);
}
// read our default dns server ip
@@ -2579,6 +2586,14 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
}
+ public List<WifiDevice> getTetherConnectedSta() {
+ if (isTetheringSupported()) {
+ return mTethering.getTetherConnectedSta();
+ } else {
+ return null;
+ }
+ }
+
// javadoc from interface
public int tether(String iface) {
ConnectivityManager.enforceTetherChangePermission(mContext);
@@ -4503,7 +4518,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
if (reapUnvalidatedNetworks == ReapUnvalidatedNetworks.REAP) {
for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) {
- if (unneeded(nai)) {
+ if (unneeded(nai) && nai != newNetwork) {
if (DBG) log("Reaping " + nai.name());
teardownUnneededNetwork(nai);
}
diff --git a/services/core/java/com/android/server/DeviceIdleController.java b/services/core/java/com/android/server/DeviceIdleController.java
index b88658b..abe8f5c 100644
--- a/services/core/java/com/android/server/DeviceIdleController.java
+++ b/services/core/java/com/android/server/DeviceIdleController.java
@@ -750,6 +750,12 @@ public class DeviceIdleController extends SystemService
return isPowerSaveWhitelistExceptIdleAppInternal(name);
}
+ @Override public int getIdleStateDetailed() {
+ getContext().enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER,
+ null);
+ return mState;
+ }
+
@Override public boolean isPowerSaveWhitelistApp(String name) {
return isPowerSaveWhitelistAppInternal(name);
}
@@ -1202,7 +1208,7 @@ public class DeviceIdleController extends SystemService
void scheduleReportActiveLocked(String activeReason, int activeUid) {
Message msg = mHandler.obtainMessage(MSG_REPORT_ACTIVE, activeUid,
- mState == STATE_IDLE ? 1 : 0, activeReason);
+ ((mState == STATE_IDLE) || (mState == STATE_IDLE_MAINTENANCE)) ? 1 : 0, activeReason);
mHandler.sendMessage(msg);
}
diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java
index 6d07a57..6d6ca3c 100644
--- a/services/core/java/com/android/server/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/InputMethodManagerService.java
@@ -90,6 +90,7 @@ import android.os.SystemClock;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
+import android.provider.Settings.SettingNotFoundException;
import android.text.TextUtils;
import android.text.TextUtils.SimpleStringSplitter;
import android.text.style.SuggestionSpan;
@@ -139,6 +140,8 @@ import java.util.HashSet;
import java.util.List;
import java.util.Locale;
+import cyanogenmod.providers.CMSettings;
+
/**
* This class provides a system service that manages input methods.
*/
@@ -482,6 +485,14 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
Settings.Secure.SELECTED_INPUT_METHOD_SUBTYPE), false, this, userId);
resolver.registerContentObserver(Settings.Secure.getUriFor(
Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD), false, this, userId);
+ resolver.registerContentObserver(CMSettings.System.getUriFor(
+ CMSettings.System.STATUS_BAR_IME_SWITCHER),
+ false, new ContentObserver(mHandler) {
+ public void onChange(boolean selfChange) {
+ updateFromSettingsLocked(true);
+ }
+ }, userId);
+
mRegistered = true;
}
@@ -1090,8 +1101,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
mStatusBar = statusBar;
statusBar.setIconVisibility("ime", false);
updateSystemUiLocked(mCurToken, mImeWindowVis, mBackDisposition);
- mShowOngoingImeSwitcherForPhones = mRes.getBoolean(
- com.android.internal.R.bool.show_ongoing_ime_switcher);
if (mShowOngoingImeSwitcherForPhones) {
mWindowManagerService.setOnHardKeyboardStatusChangeListener(
mHardKeyboardListener);
@@ -1929,6 +1938,14 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
// There is no longer an input method set, so stop any current one.
unbindCurrentMethodLocked(true, false);
}
+ // code to disable the CM Phone IME switcher with config_show_cmIMESwitcher set = false
+ try {
+ mShowOngoingImeSwitcherForPhones = CMSettings.System.getInt(mContext.getContentResolver(),
+ CMSettings.System.STATUS_BAR_IME_SWITCHER) == 1;
+ } catch (CMSettings.CMSettingNotFoundException e) {
+ mShowOngoingImeSwitcherForPhones = mRes.getBoolean(
+ com.android.internal.R.bool.config_show_cmIMESwitcher);
+ }
// Here is not the perfect place to reset the switching controller. Ideally
// mSwitchingController and mSettings should be able to share the same state.
// TODO: Make sure that mSwitchingController and mSettings are sharing the
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index 468ead0..ebe8759 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -64,6 +64,7 @@ import android.location.Geofence;
import android.location.IGpsGeofenceHardware;
import android.location.IGpsMeasurementsListener;
import android.location.IGpsNavigationMessageListener;
+import android.location.GeoFenceParams;
import android.location.IGpsStatusListener;
import android.location.IGpsStatusProvider;
import android.location.ILocationListener;
@@ -90,6 +91,28 @@ import android.provider.Settings;
import android.util.Log;
import android.util.Slog;
+import com.android.internal.content.PackageMonitor;
+import com.android.internal.location.ProviderProperties;
+import com.android.internal.location.ProviderRequest;
+import com.android.internal.os.BackgroundThread;
+import com.android.server.location.FlpHardwareProvider;
+import com.android.server.location.FusedProxy;
+import com.android.server.location.GeocoderProxy;
+import com.android.server.location.GeofenceProxy;
+import com.android.server.location.GeofenceManager;
+import com.android.server.location.GeoFencerBase;
+import com.android.server.location.GeoFencerProxy;
+import com.android.server.location.GpsLocationProvider;
+import com.android.server.location.LocationBlacklist;
+import com.android.server.location.LocationFudger;
+import com.android.server.location.LocationProviderInterface;
+import com.android.server.location.LocationProviderProxy;
+import com.android.server.location.LocationRequestStatistics;
+import com.android.server.location.LocationRequestStatistics.PackageProviderKey;
+import com.android.server.location.LocationRequestStatistics.PackageStatistics;
+import com.android.server.location.MockProvider;
+import com.android.server.location.PassiveProvider;
+
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -154,6 +177,11 @@ public class LocationManagerService extends ILocationManager.Stub {
private LocationFudger mLocationFudger;
private GeofenceManager mGeofenceManager;
private PackageManager mPackageManager;
+ private String mComboNlpPackageName;
+ private String mComboNlpReadyMarker;
+ private String mComboNlpScreenMarker;
+ private String mGeoFencerPackageName;
+ private GeoFencerBase mGeoFencer;
private PowerManager mPowerManager;
private UserManager mUserManager;
private GeocoderProxy mGeocodeProvider;
@@ -509,6 +537,15 @@ public class LocationManagerService extends ILocationManager.Stub {
Slog.e(TAG, "no geocoder provider found");
}
+ mGeoFencerPackageName = resources.getString(
+ com.android.internal.R.string.config_geofenceProvider);
+ if (mGeoFencerPackageName != null &&
+ mPackageManager.resolveService(new Intent(mGeoFencerPackageName), 0) != null){
+ mGeoFencer = GeoFencerProxy.getGeoFencerProxy(mContext, mGeoFencerPackageName);
+ } else {
+ mGeoFencer = null;
+ }
+
// bind to fused hardware provider if supported
// in devices without support, requesting an instance of FlpHardwareProvider will raise an
// exception, so make sure we only do that when supported
@@ -562,6 +599,13 @@ public class LocationManagerService extends ILocationManager.Stub {
Slog.e(TAG, "Unable to bind ActivityRecognitionProxy.");
}
+ mComboNlpPackageName = resources.getString(
+ com.android.internal.R.string.config_comboNetworkLocationProvider);
+ if (mComboNlpPackageName != null) {
+ mComboNlpReadyMarker = mComboNlpPackageName + ".nlp:ready";
+ mComboNlpScreenMarker = mComboNlpPackageName + ".nlp:screen";
+ }
+
String[] testProviderStrings = resources.getStringArray(
com.android.internal.R.array.config_testLocationProviders);
for (String testProviderString : testProviderStrings) {
@@ -1614,9 +1658,11 @@ public class LocationManagerService extends ILocationManager.Stub {
checkLocationAccess(pid, uid, packageName, allowedResolutionLevel);
synchronized (mLock) {
- Receiver recevier = checkListenerOrIntentLocked(listener, intent, pid, uid,
+ Receiver receiver = checkListenerOrIntentLocked(listener, intent, pid, uid,
packageName, workSource, hideFromAppOps);
- requestLocationUpdatesLocked(sanitizedRequest, recevier, pid, uid, packageName);
+ if (receiver != null) {
+ requestLocationUpdatesLocked(sanitizedRequest, receiver, pid, uid, packageName);
+ }
}
} finally {
Binder.restoreCallingIdentity(identity);
@@ -1675,7 +1721,9 @@ public class LocationManagerService extends ILocationManager.Stub {
// providers may use public location API's, need to clear identity
long identity = Binder.clearCallingIdentity();
try {
- removeUpdatesLocked(receiver);
+ if (receiver != null) {
+ removeUpdatesLocked(receiver);
+ }
} finally {
Binder.restoreCallingIdentity(identity);
}
@@ -1814,8 +1862,20 @@ public class LocationManagerService extends ILocationManager.Stub {
}
long identity = Binder.clearCallingIdentity();
try {
- mGeofenceManager.addFence(sanitizedRequest, geofence, intent, allowedResolutionLevel,
- uid, packageName);
+ if (mGeoFencer != null) {
+ long expiration;
+ if (sanitizedRequest.getExpireAt() == Long.MAX_VALUE) {
+ expiration = -1; // -1 means forever
+ } else {
+ expiration = sanitizedRequest.getExpireAt() - SystemClock.elapsedRealtime();
+ }
+ mGeoFencer.add(new GeoFenceParams(uid, geofence.getLatitude(),
+ geofence.getLongitude(), geofence.getRadius(),
+ expiration, intent, packageName));
+ } else {
+ mGeofenceManager.addFence(sanitizedRequest, geofence, intent,
+ allowedResolutionLevel, uid, packageName);
+ }
} finally {
Binder.restoreCallingIdentity(identity);
}
@@ -1831,7 +1891,11 @@ public class LocationManagerService extends ILocationManager.Stub {
// geo-fence manager uses the public location API, need to clear identity
long identity = Binder.clearCallingIdentity();
try {
- mGeofenceManager.removeFence(geofence, intent);
+ if (mGeoFencer != null) {
+ mGeoFencer.remove(intent);
+ } else {
+ mGeofenceManager.removeFence(geofence, intent);
+ }
} finally {
Binder.restoreCallingIdentity(identity);
}
@@ -2332,6 +2396,70 @@ public class LocationManagerService extends ILocationManager.Stub {
synchronized (mLock) {
return mMockProviders.containsKey(provider);
}
+
+ }
+
+ private Location screenLocationLocked(Location location, String provider) {
+ if (isMockProvider(LocationManager.NETWORK_PROVIDER)) {
+ return location;
+ }
+ LocationProviderProxy providerProxy =
+ (LocationProviderProxy)mProvidersByName.get(LocationManager.NETWORK_PROVIDER);
+ if (mComboNlpPackageName == null || providerProxy == null ||
+ false == provider.equals(LocationManager.NETWORK_PROVIDER) ||
+ isMockProvider(LocationManager.NETWORK_PROVIDER)) {
+ return location;
+ }
+
+ String connectedNlpPackage = providerProxy.getConnectedPackageName();
+ if (connectedNlpPackage == null || !connectedNlpPackage.equals(mComboNlpPackageName)) {
+ return location;
+ }
+
+ Bundle extras = location.getExtras();
+ boolean isBeingScreened = false;
+ if (extras == null) {
+ extras = new Bundle();
+ }
+
+ if (!extras.containsKey(mComboNlpReadyMarker)) {
+ // see if Combo Nlp is a passive listener
+ ArrayList<UpdateRecord> records =
+ mRecordsByProvider.get(LocationManager.PASSIVE_PROVIDER);
+ if (records != null) {
+ for (UpdateRecord r : records) {
+ if (r.mReceiver.mPackageName.equals(mComboNlpPackageName)) {
+ if (!isBeingScreened) {
+ isBeingScreened = true;
+ extras.putBoolean(mComboNlpScreenMarker, true);
+ }
+ // send location to Combo Nlp for screening
+ if (!r.mReceiver.callLocationChangedLocked(location)) {
+ Slog.w(TAG, "RemoteException calling onLocationChanged on "
+ + r.mReceiver);
+ } else {
+ if (D) {
+ Log.d(TAG, "Sending location for screening");
+ }
+ }
+ }
+ }
+ }
+ if (isBeingScreened) {
+ return null;
+ }
+ if (D) {
+ Log.d(TAG, "Not screening locations");
+ }
+ } else {
+ if (D) {
+ Log.d(TAG, "This location is marked as ready for broadcast");
+ }
+ // clear the ready marker
+ extras.remove(mComboNlpReadyMarker);
+ }
+
+ return location;
}
private void handleLocationChanged(Location location, boolean passive) {
@@ -2350,6 +2478,10 @@ public class LocationManagerService extends ILocationManager.Stub {
synchronized (mLock) {
if (isAllowedByCurrentUserSettingsLocked(provider)) {
if (!passive) {
+ location = screenLocationLocked(location, provider);
+ if (location == null) {
+ return;
+ }
// notify passive provider of the new location
mPassiveProvider.updateLocation(myLocation);
}
@@ -2655,6 +2787,10 @@ public class LocationManagerService extends ILocationManager.Stub {
mGeofenceManager.dump(pw);
+ if (mGeoFencer != null) {
+ mGeoFencer.dump(pw, "");
+ }
+
if (mEnabledProviders.size() > 0) {
pw.println(" Enabled Providers:");
for (String i : mEnabledProviders) {
diff --git a/services/core/java/com/android/server/LockSettingsService.java b/services/core/java/com/android/server/LockSettingsService.java
index f1d7da4..1dbb054 100644
--- a/services/core/java/com/android/server/LockSettingsService.java
+++ b/services/core/java/com/android/server/LockSettingsService.java
@@ -58,6 +58,9 @@ import com.android.server.LockSettingsStorage.CredentialHash;
import java.util.Arrays;
import java.util.List;
+import java.util.Timer;
+import java.util.TimerTask;
+
/**
* Keeps the lock pattern/password data and related settings for each user.
* Used by LockPatternUtils. Needs to be a service because Settings app also needs
@@ -70,6 +73,8 @@ public class LockSettingsService extends ILockSettings.Stub {
private static final String TAG = "LockSettingsService";
+ private static final String DEFAULT_PASSWORD = "default_password";
+
private final Context mContext;
private final LockSettingsStorage mStorage;
@@ -78,6 +83,7 @@ public class LockSettingsService extends ILockSettings.Stub {
private LockPatternUtils mLockPatternUtils;
private boolean mFirstCallToVold;
private IGateKeeperService mGateKeeperService;
+ private static String mSavePassword = DEFAULT_PASSWORD;
private interface CredentialUtil {
void setCredential(String credential, String savedCredential, int userId)
@@ -367,6 +373,25 @@ public class LockSettingsService extends ILockSettings.Stub {
return mStorage.hasPattern(userId);
}
+ public void retainPassword(String password) {
+ if (LockPatternUtils.isDeviceEncryptionEnabled()) {
+ if (password != null)
+ mSavePassword = password;
+ else
+ mSavePassword = DEFAULT_PASSWORD;
+ }
+ }
+
+ public void sanitizePassword() {
+ if (LockPatternUtils.isDeviceEncryptionEnabled()) {
+ mSavePassword = DEFAULT_PASSWORD;
+ }
+ }
+
+ public String getPassword() {
+ return mSavePassword;
+ }
+
private void setKeystorePassword(String password, int userHandle) {
final UserManager um = (UserManager) mContext.getSystemService(USER_SERVICE);
final KeyStore ks = KeyStore.getInstance();
@@ -553,6 +578,8 @@ public class LockSettingsService extends ILockSettings.Stub {
&& shouldReEnrollBaseZero) {
setLockPattern(pattern, patternToVerify, userId);
}
+ if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK)
+ retainPassword(pattern);
return response;
@@ -561,7 +588,10 @@ public class LockSettingsService extends ILockSettings.Stub {
@Override
public VerifyCredentialResponse checkPassword(String password, int userId)
throws RemoteException {
- return doVerifyPassword(password, false, 0, userId);
+ VerifyCredentialResponse response = doVerifyPassword(password, false, 0, userId);
+ if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK)
+ retainPassword(password);
+ return response;
}
@Override
diff --git a/services/core/java/com/android/server/MasterClearReceiver.java b/services/core/java/com/android/server/MasterClearReceiver.java
index 1653db9..23556c0 100644
--- a/services/core/java/com/android/server/MasterClearReceiver.java
+++ b/services/core/java/com/android/server/MasterClearReceiver.java
@@ -34,6 +34,9 @@ import java.io.IOException;
public class MasterClearReceiver extends BroadcastReceiver {
private static final String TAG = "MasterClear";
+ /* {@hide} */
+ public static final String EXTRA_WIPE_MEDIA = "wipe_media";
+
@Override
public void onReceive(final Context context, final Intent intent) {
if (intent.getAction().equals(Intent.ACTION_REMOTE_INTENT)) {
@@ -54,7 +57,8 @@ public class MasterClearReceiver extends BroadcastReceiver {
@Override
public void run() {
try {
- RecoverySystem.rebootWipeUserData(context, shutdown, reason);
+ boolean wipeMedia = intent.getBooleanExtra(EXTRA_WIPE_MEDIA, false);
+ RecoverySystem.rebootWipeUserData(context, shutdown, reason, wipeMedia);
Log.wtf(TAG, "Still running after master clear?!");
} catch (IOException e) {
Slog.e(TAG, "Can't perform master clear/factory reset", e);
diff --git a/services/core/java/com/android/server/MountService.java b/services/core/java/com/android/server/MountService.java
index 5e67414..4847de3 100644
--- a/services/core/java/com/android/server/MountService.java
+++ b/services/core/java/com/android/server/MountService.java
@@ -1093,8 +1093,10 @@ class MountService extends IMountService.Stub
final long destroy = Long.parseLong(cooked[6]);
final DropBoxManager dropBox = mContext.getSystemService(DropBoxManager.class);
- dropBox.addText(TAG_STORAGE_BENCHMARK, scrubPath(path)
- + " " + ident + " " + create + " " + run + " " + destroy);
+ if (dropBox != null) {
+ dropBox.addText(TAG_STORAGE_BENCHMARK, scrubPath(path)
+ + " " + ident + " " + create + " " + run + " " + destroy);
+ }
final VolumeRecord rec = findRecordForPath(path);
if (rec != null) {
@@ -1111,8 +1113,10 @@ class MountService extends IMountService.Stub
final long time = Long.parseLong(cooked[3]);
final DropBoxManager dropBox = mContext.getSystemService(DropBoxManager.class);
- dropBox.addText(TAG_STORAGE_TRIM, scrubPath(path)
- + " " + bytes + " " + time);
+ if (dropBox != null) {
+ dropBox.addText(TAG_STORAGE_TRIM, scrubPath(path)
+ + " " + bytes + " " + time);
+ }
final VolumeRecord rec = findRecordForPath(path);
if (rec != null) {
@@ -2400,7 +2404,7 @@ class MountService extends IMountService.Stub
}
}
- public int encryptStorage(int type, String password) {
+ private int encryptStorageExtended(int type, String password, boolean wipe) {
if (TextUtils.isEmpty(password) && type != StorageManager.CRYPT_TYPE_DEFAULT) {
throw new IllegalArgumentException("password cannot be empty");
}
@@ -2430,6 +2434,22 @@ class MountService extends IMountService.Stub
return 0;
}
+ /** Encrypt Storage given a password.
+ * @param type The password type.
+ * @param password The password to be used in encryption.
+ */
+ public int encryptStorage(int type, String password) {
+ return encryptStorageExtended(type, password, false);
+ }
+
+ /** Encrypt Storage given a password after wiping it.
+ * @param type The password type.
+ * @param password The password to be used in encryption.
+ */
+ public int encryptWipeStorage(int type, String password) {
+ return encryptStorageExtended(type, password, true);
+ }
+
/** Set the password for encrypting the master key.
* @param type One of the CRYPTO_TYPE_XXX consts defined in StorageManager.
* @param password The password to set.
@@ -2444,9 +2464,13 @@ class MountService extends IMountService.Stub
Slog.i(TAG, "changing encryption password...");
}
+ LockSettingsService lockSettings = new LockSettingsService(mContext);
+ String currentPassword = lockSettings.getPassword();
+
try {
NativeDaemonEvent event = mCryptConnector.execute("cryptfs", "changepw", CRYPTO_TYPES[type],
- new SensitiveArg(password));
+ new SensitiveArg(currentPassword), new SensitiveArg(password));
+ lockSettings.sanitizePassword();
return Integer.parseInt(event.getMessage());
} catch (NativeDaemonConnectorException e) {
// Encryption failed
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index ba9279c..fd42b0a 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -170,6 +170,7 @@ public class NetworkManagementService extends INetworkManagementService.Stub
public static final int InterfaceDnsServerInfo = 615;
public static final int RouteChange = 616;
public static final int StrictCleartext = 617;
+ public static final int InterfaceMessage = 618;
}
static final int DAEMON_MSG_MOBILE_CONN_REAL_TIME_INFO = 1;
@@ -520,6 +521,21 @@ public class NetworkManagementService extends INetworkManagementService.Stub
}
/**
+ * Notify our observers of a change in the data activity state of the interface
+ */
+ private void notifyInterfaceMessage(String message) {
+ final int length = mObservers.beginBroadcast();
+ for (int i = 0; i < length; i++) {
+ try {
+ mObservers.getBroadcastItem(i).interfaceMessageRecevied(message);
+ } catch (RemoteException e) {
+ } catch (RuntimeException e) {
+ }
+ }
+ mObservers.finishBroadcast();
+ }
+
+ /**
* Prepare native daemon once connected, enabling modules and pushing any
* existing in-memory rules.
*/
@@ -789,6 +805,22 @@ public class NetworkManagementService extends INetworkManagementService.Stub
}
throw new IllegalStateException(errorMessage);
// break;
+ case NetdResponseCode.InterfaceMessage:
+ /*
+ * An message arrived in network interface.
+ * Format: "NNN IfaceMessage <3>AP-STA-CONNECTED 00:08:22:64:9d:84
+ */
+ if (cooked.length < 3 || !cooked[1].equals("IfaceMessage")) {
+ throw new IllegalStateException(errorMessage);
+ }
+ Slog.d(TAG, "onEvent: "+ raw);
+ if(cooked[4] != null) {
+ notifyInterfaceMessage(cooked[3] + " " + cooked[4]);
+ } else {
+ notifyInterfaceMessage(cooked[3]);
+ }
+ return true;
+ // break;
case NetdResponseCode.InterfaceClassActivity:
/*
* An network interface class state changed (active/idle)
@@ -806,7 +838,7 @@ public class NetworkManagementService extends INetworkManagementService.Stub
timestampNanos = SystemClock.elapsedRealtimeNanos();
}
boolean isActive = cooked[2].equals("active");
- notifyInterfaceClassActivity(Integer.parseInt(cooked[3]),
+ notifyInterfaceClassActivity(cooked[3] == null ? 0 : Integer.parseInt(cooked[3]),
isActive ? DataConnectionRealTimeInfo.DC_POWER_STATE_HIGH
: DataConnectionRealTimeInfo.DC_POWER_STATE_LOW, timestampNanos, false);
return true;
diff --git a/services/core/java/com/android/server/PermissionDialog.java b/services/core/java/com/android/server/PermissionDialog.java
new file mode 100644
index 0000000..0f337b8
--- /dev/null
+++ b/services/core/java/com/android/server/PermissionDialog.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ *
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+import android.app.AppOpsManager;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.res.Resources;
+import android.os.Handler;
+import android.os.Message;
+import android.view.View;
+import android.view.WindowManager;
+import android.widget.CheckBox;
+import android.widget.TextView;
+
+public class PermissionDialog extends BasePermissionDialog {
+ private final static String TAG = "PermissionDialog";
+
+ private final AppOpsService mService;
+ private final String mPackageName;
+ private final int mCode;
+ private View mView;
+ private CheckBox mChoice;
+ private int mUid;
+ final CharSequence[] mOpLabels;
+ private Context mContext;
+
+ // Event 'what' codes
+ static final int ACTION_ALLOWED = 0x2;
+ static final int ACTION_IGNORED = 0x4;
+ static final int ACTION_IGNORED_TIMEOUT = 0x8;
+
+ // 15s timeout, then we automatically dismiss the permission
+ // dialog. Otherwise, it may cause watchdog timeout sometimes.
+ static final long DISMISS_TIMEOUT = 1000 * 15 * 1;
+
+ public PermissionDialog(Context context, AppOpsService service,
+ int code, int uid, String packageName) {
+ super(context);
+
+ mContext = context;
+ Resources res = context.getResources();
+
+ mService = service;
+ mCode = code;
+ mPackageName = packageName;
+ mUid = uid;
+ mOpLabels = res.getTextArray(
+ com.android.internal.R.array.app_ops_labels);
+
+ setCancelable(false);
+
+ setButton(DialogInterface.BUTTON_POSITIVE,
+ res.getString(com.android.internal.R.string.allow), mHandler.obtainMessage(ACTION_ALLOWED));
+
+ setButton(DialogInterface.BUTTON_NEGATIVE,
+ res.getString(com.android.internal.R.string.deny), mHandler.obtainMessage(ACTION_IGNORED));
+
+ setTitle(res.getString(com.android.internal.R.string.privacy_guard_dialog_title));
+ WindowManager.LayoutParams attrs = getWindow().getAttributes();
+ attrs.setTitle("Permission info: " + getAppName(mPackageName));
+ attrs.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_SYSTEM_ERROR
+ | WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
+ getWindow().setAttributes(attrs);
+
+ mView = getLayoutInflater().inflate(
+ com.android.internal.R.layout.permission_confirmation_dialog,
+ null);
+ TextView tv = (TextView) mView.findViewById(
+ com.android.internal.R.id.permission_text);
+ mChoice = (CheckBox) mView.findViewById(
+ com.android.internal.R.id.permission_remember_choice_checkbox);
+ String name = getAppName(mPackageName);
+ if(name == null)
+ name = mPackageName;
+ tv.setText(mContext.getString(com.android.internal.R.string.privacy_guard_dialog_summary,
+ name, mOpLabels[mCode]));
+ setView(mView);
+
+ // After the timeout, pretend the user clicked the quit button
+ mHandler.sendMessageDelayed(
+ mHandler.obtainMessage(ACTION_IGNORED_TIMEOUT), DISMISS_TIMEOUT);
+ }
+
+ private String getAppName(String packageName) {
+ ApplicationInfo appInfo = null;
+ PackageManager pm = mContext.getPackageManager();
+ try {
+ appInfo = pm.getApplicationInfo(packageName,
+ PackageManager.GET_DISABLED_COMPONENTS
+ | PackageManager.GET_UNINSTALLED_PACKAGES);
+ } catch (final NameNotFoundException e) {
+ return null;
+ }
+ if(appInfo != null) {
+ return (String)pm.getApplicationLabel(appInfo);
+ }
+ return null;
+ }
+
+ private final Handler mHandler = new Handler() {
+ public void handleMessage(Message msg) {
+ int mode;
+ boolean remember = mChoice.isChecked();
+ switch(msg.what) {
+ case ACTION_ALLOWED:
+ mode = AppOpsManager.MODE_ALLOWED;
+ break;
+ case ACTION_IGNORED:
+ mode = AppOpsManager.MODE_IGNORED;
+ break;
+ default:
+ mode = AppOpsManager.MODE_IGNORED;
+ remember = false;
+ }
+ mService.notifyOperation(mCode, mUid, mPackageName, mode,
+ remember);
+ dismiss();
+ }
+ };
+}
diff --git a/services/core/java/com/android/server/PermissionDialogReqQueue.java b/services/core/java/com/android/server/PermissionDialogReqQueue.java
new file mode 100644
index 0000000..ee94427
--- /dev/null
+++ b/services/core/java/com/android/server/PermissionDialogReqQueue.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ *
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class PermissionDialogReqQueue {
+ public PermissionDialog getDialog() {
+ return mDialog;
+ }
+
+ public void setDialog(PermissionDialog mDialog) {
+ this.mDialog = mDialog;
+ }
+
+ public final static class PermissionDialogReq {
+ public void set(int res) {
+ synchronized (this) {
+ mHasResult = true;
+ mResult = res;
+ notifyAll();
+ }
+ }
+
+ public int get() {
+ synchronized (this) {
+ while (!mHasResult) {
+ try {
+ wait();
+ } catch (InterruptedException e) {
+ }
+ }
+ }
+ return mResult;
+ }
+
+ boolean mHasResult = false;
+ int mResult;
+ }
+
+ private PermissionDialog mDialog;
+ private List<PermissionDialogReq> resultList;
+
+ public PermissionDialogReqQueue() {
+ mDialog = null;
+ resultList = new ArrayList<PermissionDialogReq>();
+ }
+
+ public void register(PermissionDialogReq res) {
+ synchronized (this) {
+ resultList.add(res);
+ }
+ }
+
+ public void notifyAll(int mode) {
+ synchronized (this) {
+ while (resultList.size() != 0) {
+ PermissionDialogReq res = resultList.get(0);
+ res.set(mode);
+ resultList.remove(0);
+ }
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/SystemConfig.java b/services/core/java/com/android/server/SystemConfig.java
index cd61347..2d94370 100644
--- a/services/core/java/com/android/server/SystemConfig.java
+++ b/services/core/java/com/android/server/SystemConfig.java
@@ -18,6 +18,7 @@ package com.android.server;
import android.app.ActivityManager;
import android.content.pm.FeatureInfo;
+import android.content.pm.Signature;
import android.os.*;
import android.os.Process;
import android.util.ArrayMap;
@@ -99,6 +100,9 @@ public class SystemConfig {
// URL-handling state upon factory reset.
final ArraySet<String> mLinkedApps = new ArraySet<>();
+ final ArrayMap<Signature, ArraySet<String>> mSignatureAllowances
+ = new ArrayMap<Signature, ArraySet<String>>();
+
public static SystemConfig getInstance() {
synchronized (SystemConfig.class) {
if (sInstance == null) {
@@ -144,6 +148,10 @@ public class SystemConfig {
return mLinkedApps;
}
+ public ArrayMap<Signature, ArraySet<String>> getSignatureAllowances() {
+ return mSignatureAllowances;
+ }
+
SystemConfig() {
// Read configuration from system
readPermissions(Environment.buildPath(
@@ -290,6 +298,43 @@ public class SystemConfig {
perms.add(perm);
XmlUtils.skipCurrentTag(parser);
+ } else if ("allow-permission".equals(name)) {
+ String perm = parser.getAttributeValue(null, "name");
+ if (perm == null) {
+ Slog.w(TAG,
+ "<allow-permission> without name at "
+ + parser.getPositionDescription());
+ XmlUtils.skipCurrentTag(parser);
+ continue;
+ }
+ String signature = parser.getAttributeValue(null, "signature");
+ if (signature == null) {
+ Slog.w(TAG,
+ "<allow-permission> without signature at "
+ + parser.getPositionDescription());
+ XmlUtils.skipCurrentTag(parser);
+ continue;
+ }
+ Signature sig = null;
+ try {
+ sig = new Signature(signature);
+ } catch (IllegalArgumentException e) {
+ // sig will be null so we will log it below
+ }
+ if (sig != null) {
+ ArraySet<String> perms = mSignatureAllowances.get(sig);
+ if (perms == null) {
+ perms = new ArraySet<String>();
+ mSignatureAllowances.put(sig, perms);
+ }
+ perms.add(perm);
+ } else {
+ Slog.w(TAG,
+ "<allow-permission> with bad signature at "
+ + parser.getPositionDescription());
+ }
+ XmlUtils.skipCurrentTag(parser);
+
} else if ("library".equals(name) && !onlyFeatures) {
String lname = parser.getAttributeValue(null, "name");
String lfile = parser.getAttributeValue(null, "file");
diff --git a/services/core/java/com/android/server/ThemeService.java b/services/core/java/com/android/server/ThemeService.java
new file mode 100644
index 0000000..dd85ad9
--- /dev/null
+++ b/services/core/java/com/android/server/ThemeService.java
@@ -0,0 +1,1254 @@
+/*
+ * Copyright (C) 2014 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 com.android.server;
+
+import android.Manifest;
+import android.app.ActivityManager;
+import android.app.ActivityManagerNative;
+import android.app.IActivityManager;
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.WallpaperManager;
+import android.content.BroadcastReceiver;
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ThemeUtils;
+import android.content.res.AssetManager;
+import android.content.res.Configuration;
+import android.content.res.IThemeProcessingListener;
+import android.content.res.ThemeChangeRequest;
+import android.content.res.ThemeConfig;
+import android.content.res.IThemeChangeListener;
+import android.content.res.IThemeService;
+import android.graphics.Bitmap;
+import android.media.RingtoneManager;
+import android.os.Binder;
+import android.os.Environment;
+import android.os.FileUtils;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.os.Message;
+import android.os.Process;
+import android.os.RemoteCallbackList;
+import android.os.RemoteException;
+import android.os.SystemProperties;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.provider.Settings.SettingNotFoundException;
+import android.provider.ThemesContract;
+import android.provider.ThemesContract.MixnMatchColumns;
+import android.provider.ThemesContract.ThemesColumns;
+import android.text.TextUtils;
+import android.util.Log;
+
+import com.android.internal.R;
+import com.android.internal.util.cm.ImageUtils;
+import cyanogenmod.providers.CMSettings;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+
+import static android.content.pm.ThemeUtils.SYSTEM_THEME_PATH;
+import static android.content.pm.ThemeUtils.THEME_BOOTANIMATION_PATH;
+import static android.content.res.ThemeConfig.SYSTEM_DEFAULT;
+
+import java.util.List;
+
+/**
+ * {@hide}
+ */
+public class ThemeService extends IThemeService.Stub {
+ private static final String TAG = ThemeService.class.getName();
+
+ private static final boolean DEBUG = false;
+
+ private static final String GOOGLE_SETUPWIZARD_PACKAGE = "com.google.android.setupwizard";
+ private static final String CM_SETUPWIZARD_PACKAGE = "com.cyanogenmod.account";
+
+ private static final long MAX_ICON_CACHE_SIZE = 33554432L; // 32MB
+ private static final long PURGED_ICON_CACHE_SIZE = 25165824L; // 24 MB
+
+ // Defines a min and max compatible api level for themes on this system.
+ private static final int MIN_COMPATIBLE_VERSION = 21;
+
+ private HandlerThread mWorker;
+ private ThemeWorkerHandler mHandler;
+ private ResourceProcessingHandler mResourceProcessingHandler;
+ private Context mContext;
+ private PackageManager mPM;
+ private int mProgress;
+ private boolean mWallpaperChangedByUs = false;
+ private long mIconCacheSize = 0L;
+ private int mCurrentUserId = UserHandle.USER_OWNER;
+
+ private boolean mIsThemeApplying = false;
+
+ private final RemoteCallbackList<IThemeChangeListener> mClients =
+ new RemoteCallbackList<IThemeChangeListener>();
+
+ private final RemoteCallbackList<IThemeProcessingListener> mProcessingListeners =
+ new RemoteCallbackList<IThemeProcessingListener>();
+
+ final private ArrayList<String> mThemesToProcessQueue = new ArrayList<String>(0);
+
+ private class ThemeWorkerHandler extends Handler {
+ private static final int MESSAGE_CHANGE_THEME = 1;
+ private static final int MESSAGE_APPLY_DEFAULT_THEME = 2;
+ private static final int MESSAGE_REBUILD_RESOURCE_CACHE = 3;
+
+ public ThemeWorkerHandler(Looper looper) {
+ super(looper);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MESSAGE_CHANGE_THEME:
+ final ThemeChangeRequest request = (ThemeChangeRequest) msg.obj;
+ doApplyTheme(request, msg.arg1 == 1);
+ break;
+ case MESSAGE_APPLY_DEFAULT_THEME:
+ doApplyDefaultTheme();
+ break;
+ case MESSAGE_REBUILD_RESOURCE_CACHE:
+ doRebuildResourceCache();
+ break;
+ default:
+ Log.w(TAG, "Unknown message " + msg.what);
+ break;
+ }
+ }
+ }
+
+ private class ResourceProcessingHandler extends Handler {
+ private static final int MESSAGE_QUEUE_THEME_FOR_PROCESSING = 3;
+ private static final int MESSAGE_DEQUEUE_AND_PROCESS_THEME = 4;
+
+ public ResourceProcessingHandler(Looper looper) {
+ super(looper);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MESSAGE_QUEUE_THEME_FOR_PROCESSING:
+ String pkgName = (String) msg.obj;
+ synchronized (mThemesToProcessQueue) {
+ if (!mThemesToProcessQueue.contains(pkgName)) {
+ if (DEBUG) Log.d(TAG, "Adding " + pkgName + " for processing");
+ mThemesToProcessQueue.add(pkgName);
+ if (mThemesToProcessQueue.size() == 1) {
+ this.sendEmptyMessage(MESSAGE_DEQUEUE_AND_PROCESS_THEME);
+ }
+ }
+ }
+ break;
+ case MESSAGE_DEQUEUE_AND_PROCESS_THEME:
+ synchronized (mThemesToProcessQueue) {
+ pkgName = mThemesToProcessQueue.get(0);
+ }
+ if (pkgName != null) {
+ if (DEBUG) Log.d(TAG, "Processing " + pkgName);
+ String name;
+ try {
+ PackageInfo pi = mPM.getPackageInfo(pkgName, 0);
+ name = getThemeName(pi);
+ } catch (PackageManager.NameNotFoundException e) {
+ name = null;
+ }
+
+ int result = mPM.processThemeResources(pkgName);
+ if (result < 0) {
+ postFailedThemeInstallNotification(name != null ? name : pkgName);
+ }
+ sendThemeResourcesCachedBroadcast(pkgName, result);
+
+ synchronized (mThemesToProcessQueue) {
+ mThemesToProcessQueue.remove(0);
+ if (mThemesToProcessQueue.size() > 0 &&
+ !hasMessages(MESSAGE_DEQUEUE_AND_PROCESS_THEME)) {
+ this.sendEmptyMessage(MESSAGE_DEQUEUE_AND_PROCESS_THEME);
+ }
+ }
+ postFinishedProcessing(pkgName);
+ }
+ break;
+ default:
+ Log.w(TAG, "Unknown message " + msg.what);
+ break;
+ }
+ }
+ }
+
+ public ThemeService(Context context) {
+ super();
+ mContext = context;
+ mWorker = new HandlerThread("ThemeServiceWorker", Process.THREAD_PRIORITY_BACKGROUND);
+ mWorker.start();
+ mHandler = new ThemeWorkerHandler(mWorker.getLooper());
+ Log.i(TAG, "Spawned worker thread");
+
+ HandlerThread processingThread = new HandlerThread("ResourceProcessingThread",
+ Process.THREAD_PRIORITY_BACKGROUND);
+ processingThread.start();
+ mResourceProcessingHandler =
+ new ResourceProcessingHandler(processingThread.getLooper());
+
+ // create the theme directory if it does not exist
+ ThemeUtils.createThemeDirIfNotExists();
+ ThemeUtils.createFontDirIfNotExists();
+ ThemeUtils.createAlarmDirIfNotExists();
+ ThemeUtils.createNotificationDirIfNotExists();
+ ThemeUtils.createRingtoneDirIfNotExists();
+ ThemeUtils.createIconCacheDirIfNotExists();
+ }
+
+ public void systemRunning() {
+ // listen for wallpaper changes
+ IntentFilter filter = new IntentFilter(Intent.ACTION_WALLPAPER_CHANGED);
+ mContext.registerReceiver(mWallpaperChangeReceiver, filter);
+
+ filter = new IntentFilter(Intent.ACTION_USER_SWITCHED);
+ mContext.registerReceiver(mUserChangeReceiver, filter);
+
+ mPM = mContext.getPackageManager();
+
+ processInstalledThemes();
+
+ if (!isThemeApiUpToDate()) {
+ Log.d(TAG, "The system has been upgraded to a theme new api, " +
+ "checking if currently set theme is compatible");
+ removeObsoleteThemeOverlayIfExists();
+ updateThemeApi();
+ }
+ }
+
+ private void removeObsoleteThemeOverlayIfExists() {
+ // Get the current overlay theme so we can see it it's overlay should be unapplied
+ final IActivityManager am = ActivityManagerNative.getDefault();
+ ThemeConfig config = null;
+ try {
+ if (am != null) {
+ config = am.getConfiguration().themeConfig;
+ } else {
+ Log.e(TAG, "ActivityManager getDefault() " +
+ "returned null, cannot remove obsolete theme");
+ }
+ } catch(RemoteException e) {
+ Log.e(TAG, "Failed to get the theme config ", e);
+ }
+ if (config == null) return; // No need to unapply a theme if one isn't set
+
+ // Populate the currentTheme map for the components we care about, we'll look
+ // at the compatibility of each pkg below.
+ HashMap<String, String> currentThemeMap = new HashMap<String, String>();
+ currentThemeMap.put(ThemesColumns.MODIFIES_STATUS_BAR, config.getOverlayForStatusBar());
+ currentThemeMap.put(ThemesColumns.MODIFIES_NAVIGATION_BAR,
+ config.getOverlayForNavBar());
+ currentThemeMap.put(ThemesColumns.MODIFIES_OVERLAYS, config.getOverlayPkgName());
+
+ // Look at each component's theme (that we care about at least) and check compatibility
+ // of the pkg with the system. If it is not compatible then we will add it to a theme
+ // change request.
+ Map<String, String> defaults = ThemeUtils.getDefaultComponents(mContext);
+ ThemeChangeRequest.Builder builder = new ThemeChangeRequest.Builder();
+ for(Map.Entry<String, String> entry : currentThemeMap.entrySet()) {
+ String component = entry.getKey();
+ String pkgName = entry.getValue();
+ String defaultPkg = defaults.get(component);
+
+ // Check that the default overlay theme is not currently set
+ if (defaultPkg.equals(pkgName)) {
+ Log.d(TAG, "Current overlay theme is same as default. " +
+ "Not doing anything for " + component);
+ continue;
+ }
+
+ // No need to unapply a system theme since it is always compatible
+ if (ThemeConfig.SYSTEM_DEFAULT.equals(pkgName)) {
+ Log.d(TAG, "Current overlay theme for "
+ + component + " was system. no need to unapply");
+ continue;
+ }
+
+ if (!isThemeCompatibleWithUpgradedApi(pkgName)) {
+ Log.d(TAG, pkgName + "is incompatible with latest theme api for component " +
+ component + ", Applying " + defaultPkg);
+ builder.setComponent(component, pkgName);
+ }
+ }
+
+ // Now actually unapply the incompatible themes
+ ThemeChangeRequest request = builder.build();
+ if (!request.getThemeComponentsMap().isEmpty()) {
+ try {
+ requestThemeChange(request, true);
+ } catch(RemoteException e) {
+ // This cannot happen
+ }
+ } else {
+ Log.d(TAG, "Current theme is compatible with the system. Not unapplying anything");
+ }
+ }
+
+ private boolean isThemeCompatibleWithUpgradedApi(String pkgName) {
+ // Note this function does not cover the case of a downgrade. That case is out of scope and
+ // would require predicting whether the future API levels will be compatible or not.
+ boolean compatible = false;
+ try {
+ PackageInfo pi = mPM.getPackageInfo(pkgName, 0);
+ Log.d(TAG, "Comparing theme target: " + pi.applicationInfo.targetSdkVersion +
+ "to " + android.os.Build.VERSION.SDK_INT);
+ compatible = pi.applicationInfo.targetSdkVersion >= MIN_COMPATIBLE_VERSION;
+ } catch (NameNotFoundException e) {
+ Log.e(TAG, "Unable to get package info for " + pkgName, e);
+ }
+ return compatible;
+ }
+
+ private boolean isThemeApiUpToDate() {
+ // We can't be 100% sure its an upgrade. If the field is undefined it
+ // could have been a factory reset.
+ final ContentResolver resolver = mContext.getContentResolver();
+ int recordedApiLevel = android.os.Build.VERSION.SDK_INT;
+ try {
+ recordedApiLevel = CMSettings.Secure.getInt(resolver,
+ CMSettings.Secure.THEME_PREV_BOOT_API_LEVEL);
+ } catch (CMSettings.CMSettingNotFoundException e) {
+ recordedApiLevel = -1;
+ Log.d(TAG, "Previous api level not found. First time booting?");
+ }
+ Log.d(TAG, "Prev api level was: " + recordedApiLevel
+ + ", api is now: " + android.os.Build.VERSION.SDK_INT);
+
+ return recordedApiLevel == android.os.Build.VERSION.SDK_INT;
+ }
+
+ private void updateThemeApi() {
+ final ContentResolver resolver = mContext.getContentResolver();
+ boolean success = CMSettings.Secure.putInt(resolver,
+ CMSettings.Secure.THEME_PREV_BOOT_API_LEVEL, android.os.Build.VERSION.SDK_INT);
+ if (!success) {
+ Log.e(TAG, "Unable to store latest API level to secure settings");
+ }
+ }
+
+ private void doApplyTheme(ThemeChangeRequest request, boolean removePerAppTheme) {
+ synchronized(this) {
+ mProgress = 0;
+ }
+
+ if (request == null || request.getNumChangesRequested() == 0) {
+ postFinish(true, request, 0);
+ return;
+ }
+ mIsThemeApplying = true;
+ long updateTime = System.currentTimeMillis();
+
+ incrementProgress(5);
+
+ // TODO: provide progress updates that reflect the time needed for each component
+ final int progressIncrement = 75 / request.getNumChangesRequested();
+
+ if (request.getIconsThemePackageName() != null) {
+ updateIcons(request.getIconsThemePackageName());
+ incrementProgress(progressIncrement);
+ }
+
+ if (request.getWallpaperThemePackageName() != null) {
+ if (updateWallpaper(request.getWallpaperThemePackageName(),
+ request.getWallpaperId())) {
+ mWallpaperChangedByUs = true;
+ }
+ incrementProgress(progressIncrement);
+ }
+
+ if (request.getLockWallpaperThemePackageName() != null) {
+ updateLockscreen(request.getLockWallpaperThemePackageName());
+ incrementProgress(progressIncrement);
+ }
+
+ Environment.setUserRequired(false);
+ if (request.getNotificationThemePackageName() != null) {
+ updateNotifications(request.getNotificationThemePackageName());
+ incrementProgress(progressIncrement);
+ }
+
+ if (request.getAlarmThemePackageName() != null) {
+ updateAlarms(request.getAlarmThemePackageName());
+ incrementProgress(progressIncrement);
+ }
+
+ if (request.getRingtoneThemePackageName() != null) {
+ updateRingtones(request.getRingtoneThemePackageName());
+ incrementProgress(progressIncrement);
+ }
+ Environment.setUserRequired(true);
+
+ if (request.getBootanimationThemePackageName() != null) {
+ updateBootAnim(request.getBootanimationThemePackageName());
+ incrementProgress(progressIncrement);
+ }
+
+ if (request.getFontThemePackageName() != null) {
+ updateFonts(request.getFontThemePackageName());
+ incrementProgress(progressIncrement);
+ }
+
+ if (request.getLiveLockScreenThemePackageName() != null) {
+ updateLiveLockScreen(request.getLiveLockScreenThemePackageName());
+ incrementProgress(progressIncrement);
+ }
+
+ try {
+ updateProvider(request, updateTime);
+ } catch(IllegalArgumentException e) {
+ // Safeguard against provider not being ready yet.
+ Log.e(TAG, "Not updating the theme provider since it is unavailable");
+ }
+
+ if (shouldUpdateConfiguration(request)) {
+ updateConfiguration(request, removePerAppTheme);
+ }
+
+ killLaunchers(request);
+
+ postFinish(true, request, updateTime);
+ mIsThemeApplying = false;
+ }
+
+ private void doApplyDefaultTheme() {
+ final ContentResolver resolver = mContext.getContentResolver();
+ final String defaultThemePkg = Settings.Secure.getString(resolver,
+ Settings.Secure.DEFAULT_THEME_PACKAGE);
+ if (!TextUtils.isEmpty(defaultThemePkg)) {
+ String defaultThemeComponents = CMSettings.Secure.getString(resolver,
+ CMSettings.Secure.DEFAULT_THEME_COMPONENTS);
+ List<String> components;
+ if (TextUtils.isEmpty(defaultThemeComponents)) {
+ components = ThemeUtils.getAllComponents();
+ } else {
+ components = new ArrayList<String>(
+ Arrays.asList(defaultThemeComponents.split("\\|")));
+ }
+ ThemeChangeRequest.Builder builder = new ThemeChangeRequest.Builder();
+ for (String component : components) {
+ builder.setComponent(component, defaultThemePkg);
+ }
+ try {
+ requestThemeChange(builder.build(), true);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Unable to set default theme", e);
+ }
+ }
+ }
+
+ private void doRebuildResourceCache() {
+ FileUtils.deleteContents(new File(ThemeUtils.RESOURCE_CACHE_DIR));
+ processInstalledThemes();
+ }
+
+ private void updateProvider(ThemeChangeRequest request, long updateTime) {
+ ContentValues values = new ContentValues();
+ values.put(MixnMatchColumns.COL_UPDATE_TIME, updateTime);
+ Map<String, String> componentMap = request.getThemeComponentsMap();
+ for (String component : componentMap.keySet()) {
+ values.put(ThemesContract.MixnMatchColumns.COL_VALUE, componentMap.get(component));
+ String where = ThemesContract.MixnMatchColumns.COL_KEY + "=?";
+ String[] selectionArgs = { MixnMatchColumns.componentToMixNMatchKey(component) };
+ if (selectionArgs[0] == null) {
+ continue; // No equivalence between mixnmatch and theme
+ }
+
+ // Add component ID for multiwallpaper
+ if (ThemesColumns.MODIFIES_LAUNCHER.equals(component)) {
+ values.put(MixnMatchColumns.COL_COMPONENT_ID, request.getWallpaperId());
+ }
+
+ mContext.getContentResolver().update(MixnMatchColumns.CONTENT_URI, values, where,
+ selectionArgs);
+ }
+ }
+
+ private boolean updateIcons(String pkgName) {
+ ThemeUtils.clearIconCache();
+ try {
+ if (pkgName.equals(SYSTEM_DEFAULT)) {
+ mPM.updateIconMaps(null);
+ } else {
+ mPM.updateIconMaps(pkgName);
+ }
+ } catch (Exception e) {
+ Log.w(TAG, "Changing icons failed", e);
+ return false;
+ }
+ return true;
+ }
+
+ private boolean updateFonts(String pkgName) {
+ //Clear the font dir
+ FileUtils.deleteContents(new File(ThemeUtils.SYSTEM_THEME_FONT_PATH));
+
+ if (!pkgName.equals(SYSTEM_DEFAULT)) {
+ //Get Font Assets
+ Context themeCtx;
+ String[] assetList;
+ try {
+ themeCtx = mContext.createPackageContext(pkgName, Context.CONTEXT_IGNORE_SECURITY);
+ AssetManager assetManager = themeCtx.getAssets();
+ assetList = assetManager.list("fonts");
+ } catch (Exception e) {
+ Log.e(TAG, "There was an error getting assets for pkg " + pkgName, e);
+ return false;
+ }
+ if (assetList == null || assetList.length == 0) {
+ Log.e(TAG, "Could not find any font assets");
+ return false;
+ }
+
+ //Copy font assets to font dir
+ for(String asset : assetList) {
+ InputStream is = null;
+ OutputStream os = null;
+ try {
+ is = ThemeUtils.getInputStreamFromAsset(themeCtx,
+ "file:///android_asset/fonts/" + asset);
+ File outFile = new File(ThemeUtils.SYSTEM_THEME_FONT_PATH, asset);
+ FileUtils.copyToFile(is, outFile);
+ FileUtils.setPermissions(outFile,
+ FileUtils.S_IRWXU|FileUtils.S_IRGRP|FileUtils.S_IRWXO, -1, -1);
+ } catch (Exception e) {
+ Log.e(TAG, "There was an error installing the new fonts for pkg " + pkgName, e);
+ return false;
+ } finally {
+ ThemeUtils.closeQuietly(is);
+ ThemeUtils.closeQuietly(os);
+ }
+ }
+ }
+
+ //Notify zygote that themes need a refresh
+ SystemProperties.set("sys.refresh_theme", "1");
+ return true;
+ }
+
+ private boolean updateBootAnim(String pkgName) {
+ if (SYSTEM_DEFAULT.equals(pkgName)) {
+ clearBootAnimation();
+ return true;
+ }
+
+ try {
+ final ApplicationInfo ai = mPM.getApplicationInfo(pkgName, 0);
+ applyBootAnimation(ai.sourceDir);
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.w(TAG, "Changing boot animation failed", e);
+ return false;
+ }
+ return true;
+ }
+
+ private boolean updateAlarms(String pkgName) {
+ return updateAudible(ThemeUtils.SYSTEM_THEME_ALARM_PATH, "alarms",
+ RingtoneManager.TYPE_ALARM, pkgName);
+ }
+
+ private boolean updateNotifications(String pkgName) {
+ return updateAudible(ThemeUtils.SYSTEM_THEME_NOTIFICATION_PATH, "notifications",
+ RingtoneManager.TYPE_NOTIFICATION, pkgName);
+ }
+
+ private boolean updateRingtones(String pkgName) {
+ return updateAudible(ThemeUtils.SYSTEM_THEME_RINGTONE_PATH, "ringtones",
+ RingtoneManager.TYPE_RINGTONE, pkgName);
+ }
+
+ private boolean updateAudible(String dirPath, String assetPath, int type, String pkgName) {
+ //Clear the dir
+ ThemeUtils.clearAudibles(mContext, dirPath);
+ if (pkgName.equals(SYSTEM_DEFAULT)) {
+ if (!ThemeUtils.setDefaultAudible(mContext, type)) {
+ Log.e(TAG, "There was an error installing the default audio file");
+ return false;
+ }
+ return true;
+ }
+
+ PackageInfo pi = null;
+ try {
+ pi = mPM.getPackageInfo(pkgName, 0);
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.e(TAG, "Unable to update audible " + dirPath, e);
+ return false;
+ }
+
+ //Get theme Assets
+ Context themeCtx;
+ String[] assetList;
+ try {
+ themeCtx = mContext.createPackageContext(pkgName, Context.CONTEXT_IGNORE_SECURITY);
+ AssetManager assetManager = themeCtx.getAssets();
+ assetList = assetManager.list(assetPath);
+ } catch (Exception e) {
+ Log.e(TAG, "There was an error getting assets for pkg " + pkgName, e);
+ return false;
+ }
+ if (assetList == null || assetList.length == 0) {
+ Log.e(TAG, "Could not find any audio assets");
+ return false;
+ }
+
+ // TODO: right now we just load the first file but this will need to be changed
+ // in the future if multiple audio files are supported.
+ final String asset = assetList[0];
+ if (!ThemeUtils.isValidAudible(asset)) return false;
+
+ InputStream is = null;
+ OutputStream os = null;
+ try {
+ is = ThemeUtils.getInputStreamFromAsset(themeCtx, "file:///android_asset/"
+ + assetPath + File.separator + asset);
+ File outFile = new File(dirPath, asset);
+ FileUtils.copyToFile(is, outFile);
+ FileUtils.setPermissions(outFile,
+ FileUtils.S_IRWXU|FileUtils.S_IRGRP|FileUtils.S_IRWXO,-1, -1);
+ ThemeUtils.setAudible(mContext, outFile, type, pi.themeInfo.name);
+ } catch (Exception e) {
+ Log.e(TAG, "There was an error installing the new audio file for pkg " + pkgName, e);
+ return false;
+ } finally {
+ ThemeUtils.closeQuietly(is);
+ ThemeUtils.closeQuietly(os);
+ }
+ return true;
+ }
+
+ private boolean updateLockscreen(String pkgName) {
+ boolean success;
+ success = setCustomLockScreenWallpaper(pkgName);
+
+ // TODO: uncomment once Keyguard wallpaper is re-implemented
+ /*
+ if (success) {
+ mContext.sendBroadcastAsUser(new Intent(Intent.ACTION_KEYGUARD_WALLPAPER_CHANGED),
+ UserHandle.ALL);
+ }
+ */
+ return success;
+ }
+
+ private boolean setCustomLockScreenWallpaper(String pkgName) {
+ // TODO: uncomment once Keyguard wallpaper is re-implemented
+ /*
+ WallpaperManager wm = WallpaperManager.getInstance(mContext);
+ try {
+ if (SYSTEM_DEFAULT.equals(pkgName) || TextUtils.isEmpty(pkgName)) {
+ wm.clearKeyguardWallpaper();
+ } else {
+ InputStream in = ImageUtils.getCroppedKeyguardStream(pkgName, mContext);
+ if (in != null) {
+ wm.setKeyguardStream(in);
+ ThemeUtils.closeQuietly(in);
+ }
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "There was an error setting lockscreen wp for pkg " + pkgName, e);
+ return false;
+ }
+ */
+ return true;
+ }
+
+ private boolean updateWallpaper(String pkgName, long id) {
+ WallpaperManager wm = WallpaperManager.getInstance(mContext);
+ if (SYSTEM_DEFAULT.equals(pkgName)) {
+ try {
+ wm.clear();
+ } catch (IOException e) {
+ return false;
+ }
+ } else if (TextUtils.isEmpty(pkgName)) {
+ try {
+ wm.clear(false);
+ } catch (IOException e) {
+ return false;
+ }
+ } else {
+ InputStream in = null;
+ try {
+ in = ImageUtils.getCroppedWallpaperStream(pkgName, id, mContext);
+ if (in != null)
+ wm.setStream(in);
+ } catch (Exception e) {
+ return false;
+ } finally {
+ ThemeUtils.closeQuietly(in);
+ }
+ }
+ return true;
+ }
+
+ private boolean updateLiveLockScreen(String pkgName) {
+ // TODO: do something meaningful here once ready
+ return true;
+ }
+
+ private boolean updateConfiguration(ThemeChangeRequest request,
+ boolean removePerAppThemes) {
+ final IActivityManager am = ActivityManagerNative.getDefault();
+ if (am != null) {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ Configuration config = am.getConfiguration();
+ ThemeConfig.Builder themeBuilder = createBuilderFrom(config, request, null,
+ removePerAppThemes);
+ ThemeConfig newConfig = themeBuilder.build();
+
+ config.themeConfig = newConfig;
+ am.updateConfiguration(config);
+ } catch (RemoteException e) {
+ return false;
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+ return true;
+ }
+
+ private boolean updateConfiguration(ThemeConfig themeConfig) {
+ final IActivityManager am = ActivityManagerNative.getDefault();
+ if (am != null) {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ Configuration config = am.getConfiguration();
+
+ config.themeConfig = themeConfig;
+ am.updateConfiguration(config);
+ } catch (RemoteException e) {
+ return false;
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+ return true;
+ }
+
+ private boolean shouldUpdateConfiguration(ThemeChangeRequest request) {
+ return request.getOverlayThemePackageName() != null ||
+ request.getFontThemePackageName() != null ||
+ request.getIconsThemePackageName() != null ||
+ request.getStatusBarThemePackageName() != null ||
+ request.getNavBarThemePackageName() != null ||
+ request.getPerAppOverlays().size() > 0;
+ }
+
+ private static ThemeConfig.Builder createBuilderFrom(Configuration config,
+ ThemeChangeRequest request, String pkgName, boolean removePerAppThemes) {
+ ThemeConfig.Builder builder = new ThemeConfig.Builder(config.themeConfig);
+
+ if (removePerAppThemes) removePerAppThemesFromConfig(builder, config.themeConfig);
+
+ if (request.getIconsThemePackageName() != null) {
+ builder.defaultIcon(pkgName == null ? request.getIconsThemePackageName() : pkgName);
+ }
+
+ if (request.getOverlayThemePackageName() != null) {
+ builder.defaultOverlay(pkgName == null ?
+ request.getOverlayThemePackageName() : pkgName);
+ }
+
+ if (request.getFontThemePackageName() != null) {
+ builder.defaultFont(pkgName == null ? request.getFontThemePackageName() : pkgName);
+ }
+
+ if (request.getStatusBarThemePackageName() != null) {
+ builder.overlay(ThemeConfig.SYSTEMUI_STATUS_BAR_PKG, pkgName == null ?
+ request.getStatusBarThemePackageName() : pkgName);
+ }
+
+ if (request.getNavBarThemePackageName() != null) {
+ builder.overlay(ThemeConfig.SYSTEMUI_NAVBAR_PKG, pkgName == null ?
+ request.getNavBarThemePackageName() : pkgName);
+ }
+
+ // check for any per app overlays being applied
+ Map<String, String> appOverlays = request.getPerAppOverlays();
+ for (String appPkgName : appOverlays.keySet()) {
+ if (appPkgName != null) {
+ builder.overlay(appPkgName, appOverlays.get(appPkgName));
+ }
+ }
+
+ builder.setLastThemeChangeRequestType(request.getReqeustType());
+
+ return builder;
+ }
+
+ private static void removePerAppThemesFromConfig(ThemeConfig.Builder builder,
+ ThemeConfig themeConfig) {
+ if (themeConfig != null) {
+ Map<String, ThemeConfig.AppTheme> themes = themeConfig.getAppThemes();
+ for (String appPkgName : themes.keySet()) {
+ if (ThemeUtils.isPerAppThemeComponent(appPkgName)) {
+ builder.overlay(appPkgName, null);
+ }
+ }
+ }
+ }
+
+ // Kill the current Home process, they tend to be evil and cache
+ // drawable references in all apps
+ private void killLaunchers(ThemeChangeRequest request) {
+ if (request.getOverlayThemePackageName() == null
+ && request.getIconsThemePackageName() == null) {
+ return;
+ }
+
+ final ActivityManager am =
+ (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
+
+ Intent homeIntent = new Intent();
+ homeIntent.setAction(Intent.ACTION_MAIN);
+ homeIntent.addCategory(Intent.CATEGORY_HOME);
+
+ List<ResolveInfo> infos = mPM.queryIntentActivities(homeIntent, 0);
+ List<ResolveInfo> themeChangeInfos = mPM.queryBroadcastReceivers(
+ new Intent(ThemeUtils.ACTION_THEME_CHANGED), 0);
+ for(ResolveInfo info : infos) {
+ if (info.activityInfo != null && info.activityInfo.applicationInfo != null &&
+ !isSetupActivity(info) && !handlesThemeChanges(
+ info.activityInfo.applicationInfo.packageName, themeChangeInfos)) {
+ String pkgToStop = info.activityInfo.applicationInfo.packageName;
+ Log.d(TAG, "Force stopping " + pkgToStop + " for theme change");
+ try {
+ am.forceStopPackage(pkgToStop);
+ } catch(Exception e) {
+ Log.e(TAG, "Unable to force stop package, did you forget platform signature?",
+ e);
+ }
+ }
+ }
+ }
+
+ private boolean isSetupActivity(ResolveInfo info) {
+ return GOOGLE_SETUPWIZARD_PACKAGE.equals(info.activityInfo.packageName) ||
+ CM_SETUPWIZARD_PACKAGE.equals(info.activityInfo.packageName);
+ }
+
+ private boolean handlesThemeChanges(String pkgName, List<ResolveInfo> infos) {
+ if (infos != null && infos.size() > 0) {
+ for (ResolveInfo info : infos) {
+ if (info.activityInfo.applicationInfo.packageName.equals(pkgName)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ private void postProgress() {
+ int N = mClients.beginBroadcast();
+ for(int i=0; i < N; i++) {
+ IThemeChangeListener listener = mClients.getBroadcastItem(0);
+ try {
+ listener.onProgress(mProgress);
+ } catch(RemoteException e) {
+ Log.w(TAG, "Unable to post progress to client listener", e);
+ }
+ }
+ mClients.finishBroadcast();
+ }
+
+ private void postFinish(boolean isSuccess, ThemeChangeRequest request, long updateTime) {
+ synchronized(this) {
+ mProgress = 0;
+ }
+
+ int N = mClients.beginBroadcast();
+ for(int i=0; i < N; i++) {
+ IThemeChangeListener listener = mClients.getBroadcastItem(0);
+ try {
+ listener.onFinish(isSuccess);
+ } catch(RemoteException e) {
+ Log.w(TAG, "Unable to post progress to client listener", e);
+ }
+ }
+ mClients.finishBroadcast();
+
+ // if successful, broadcast that the theme changed
+ if (isSuccess) {
+ broadcastThemeChange(request, updateTime);
+ }
+ }
+
+ private void postFinishedProcessing(String pkgName) {
+ int N = mProcessingListeners.beginBroadcast();
+ for(int i=0; i < N; i++) {
+ IThemeProcessingListener listener = mProcessingListeners.getBroadcastItem(0);
+ try {
+ listener.onFinishedProcessing(pkgName);
+ } catch(RemoteException e) {
+ Log.w(TAG, "Unable to post progress to listener", e);
+ }
+ }
+ mProcessingListeners.finishBroadcast();
+ }
+
+ private void broadcastThemeChange(ThemeChangeRequest request, long updateTime) {
+ Map<String, String> componentMap = request.getThemeComponentsMap();
+ if (componentMap == null || componentMap.size() == 0) return;
+
+ final Intent intent = new Intent(ThemeUtils.ACTION_THEME_CHANGED);
+ ArrayList componentsArrayList = new ArrayList(componentMap.keySet());
+ intent.putStringArrayListExtra(ThemeUtils.EXTRA_COMPONENTS, componentsArrayList);
+ intent.putExtra(ThemeUtils.EXTRA_REQUEST_TYPE, request.getReqeustType().ordinal());
+ intent.putExtra(ThemeUtils.EXTRA_UPDATE_TIME, updateTime);
+ mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
+ }
+
+ private void incrementProgress(int increment) {
+ synchronized(this) {
+ mProgress += increment;
+ if (mProgress > 100) mProgress = 100;
+ }
+ postProgress();
+ }
+
+ @Override
+ public void requestThemeChangeUpdates(IThemeChangeListener listener) throws RemoteException {
+ mContext.enforceCallingOrSelfPermission(
+ Manifest.permission.ACCESS_THEME_MANAGER, null);
+ mClients.register(listener);
+ }
+
+ @Override
+ public void removeUpdates(IThemeChangeListener listener) throws RemoteException {
+ mContext.enforceCallingOrSelfPermission(
+ Manifest.permission.ACCESS_THEME_MANAGER, null);
+ mClients.unregister(listener);
+ }
+
+ @Override
+ public void requestThemeChange(ThemeChangeRequest request, boolean removePerAppThemes)
+ throws RemoteException {
+ mContext.enforceCallingOrSelfPermission(
+ Manifest.permission.ACCESS_THEME_MANAGER, null);
+ Message msg;
+
+ /**
+ * Since the ThemeService handles compiling theme resource we need to make sure that any
+ * of the components we are trying to apply are either already processed or put to the
+ * front of the queue and handled before the theme change takes place.
+ *
+ * TODO: create a callback that can be sent to any ThemeChangeListeners to notify them that
+ * the theme will be applied once the processing is done.
+ */
+ synchronized (mThemesToProcessQueue) {
+ Map<String, String> componentMap = request.getThemeComponentsMap();
+ for (Object key : componentMap.keySet()) {
+ if (ThemesColumns.MODIFIES_OVERLAYS.equals(key) ||
+ ThemesColumns.MODIFIES_NAVIGATION_BAR.equals(key) ||
+ ThemesColumns.MODIFIES_STATUS_BAR.equals(key) ||
+ ThemesColumns.MODIFIES_ICONS.equals(key)) {
+ String pkgName = (String) componentMap.get(key);
+ if (mThemesToProcessQueue.indexOf(pkgName) > 0) {
+ mThemesToProcessQueue.remove(pkgName);
+ mThemesToProcessQueue.add(0, pkgName);
+ // We want to make sure these resources are taken care of first so
+ // send the dequeue message and place it in the front of the queue
+ msg = mResourceProcessingHandler.obtainMessage(
+ ResourceProcessingHandler.MESSAGE_DEQUEUE_AND_PROCESS_THEME);
+ mResourceProcessingHandler.sendMessageAtFrontOfQueue(msg);
+ }
+ }
+ }
+ }
+ msg = Message.obtain();
+ msg.what = ThemeWorkerHandler.MESSAGE_CHANGE_THEME;
+ msg.obj = request;
+ msg.arg1 = removePerAppThemes ? 1 : 0;
+ mHandler.sendMessage(msg);
+ }
+
+ @Override
+ public void applyDefaultTheme() {
+ mContext.enforceCallingOrSelfPermission(
+ Manifest.permission.ACCESS_THEME_MANAGER, null);
+ Message msg = Message.obtain();
+ msg.what = ThemeWorkerHandler.MESSAGE_APPLY_DEFAULT_THEME;
+ mHandler.sendMessage(msg);
+ }
+
+ @Override
+ public boolean isThemeApplying() throws RemoteException {
+ mContext.enforceCallingOrSelfPermission(Manifest.permission.ACCESS_THEME_MANAGER, null);
+ return mIsThemeApplying;
+ }
+
+ @Override
+ public int getProgress() throws RemoteException {
+ mContext.enforceCallingOrSelfPermission(Manifest.permission.ACCESS_THEME_MANAGER, null);
+ synchronized(this) {
+ return mProgress;
+ }
+ }
+
+ @Override
+ public boolean cacheComposedIcon(Bitmap icon, String fileName) throws RemoteException {
+ final long token = Binder.clearCallingIdentity();
+ boolean success;
+ FileOutputStream os;
+ final File cacheDir = new File(ThemeUtils.SYSTEM_THEME_ICON_CACHE_DIR);
+ if (cacheDir.listFiles().length == 0) {
+ mIconCacheSize = 0;
+ }
+ try {
+ File outFile = new File(cacheDir, fileName);
+ os = new FileOutputStream(outFile);
+ icon.compress(Bitmap.CompressFormat.PNG, 90, os);
+ os.close();
+ FileUtils.setPermissions(outFile,
+ FileUtils.S_IRWXU | FileUtils.S_IRWXG | FileUtils.S_IROTH,
+ -1, -1);
+ mIconCacheSize += outFile.length();
+ if (mIconCacheSize > MAX_ICON_CACHE_SIZE) {
+ purgeIconCache();
+ }
+ success = true;
+ } catch (Exception e) {
+ success = false;
+ Log.w(TAG, "Unable to cache icon " + fileName, e);
+ }
+ Binder.restoreCallingIdentity(token);
+ return success;
+ }
+
+ @Override
+ public boolean processThemeResources(String themePkgName) throws RemoteException {
+ mContext.enforceCallingOrSelfPermission(
+ Manifest.permission.ACCESS_THEME_MANAGER, null);
+ try {
+ mPM.getPackageInfo(themePkgName, 0);
+ } catch (PackageManager.NameNotFoundException e) {
+ // Package doesn't exist so nothing to process
+ return false;
+ }
+ // Obtain a message and send it to the handler to process this theme
+ Message msg = mResourceProcessingHandler.obtainMessage(
+ ResourceProcessingHandler.MESSAGE_QUEUE_THEME_FOR_PROCESSING, 0, 0, themePkgName);
+ mResourceProcessingHandler.sendMessage(msg);
+ return true;
+ }
+
+ @Override
+ public boolean isThemeBeingProcessed(String themePkgName) throws RemoteException {
+ mContext.enforceCallingOrSelfPermission(
+ Manifest.permission.ACCESS_THEME_MANAGER, null);
+ synchronized (mThemesToProcessQueue) {
+ return mThemesToProcessQueue.contains(themePkgName);
+ }
+ }
+
+ @Override
+ public void registerThemeProcessingListener(IThemeProcessingListener listener)
+ throws RemoteException {
+ mContext.enforceCallingOrSelfPermission(
+ Manifest.permission.ACCESS_THEME_MANAGER, null);
+ mProcessingListeners.register(listener);
+ }
+
+ @Override
+ public void unregisterThemeProcessingListener(IThemeProcessingListener listener)
+ throws RemoteException {
+ mContext.enforceCallingOrSelfPermission(
+ Manifest.permission.ACCESS_THEME_MANAGER, null);
+ mProcessingListeners.unregister(listener);
+ }
+
+ @Override
+ public void rebuildResourceCache() throws RemoteException {
+ mContext.enforceCallingOrSelfPermission(
+ Manifest.permission.ACCESS_THEME_MANAGER, null);
+ mHandler.sendEmptyMessage(ThemeWorkerHandler.MESSAGE_REBUILD_RESOURCE_CACHE);
+ }
+
+ private void purgeIconCache() {
+ Log.d(TAG, "Purging icon cahe of size " + mIconCacheSize);
+ File cacheDir = new File(ThemeUtils.SYSTEM_THEME_ICON_CACHE_DIR);
+ File[] files = cacheDir.listFiles();
+ Arrays.sort(files, mOldestFilesFirstComparator);
+ for (File f : files) {
+ if (!f.isDirectory()) {
+ final long size = f.length();
+ if(f.delete()) mIconCacheSize -= size;
+ }
+ if (mIconCacheSize <= PURGED_ICON_CACHE_SIZE) break;
+ }
+ }
+
+ private boolean applyBootAnimation(String themePath) {
+ boolean success = false;
+ try {
+ ZipFile zip = new ZipFile(new File(themePath));
+ ZipEntry ze = zip.getEntry(THEME_BOOTANIMATION_PATH);
+ if (ze != null) {
+ clearBootAnimation();
+ BufferedInputStream is = new BufferedInputStream(zip.getInputStream(ze));
+ final String bootAnimationPath = SYSTEM_THEME_PATH + File.separator
+ + "bootanimation.zip";
+ ThemeUtils.copyAndScaleBootAnimation(mContext, is, bootAnimationPath);
+ FileUtils.setPermissions(bootAnimationPath,
+ FileUtils.S_IRWXU|FileUtils.S_IRGRP|FileUtils.S_IROTH, -1, -1);
+ }
+ zip.close();
+ success = true;
+ } catch (Exception e) {
+ Log.w(TAG, "Unable to load boot animation for " + themePath, e);
+ }
+
+ return success;
+ }
+
+ private void clearBootAnimation() {
+ File anim = new File(SYSTEM_THEME_PATH + File.separator + "bootanimation.zip");
+ if (anim.exists())
+ anim.delete();
+ }
+
+ private BroadcastReceiver mWallpaperChangeReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (!mWallpaperChangedByUs) {
+ // In case the mixnmatch table has a mods_launcher entry, we'll clear it
+ ThemeChangeRequest.Builder builder = new ThemeChangeRequest.Builder();
+ builder.setWallpaper("");
+ updateProvider(builder.build(), System.currentTimeMillis());
+ } else {
+ mWallpaperChangedByUs = false;
+ }
+ }
+ };
+
+ private BroadcastReceiver mUserChangeReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
+ if (userHandle >= 0 && userHandle != mCurrentUserId) {
+ mCurrentUserId = userHandle;
+ ThemeConfig config = ThemeConfig.getBootThemeForUser(mContext.getContentResolver(),
+ userHandle);
+ if (DEBUG) {
+ Log.d(TAG,
+ "Changing theme for user " + userHandle + " to " + config.toString());
+ }
+ ThemeChangeRequest request = new ThemeChangeRequest.Builder(config).build();
+ try {
+ requestThemeChange(request, true);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Unable to change theme for user change", e);
+ }
+ }
+ }
+ };
+
+ private Comparator<File> mOldestFilesFirstComparator = new Comparator<File>() {
+ @Override
+ public int compare(File lhs, File rhs) {
+ return (int) (lhs.lastModified() - rhs.lastModified());
+ }
+ };
+
+ private void processInstalledThemes() {
+ final String defaultTheme = ThemeUtils.getDefaultThemePackageName(mContext);
+ Message msg;
+ // Make sure the default theme is the first to get processed!
+ if (!ThemeConfig.SYSTEM_DEFAULT.equals(defaultTheme)) {
+ msg = mHandler.obtainMessage(
+ ResourceProcessingHandler.MESSAGE_QUEUE_THEME_FOR_PROCESSING,
+ 0, 0, defaultTheme);
+ mResourceProcessingHandler.sendMessage(msg);
+ }
+ // Iterate over all installed packages and queue up the ones that are themes or icon packs
+ List<PackageInfo> packages = mPM.getInstalledPackages(0);
+ for (PackageInfo info : packages) {
+ if (!defaultTheme.equals(info.packageName) &&
+ (info.isThemeApk || info.isLegacyIconPackApk)) {
+ msg = mHandler.obtainMessage(
+ ResourceProcessingHandler.MESSAGE_QUEUE_THEME_FOR_PROCESSING,
+ 0, 0, info.packageName);
+ mResourceProcessingHandler.sendMessage(msg);
+ }
+ }
+ }
+
+ private void sendThemeResourcesCachedBroadcast(String themePkgName, int resultCode) {
+ final Intent intent = new Intent(Intent.ACTION_THEME_RESOURCES_CACHED);
+ intent.putExtra(Intent.EXTRA_THEME_PACKAGE_NAME, themePkgName);
+ intent.putExtra(Intent.EXTRA_THEME_RESULT, resultCode);
+ mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
+ }
+
+ /**
+ * Posts a notification to let the user know the theme was not installed.
+ * @param name
+ */
+ private void postFailedThemeInstallNotification(String name) {
+ NotificationManager nm =
+ (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
+ Notification notice = new Notification.Builder(mContext)
+ .setAutoCancel(true)
+ .setOngoing(false)
+ .setContentTitle(
+ mContext.getString(R.string.theme_install_error_title))
+ .setContentText(String.format(mContext.getString(
+ R.string.theme_install_error_message),
+ name))
+ .setSmallIcon(android.R.drawable.stat_notify_error)
+ .setWhen(System.currentTimeMillis())
+ .build();
+ nm.notify(name.hashCode(), notice);
+ }
+
+ private String getThemeName(PackageInfo pi) {
+ if (pi.themeInfo != null) {
+ return pi.themeInfo.name;
+ } else if (pi.isLegacyIconPackApk) {
+ return pi.applicationInfo.name;
+ }
+
+ return null;
+ }
+}
diff --git a/services/core/java/com/android/server/Watchdog.java b/services/core/java/com/android/server/Watchdog.java
index 772a15c..22529a3 100644
--- a/services/core/java/com/android/server/Watchdog.java
+++ b/services/core/java/com/android/server/Watchdog.java
@@ -42,6 +42,8 @@ import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
+import java.util.Date;
+import java.text.SimpleDateFormat;
/** This class calls its monitor every minute. Killing this process if they don't return **/
public class Watchdog extends Thread {
@@ -80,6 +82,7 @@ public class Watchdog extends Thread {
int mPhonePid;
IActivityController mController;
boolean mAllowRestart = true;
+ SimpleDateFormat mTraceDateFormat = new SimpleDateFormat("dd_MMM_HH_mm_ss.SSS");
/**
* Used for checking status of handle threads and scheduling monitor callbacks.
@@ -428,9 +431,22 @@ public class Watchdog extends Thread {
dumpKernelStackTraces();
}
- // Trigger the kernel to dump all blocked threads, and backtraces on all CPUs to the kernel log
- doSysRq('w');
- doSysRq('l');
+ String tracesPath = SystemProperties.get("dalvik.vm.stack-trace-file", null);
+ String traceFileNameAmendment = "_SystemServer_WDT" + mTraceDateFormat.format(new Date());
+
+ if (tracesPath != null && tracesPath.length() != 0) {
+ File traceRenameFile = new File(tracesPath);
+ String newTracesPath;
+ int lpos = tracesPath.lastIndexOf (".");
+ if (-1 != lpos)
+ newTracesPath = tracesPath.substring (0, lpos) + traceFileNameAmendment + tracesPath.substring (lpos);
+ else
+ newTracesPath = tracesPath + traceFileNameAmendment;
+ traceRenameFile.renameTo(new File(newTracesPath));
+ tracesPath = newTracesPath;
+ }
+
+ final File newFd = new File(tracesPath);
// Try to add the error to the dropbox, but assuming that the ActivityManager
// itself may be deadlocked. (which has happened, causing this statement to
@@ -439,7 +455,7 @@ public class Watchdog extends Thread {
public void run() {
mActivity.addErrorToDropBox(
"watchdog", null, "system_server", null, null,
- subject, null, stack, null);
+ subject, null, newFd, null);
}
};
dropboxThread.start();
@@ -447,6 +463,24 @@ public class Watchdog extends Thread {
dropboxThread.join(2000); // wait up to 2 seconds for it to return.
} catch (InterruptedException ignored) {}
+ // Trigger the kernel to dump all blocked threads, and backtraces on all CPUs to the kernel log
+ Slog.e(TAG, "Triggering SysRq for system_server watchdog");
+ doSysRq('w');
+ doSysRq('l');
+
+ // At times, when user space watchdog traces don't give an indication on
+ // which component held a lock, because of which other threads are blocked,
+ // (thereby causing Watchdog), crash the device to analyze RAM dumps
+ boolean crashOnWatchdog = SystemProperties
+ .getBoolean("persist.sys.crashOnWatchdog", false);
+ if (crashOnWatchdog) {
+ // wait until the above blocked threads be dumped into kernel log
+ SystemClock.sleep(3000);
+
+ // now try to crash the target
+ doSysRq('c');
+ }
+
IActivityController controller;
synchronized (this) {
controller = mController;
diff --git a/services/core/java/com/android/server/WiredAccessoryManager.java b/services/core/java/com/android/server/WiredAccessoryManager.java
index e0e6070..1b82ed6 100644
--- a/services/core/java/com/android/server/WiredAccessoryManager.java
+++ b/services/core/java/com/android/server/WiredAccessoryManager.java
@@ -66,6 +66,7 @@ final class WiredAccessoryManager implements WiredAccessoryCallbacks {
private static final String NAME_H2W = "h2w";
private static final String NAME_USB_AUDIO = "usb_audio";
+ private static final String NAME_SAMSUNG_USB_AUDIO = "dock";
private static final String NAME_HDMI_AUDIO = "hdmi_audio";
private static final String NAME_HDMI = "hdmi";
@@ -330,7 +331,8 @@ final class WiredAccessoryManager implements WiredAccessoryCallbacks {
FileReader file = new FileReader(uei.getSwitchStatePath());
int len = file.read(buffer, 0, 1024);
file.close();
- curState = Integer.valueOf((new String(buffer, 0, len)).trim());
+ curState = validateSwitchState(
+ Integer.valueOf((new String(buffer, 0, len)).trim()));
if (curState > 0) {
updateStateLocked(uei.getDevPath(), uei.getDevName(), curState);
@@ -345,14 +347,23 @@ final class WiredAccessoryManager implements WiredAccessoryCallbacks {
}
// At any given time accessories could be inserted
- // one on the board, one on the dock and one on HDMI:
- // observe three UEVENTs
+ // one on the board, one on the dock, one on the
+ // samsung dock and one on HDMI:
+ // observe all UEVENTs that have valid switch supported
+ // by the Kernel
for (int i = 0; i < mUEventInfo.size(); ++i) {
UEventInfo uei = mUEventInfo.get(i);
startObserving("DEVPATH="+uei.getDevPath());
}
}
+ private int validateSwitchState(int state) {
+ // Some drivers, namely HTC headset ones, add additional bits to
+ // the switch state. As we only are able to deal with the states
+ // 0, 1 and 2, mask out all the other bits
+ return state & 0x3;
+ }
+
private List<UEventInfo> makeObservedUEventList() {
List<UEventInfo> retVal = new ArrayList<UEventInfo>();
UEventInfo uei;
@@ -375,6 +386,15 @@ final class WiredAccessoryManager implements WiredAccessoryCallbacks {
Slog.w(TAG, "This kernel does not have usb audio support");
}
+ // Monitor Samsung USB audio
+ uei = new UEventInfo(NAME_SAMSUNG_USB_AUDIO, BIT_USB_HEADSET_DGTL,
+ BIT_USB_HEADSET_ANLG, 0);
+ if (uei.checkSwitchExists()) {
+ retVal.add(uei);
+ } else {
+ Slog.w(TAG, "This kernel does not have samsung usb dock audio support");
+ }
+
// Monitor HDMI
//
// If the kernel has support for the "hdmi_audio" switch, use that. It will be
@@ -405,7 +425,7 @@ final class WiredAccessoryManager implements WiredAccessoryCallbacks {
try {
String devPath = event.get("DEVPATH");
String name = event.get("SWITCH_NAME");
- int state = Integer.parseInt(event.get("SWITCH_STATE"));
+ int state = validateSwitchState(Integer.parseInt(event.get("SWITCH_STATE")));
synchronized (mLock) {
updateStateLocked(devPath, name, state);
}
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index 3c6de07..1e0cf0a 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -528,6 +528,7 @@ public class AccountManagerService
@Override
public String getPassword(Account account) {
+ android.util.SeempLog.record(14);
int callingUid = Binder.getCallingUid();
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "getPassword: " + account
@@ -627,6 +628,7 @@ public class AccountManagerService
@Override
public String getUserData(Account account, String key) {
+ android.util.SeempLog.record(15);
final int callingUid = Binder.getCallingUid();
if (Log.isLoggable(TAG, Log.VERBOSE)) {
String msg = String.format("getUserData( account: %s, key: %s, callerUid: %s, pid: %s",
@@ -1199,6 +1201,7 @@ public class AccountManagerService
@Override
public void removeAccount(IAccountManagerResponse response, Account account,
boolean expectActivityLaunch) {
+ android.util.SeempLog.record(17);
removeAccountAsUser(
response,
account,
@@ -1587,6 +1590,7 @@ public class AccountManagerService
@Override
public void setPassword(Account account, String password) {
+ android.util.SeempLog.record(18);
final int callingUid = Binder.getCallingUid();
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "setAuthToken: " + account
@@ -1651,6 +1655,7 @@ public class AccountManagerService
@Override
public void clearPassword(Account account) {
+ android.util.SeempLog.record(19);
final int callingUid = Binder.getCallingUid();
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "clearPassword: " + account
@@ -1677,6 +1682,7 @@ public class AccountManagerService
@Override
public void setUserData(Account account, String key, String value) {
+ android.util.SeempLog.record(20);
final int callingUid = Binder.getCallingUid();
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "setUserData: " + account
@@ -2116,6 +2122,7 @@ public class AccountManagerService
public void addAccount(final IAccountManagerResponse response, final String accountType,
final String authTokenType, final String[] requiredFeatures,
final boolean expectActivityLaunch, final Bundle optionsIn) {
+ android.util.SeempLog.record(16);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "addAccount: accountType " + accountType
+ ", response " + response
@@ -2369,6 +2376,7 @@ public class AccountManagerService
@Override
public void editProperties(IAccountManagerResponse response, final String accountType,
final boolean expectActivityLaunch) {
+ android.util.SeempLog.record(21);
final int callingUid = Binder.getCallingUid();
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "editProperties: accountType " + accountType
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 970f1b5..542268e 100755
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -1378,7 +1378,7 @@ public final class ActiveServices {
return null;
}
- if (!whileRestarting && r.restartDelay > 0) {
+ if (!whileRestarting && r.restartDelay > 0 && mRestartingServices.contains(r)) {
// If waiting for a restart, then do nothing.
return null;
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index b4d2746..b34a6ef 100644..100755
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -1,6 +1,8 @@
/*
* Copyright (C) 2006-2008 The Android Open Source Project
- *
+ * This code has been modified. Portions copyright (C) 2010, T-Mobile USA, Inc.
+ * Copyright (c) 2010-2015, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
* 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
@@ -52,6 +54,7 @@ import android.app.usage.UsageStatsManagerInternal;
import android.appwidget.AppWidgetManager;
import android.content.pm.PermissionInfo;
import android.content.res.Resources;
+import android.content.res.ThemeConfig;
import android.graphics.Bitmap;
import android.graphics.Point;
import android.graphics.Rect;
@@ -72,6 +75,7 @@ import android.util.DebugUtils;
import android.util.SparseIntArray;
import android.view.Display;
+import android.view.InflateException;
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.app.AssistUtils;
@@ -170,6 +174,7 @@ import android.content.pm.InstrumentationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.ParceledListSlice;
+import android.content.pm.ThemeUtils;
import android.content.pm.UserInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.PathPermission;
@@ -178,6 +183,7 @@ import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
+import android.content.res.ThemeConfig;
import android.net.Proxy;
import android.net.ProxyInfo;
import android.net.Uri;
@@ -259,6 +265,8 @@ import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;
+import java.util.Date;
+import java.text.SimpleDateFormat;
public final class ActivityManagerService extends ActivityManagerNative
implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
@@ -292,6 +300,11 @@ public final class ActivityManagerService extends ActivityManagerNative
private static final String TAG_VISIBILITY = TAG + POSTFIX_VISIBILITY;
private static final String TAG_VISIBLE_BEHIND = TAG + POSTFIX_VISIBLE_BEHIND;
+ private static final String ACTION_POWER_OFF_ALARM =
+ "org.codeaurora.alarm.action.POWER_OFF_ALARM";
+
+ private static final String POWER_OFF_ALARM = "powerOffAlarm";
+
/** Control over CPU and battery monitoring */
// write battery stats every 30 minutes.
static final long BATTERY_STATS_TIME = 30 * 60 * 1000;
@@ -393,6 +406,8 @@ public final class ActivityManagerService extends ActivityManagerNative
// How many bytes to write into the dropbox log before truncating
static final int DROPBOX_MAX_SIZE = 256 * 1024;
+ static final String PROP_REFRESH_THEME = "sys.refresh_theme";
+
// Access modes for handleIncomingUser.
static final int ALLOW_NON_FULL = 0;
static final int ALLOW_NON_FULL_IN_PROFILE = 1;
@@ -406,6 +421,8 @@ public final class ActivityManagerService extends ActivityManagerNative
// Necessary ApplicationInfo flags to mark an app as persistent
private static final int PERSISTENT_MASK =
ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT;
+ private boolean mHomeKilled = false;
+ private String mHomeProcessName = null;
// Delay to disable app launch boost
@@ -496,6 +513,8 @@ public final class ActivityManagerService extends ActivityManagerNative
*/
String mDeviceOwnerName;
+ SimpleDateFormat mTraceDateFormat = new SimpleDateFormat("dd_MMM_HH_mm_ss.SSS");
+
public class PendingAssistExtras extends Binder implements Runnable {
public final ActivityRecord activity;
public final Bundle extras;
@@ -1023,6 +1042,7 @@ public final class ActivityManagerService extends ActivityManagerNative
boolean mLaunchWarningShown = false;
Context mContext;
+ Context mUiContext;
int mFactoryTest;
@@ -1235,6 +1255,7 @@ public final class ActivityManagerService extends ActivityManagerNative
boolean foregroundActivities;
}
+ private Map<Integer, Object[]> mForegroundActivitiesList = new HashMap<Integer, Object[]>();
final RemoteCallbackList<IProcessObserver> mProcessObservers = new RemoteCallbackList<>();
ProcessChangeItem[] mActiveProcessChanges = new ProcessChangeItem[5];
@@ -1376,6 +1397,8 @@ public final class ActivityManagerService extends ActivityManagerNative
static final int SHUTDOWN_UI_AUTOMATION_CONNECTION_MSG = 57;
static final int APP_BOOST_DEACTIVATE_MSG = 58;
static final int CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG = 59;
+ static final int POST_PRIVACY_NOTIFICATION_MSG = 60;
+ static final int CANCEL_PRIVACY_NOTIFICATION_MSG = 61;
static final int FIRST_ACTIVITY_STACK_MSG = 100;
static final int FIRST_BROADCAST_QUEUE_MSG = 200;
@@ -1385,6 +1408,16 @@ public final class ActivityManagerService extends ActivityManagerNative
CompatModeDialog mCompatModeDialog;
long mLastMemUsageReportTime = 0;
+ // Min aging threshold in milliseconds to consider a B-service
+ int mMinBServiceAgingTime =
+ SystemProperties.getInt("ro.sys.fw.bservice_age", 5000);
+ // Threshold for B-services when in memory pressure
+ int mBServiceAppThreshold =
+ SystemProperties.getInt("ro.sys.fw.bservice_limit", 5);
+ // Enable B-service aging propagation on memory pressure.
+ boolean mEnableBServicePropagation =
+ SystemProperties.getBoolean("ro.sys.fw.bservice_enable", false);
+
/**
* Flag whether the current user is a "monkey", i.e. whether
* the UI is driven by a UI automation tool.
@@ -1438,7 +1471,7 @@ public final class ActivityManagerService extends ActivityManagerNative
return;
}
if (mShowDialogs && !mSleeping && !mShuttingDown) {
- Dialog d = new AppErrorDialog(mContext,
+ Dialog d = new AppErrorDialog(getUiContext(),
ActivityManagerService.this, res, proc);
d.show();
proc.crashDialog = d;
@@ -1473,7 +1506,7 @@ public final class ActivityManagerService extends ActivityManagerNative
if (mShowDialogs) {
Dialog d = new AppNotRespondingDialog(ActivityManagerService.this,
- mContext, proc, (ActivityRecord)data.get("activity"),
+ getUiContext(), proc, (ActivityRecord)data.get("activity"),
msg.arg1 != 0);
d.show();
proc.anrDialog = d;
@@ -1499,7 +1532,7 @@ public final class ActivityManagerService extends ActivityManagerNative
}
AppErrorResult res = (AppErrorResult) data.get("result");
if (mShowDialogs && !mSleeping && !mShuttingDown) {
- Dialog d = new StrictModeViolationDialog(mContext,
+ Dialog d = new StrictModeViolationDialog(getUiContext(),
ActivityManagerService.this, res, proc);
d.show();
proc.crashDialog = d;
@@ -1513,7 +1546,7 @@ public final class ActivityManagerService extends ActivityManagerNative
} break;
case SHOW_FACTORY_ERROR_MSG: {
Dialog d = new FactoryErrorDialog(
- mContext, msg.getData().getCharSequence("msg"));
+ getUiContext(), msg.getData().getCharSequence("msg"));
d.show();
ensureBootCompleted();
} break;
@@ -1524,7 +1557,7 @@ public final class ActivityManagerService extends ActivityManagerNative
if (!app.waitedForDebugger) {
Dialog d = new AppWaitingForDebuggerDialog(
ActivityManagerService.this,
- mContext, app);
+ getUiContext(), app);
app.waitDialog = d;
app.waitedForDebugger = true;
d.show();
@@ -2071,6 +2104,69 @@ public final class ActivityManagerService extends ActivityManagerNative
}
}
} break;
+ case POST_PRIVACY_NOTIFICATION_MSG: {
+ INotificationManager inm = NotificationManager.getService();
+ if (inm == null) {
+ return;
+ }
+
+ ActivityRecord root = (ActivityRecord)msg.obj;
+ ProcessRecord process = root.app;
+ if (process == null) {
+ return;
+ }
+
+ try {
+ Context context = mContext.createPackageContext(process.info.packageName, 0);
+ String text = mContext.getString(R.string.privacy_guard_notification_detail,
+ context.getApplicationInfo().loadLabel(context.getPackageManager()));
+ String title = mContext.getString(R.string.privacy_guard_notification);
+
+ Intent infoIntent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
+ Uri.fromParts("package", root.packageName, null));
+
+ Notification notification = new Notification();
+ notification.icon = com.android.internal.R.drawable.stat_notify_privacy_guard;
+ notification.when = 0;
+ notification.flags = Notification.FLAG_ONGOING_EVENT;
+ notification.priority = Notification.PRIORITY_LOW;
+ notification.defaults = 0;
+ notification.sound = null;
+ notification.vibrate = null;
+ notification.setLatestEventInfo(mContext,
+ title, text,
+ PendingIntent.getActivityAsUser(mContext, 0, infoIntent,
+ PendingIntent.FLAG_CANCEL_CURRENT, null,
+ new UserHandle(root.userId)));
+
+ try {
+ int[] outId = new int[1];
+ inm.enqueueNotificationWithTag("android", "android", null,
+ R.string.privacy_guard_notification,
+ notification, outId, root.userId);
+ } catch (RuntimeException e) {
+ Slog.w(ActivityManagerService.TAG,
+ "Error showing notification for privacy guard", e);
+ } catch (RemoteException e) {
+ }
+ } catch (NameNotFoundException e) {
+ Slog.w(TAG, "Unable to create context for privacy guard notification", e);
+ }
+ } break;
+ case CANCEL_PRIVACY_NOTIFICATION_MSG: {
+ INotificationManager inm = NotificationManager.getService();
+ if (inm == null) {
+ return;
+ }
+ try {
+ inm.cancelNotificationWithTag("android", null,
+ R.string.privacy_guard_notification, msg.arg1);
+ } catch (RuntimeException e) {
+ Slog.w(ActivityManagerService.TAG,
+ "Error canceling notification for service", e);
+ } catch (RemoteException e) {
+ }
+ } break;
}
}
};
@@ -2619,6 +2715,15 @@ public final class ActivityManagerService extends ActivityManagerNative
-1, Process.SYSTEM_UID, UserHandle.USER_ALL);
}
+ private Context getUiContext() {
+ synchronized (this) {
+ if (mUiContext == null && mBooted) {
+ mUiContext = ThemeUtils.createUiContext(mContext);
+ }
+ return mUiContext != null ? mUiContext : mContext;
+ }
+ }
+
/**
* Initialize the application bind args. These are passed to each
* process when the bindApplication() IPC is sent to the process. They're
@@ -3353,6 +3458,13 @@ public final class ActivityManagerService extends ActivityManagerNative
debugFlags |= Zygote.DEBUG_ENABLE_ASSERT;
}
+ //Check if zygote should refresh its fonts
+ boolean refreshTheme = false;
+ if (SystemProperties.getBoolean(PROP_REFRESH_THEME, false)) {
+ SystemProperties.set(PROP_REFRESH_THEME, "false");
+ refreshTheme = true;
+ }
+
String requiredAbi = (abiOverride != null) ? abiOverride : app.info.primaryCpuAbi;
if (requiredAbi == null) {
requiredAbi = Build.SUPPORTED_ABIS[0];
@@ -3377,7 +3489,7 @@ public final class ActivityManagerService extends ActivityManagerNative
Process.ProcessStartResult startResult = Process.start(entryPoint,
app.processName, uid, uid, gids, debugFlags, mountExternal,
app.info.targetSdkVersion, app.info.seinfo, requiredAbi, instructionSet,
- app.info.dataDir, entryPointArgs);
+ app.info.dataDir, refreshTheme, entryPointArgs);
checkTime(startTime, "startProcess: returned from zygote!");
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
@@ -3505,6 +3617,15 @@ public final class ActivityManagerService extends ActivityManagerNative
return true;
}
+ /**
+ * If system is power off alarm boot mode, we need to start alarm UI.
+ */
+ void startAlarmActivityLocked() {
+ Intent intent = new Intent(ACTION_POWER_OFF_ALARM);
+ intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+ mContext.startActivityAsUser(intent, UserHandle.CURRENT);
+ }
+
private ActivityInfo resolveActivityInfo(Intent intent, int flags, int userId) {
ActivityInfo ai = null;
ComponentName comp = intent.getComponent();
@@ -3888,7 +4009,8 @@ public final class ActivityManagerService extends ActivityManagerNative
if (sourceRecord == null) {
throw new SecurityException("Called with bad activity token: " + resultTo);
}
- if (!sourceRecord.info.packageName.equals("android")) {
+ if (!sourceRecord.info.packageName.equals("android") &&
+ !sourceRecord.info.packageName.equals("org.cyanogenmod.resolver")) {
throw new SecurityException(
"Must be called from an activity that is declared in the android package");
}
@@ -4094,8 +4216,8 @@ public final class ActivityManagerService extends ActivityManagerNative
if (debug) {
Slog.v(TAG, "Next matching activity: found current " + r.packageName
+ "/" + r.info.name);
- Slog.v(TAG, "Next matching activity: next is " + aInfo.packageName
- + "/" + aInfo.name);
+ Slog.v(TAG, "Next matching activity: next is " + ((aInfo == null)
+ ? "null" : aInfo.packageName + "/" + aInfo.name));
}
break;
}
@@ -4179,6 +4301,9 @@ public final class ActivityManagerService extends ActivityManagerNative
callingUid = task.mCallingUid;
callingPackage = task.mCallingPackage;
intent = task.intent;
+ if (task.origActivity != null) {
+ intent.setComponent(task.origActivity);
+ }
intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY);
userId = task.userId;
}
@@ -4714,7 +4839,12 @@ public final class ActivityManagerService extends ActivityManagerNative
app.thread.asBinder() == thread.asBinder()) {
boolean doLowMem = app.instrumentationClass == null;
boolean doOomAdj = doLowMem;
+ boolean homeRestart = false;
if (!app.killedByAm) {
+ if (mHomeProcessName != null && app.processName.equals(mHomeProcessName)) {
+ mHomeKilled = true;
+ homeRestart = true;
+ }
Slog.i(TAG, "Process " + app.processName + " (pid " + pid
+ ") has died");
mAllowLowerMemLevel = true;
@@ -4735,6 +4865,13 @@ public final class ActivityManagerService extends ActivityManagerNative
if (doLowMem) {
doLowMemReportIfNeededLocked(app);
}
+ if (mHomeKilled && homeRestart) {
+ Intent intent = getHomeIntent();
+ ActivityInfo aInfo = mStackSupervisor.resolveActivity(intent, null, 0, null, 0);
+ startProcessLocked(aInfo.processName, aInfo.applicationInfo, true, 0,
+ "activity", null, false, false, true);
+ homeRestart = false;
+ }
} else if (app.pid != pid) {
// A new process has already been started.
Slog.i(TAG, "Process " + app.processName + " (pid " + pid
@@ -4971,6 +5108,9 @@ public final class ActivityManagerService extends ActivityManagerNative
} else if (app.crashing) {
Slog.i(TAG, "Crashing app skipping ANR: " + app + " " + annotation);
return;
+ } else if (app.killedByAm) {
+ Slog.i(TAG, "App already killed by AM skipping ANR: " + app + " " + annotation);
+ return;
}
// In case we come through here for the same app before completing
@@ -5085,6 +5225,20 @@ public final class ActivityManagerService extends ActivityManagerNative
annotation != null ? "ANR " + annotation : "ANR",
info.toString());
+ //Set the trace file name to app name + current date format to avoid overrinding trace file
+ String tracesPath = SystemProperties.get("dalvik.vm.stack-trace-file", null);
+ if (tracesPath != null && tracesPath.length() != 0) {
+ File traceRenameFile = new File(tracesPath);
+ String newTracesPath;
+ int lpos = tracesPath.lastIndexOf (".");
+ if (-1 != lpos)
+ newTracesPath = tracesPath.substring (0, lpos) + "_" + app.processName + "_" + mTraceDateFormat.format(new Date()) + tracesPath.substring (lpos);
+ else
+ newTracesPath = tracesPath + "_" + app.processName;
+
+ traceRenameFile.renameTo(new File(newTracesPath));
+ }
+
// Bring up the infamous App Not Responding dialog
Message msg = Message.obtain();
HashMap<String, Object> map = new HashMap<String, Object>();
@@ -5107,7 +5261,7 @@ public final class ActivityManagerService extends ActivityManagerNative
@Override
public void run() {
synchronized (ActivityManagerService.this) {
- final Dialog d = new LaunchWarningWindow(mContext, cur, next);
+ final Dialog d = new LaunchWarningWindow(getUiContext(), cur, next);
d.show();
mUiHandler.postDelayed(new Runnable() {
@Override
@@ -6318,14 +6472,16 @@ public final class ActivityManagerService extends ActivityManagerNative
@Override
public void keyguardGoingAway(boolean disableWindowAnimations,
- boolean keyguardGoingToNotificationShade) {
+ boolean keyguardGoingToNotificationShade,
+ boolean keyguardShowingMedia) {
enforceNotIsolatedCaller("keyguardGoingAway");
final long token = Binder.clearCallingIdentity();
try {
synchronized (this) {
if (DEBUG_LOCKSCREEN) logLockScreen("");
mWindowManager.keyguardGoingAway(disableWindowAnimations,
- keyguardGoingToNotificationShade);
+ keyguardGoingToNotificationShade,
+ keyguardShowingMedia);
if (mLockScreenShown == LOCK_SCREEN_SHOWN) {
mLockScreenShown = LOCK_SCREEN_HIDDEN;
updateSleepIfNeededLocked();
@@ -6391,6 +6547,13 @@ public final class ActivityManagerService extends ActivityManagerNative
}
}, dumpheapFilter);
+ ThemeUtils.registerThemeChangeReceiver(mContext, new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ mUiContext = null;
+ }
+ });
+
// Let system services know.
mSystemServiceManager.startBootPhase(SystemService.PHASE_BOOT_COMPLETED);
@@ -6442,7 +6605,7 @@ public final class ActivityManagerService extends ActivityManagerNative
},
0, null, null,
new String[] {android.Manifest.permission.RECEIVE_BOOT_COMPLETED},
- AppOpsManager.OP_NONE, null, true, false,
+ AppOpsManager.OP_BOOT_COMPLETED, null, true, false,
MY_PID, Process.SYSTEM_UID, userId);
}
}
@@ -6582,6 +6745,18 @@ public final class ActivityManagerService extends ActivityManagerNative
}
}
+ public String getCallingPackageForBroadcast(boolean foreground) {
+ BroadcastQueue queue = foreground ? mFgBroadcastQueue : mBgBroadcastQueue;
+ BroadcastRecord r = queue.getProcessingBroadcast();
+ if (r != null) {
+ return r.callerPackage;
+ } else {
+ Log.e(TAG, "Broadcast sender is only retrievable in the onReceive");
+ }
+ return null;
+ }
+
+
private ActivityRecord getCallingRecordLocked(IBinder token) {
ActivityRecord r = ActivityRecord.isInStackLocked(token);
if (r == null) {
@@ -9536,6 +9711,7 @@ public final class ActivityManagerService extends ActivityManagerNative
checkTime(startTime, "getContentProviderImpl: incProviderCountLocked");
+ boolean importantCaller = false;
// In this case the provider instance already exists, so we can
// return it right away.
conn = incProviderCountLocked(r, cpr, token, stable);
@@ -9545,6 +9721,7 @@ public final class ActivityManagerService extends ActivityManagerNative
// make sure to count it as being accessed and thus
// back up on the LRU list. This is good because
// content providers are often expensive to start.
+ importantCaller = true;
checkTime(startTime, "getContentProviderImpl: before updateLruProcess");
updateLruProcessLocked(cpr.proc, false, null);
checkTime(startTime, "getContentProviderImpl: after updateLruProcess");
@@ -9557,36 +9734,37 @@ public final class ActivityManagerService extends ActivityManagerNative
"com.android.providers.calendar/.CalendarProvider2")) {
Slog.v(TAG, "****************** KILLING "
+ cpr.name.flattenToShortString());
- Process.killProcess(cpr.proc.pid);
+ cpr.proc.kill("test killing calendar provider", true);
}
}
- checkTime(startTime, "getContentProviderImpl: before updateOomAdj");
- boolean success = updateOomAdjLocked(cpr.proc);
- maybeUpdateProviderUsageStatsLocked(r, cpr.info.packageName, name);
- checkTime(startTime, "getContentProviderImpl: after updateOomAdj");
- if (DEBUG_PROVIDER) Slog.i(TAG_PROVIDER, "Adjust success: " + success);
- // NOTE: there is still a race here where a signal could be
- // pending on the process even though we managed to update its
- // adj level. Not sure what to do about this, but at least
- // the race is now smaller.
+
+ boolean success = !cpr.proc.killedByAm;
+ if (success) {
+ checkTime(startTime, "getContentProviderImpl: before updateOomAdj");
+ success = updateOomAdjLocked(cpr.proc);
+ maybeUpdateProviderUsageStatsLocked(r, cpr.info.packageName, name);
+ checkTime(startTime, "getContentProviderImpl: after updateOomAdj");
+ if (DEBUG_PROVIDER) Slog.i(TAG_PROVIDER, "Adjust success: " + success);
+ }
+
+ // There is still a race here where a signal could be pending on
+ // the process even though we managed to update its adj level.
+ // We check this case for perceptible app but exclude persistent
+ // because it should not be killed normally.
+ if (success && importantCaller && r != null && !r.persistent
+ && r.pid != cpr.proc.pid && !cpr.proc.persistent) {
+ success = ProcessList.isAlive(cpr.proc.pid, true);
+ }
+
if (!success) {
- // Uh oh... it looks like the provider's process
- // has been killed on us. We need to wait for a new
- // process to be started, and make sure its death
- // doesn't kill our process.
+ // It looks like the provider's process has been killed.
+ // We need to wait for a new process to be started,
+ // and make sure its death doesn't kill caller process.
Slog.i(TAG, "Existing provider " + cpr.name.flattenToShortString()
- + " is crashing; detaching " + r);
- boolean lastRef = decProviderCountLocked(conn, cpr, token, stable);
- checkTime(startTime, "getContentProviderImpl: before appDied");
- appDiedLocked(cpr.proc);
- checkTime(startTime, "getContentProviderImpl: after appDied");
- if (!lastRef) {
- // This wasn't the last ref our process had on
- // the provider... we have now been killed, bail.
- return null;
- }
- providerRunning = false;
- conn = null;
+ + " is gone; waiting it to restart for " + r);
+ cpr.provider = null;
+ cpr.launchingApp = cpr.proc;
+ mLaunchingProviders.add(cpr);
}
}
@@ -10252,7 +10430,13 @@ public final class ActivityManagerService extends ActivityManagerNative
if ((info.flags & PERSISTENT_MASK) == PERSISTENT_MASK) {
app.persistent = true;
- app.maxAdj = ProcessList.PERSISTENT_PROC_ADJ;
+
+ // The Adj score defines an order of processes to be killed.
+ // If a process is shared by multiple apps, maxAdj must be set by the highest
+ // prioritized app to avoid being killed.
+ if (app.maxAdj >= ProcessList.PERSISTENT_PROC_ADJ) {
+ app.maxAdj = ProcessList.PERSISTENT_PROC_ADJ;
+ }
}
if (app.thread == null && mPersistentStartingProcesses.indexOf(app) < 0) {
mPersistentStartingProcesses.add(app);
@@ -10690,6 +10874,7 @@ public final class ActivityManagerService extends ActivityManagerNative
public void requestBugReport() {
enforceCallingPermission(android.Manifest.permission.DUMP, "requestBugReport");
+ mContext.sendBroadcast(new Intent("android.intent.action.BUGREPORT_STARTED"));
SystemProperties.set("ctl.start", "bugreport");
}
@@ -10767,9 +10952,15 @@ public final class ActivityManagerService extends ActivityManagerNative
return true;
}
}
+ final int anrPid = proc.pid;
mHandler.post(new Runnable() {
@Override
public void run() {
+ if (anrPid != proc.pid) {
+ Slog.i(TAG, "Ignoring stale ANR (occurred in " + anrPid +
+ ", but current pid is " + proc.pid + ")");
+ return;
+ }
appNotResponding(proc, activity, parent, aboveSystem, annotation);
}
});
@@ -10989,6 +11180,18 @@ public final class ActivityManagerService extends ActivityManagerNative
enforceCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER,
"registerProcessObserver()");
synchronized (this) {
+ for (Integer key : mForegroundActivitiesList.keySet()) {
+ Object[] o = mForegroundActivitiesList.get(key);
+ if (o.length == 3) {
+ try {
+ observer.onForegroundActivitiesChanged((int) o[0],
+ (int) o[1], (boolean) o[2]);
+ } catch (RemoteException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+ }
mProcessObservers.register(observer);
}
}
@@ -11877,6 +12080,12 @@ public final class ActivityManagerService extends ActivityManagerNative
mBooting = true;
startHomeActivityLocked(mCurrentUserId, "systemReady");
+ // start the power off alarm by boot mode
+ boolean isAlarmBoot = SystemProperties.getBoolean("ro.alarm_boot", false);
+ if (isAlarmBoot) {
+ startAlarmActivityLocked();
+ }
+
try {
if (AppGlobals.getPackageManager().hasSystemUidErrors()) {
Slog.e(TAG, "UIDs on the system are inconsistent, you need to wipe your"
@@ -11992,6 +12201,28 @@ public final class ActivityManagerService extends ActivityManagerNative
}
}
+ private void sendAppFailureBroadcast(String pkgName) {
+ Intent intent = new Intent(Intent.ACTION_APP_FAILURE,
+ (pkgName != null)? Uri.fromParts("package", pkgName, null) : null);
+ mContext.sendBroadcastAsUser(intent, UserHandle.CURRENT_OR_SELF);
+ }
+
+ /**
+ * A possible theme crash is one that throws one of the following exceptions
+ * {@link android.content.res.Resources.NotFoundException}
+ * {@link android.view.InflateException}
+ *
+ * @param exceptionClassName
+ * @return True if exceptionClassName is one of the above exceptions
+ */
+ private boolean isPossibleThemeCrash(String exceptionClassName) {
+ if (Resources.NotFoundException.class.getName().equals(exceptionClassName) ||
+ InflateException.class.getName().equals(exceptionClassName)) {
+ return true;
+ }
+ return false;
+ }
+
private boolean handleAppCrashLocked(ProcessRecord app, String reason,
String shortMsg, String longMsg, String stackTrace) {
long now = SystemClock.uptimeMillis();
@@ -12002,6 +12233,9 @@ public final class ActivityManagerService extends ActivityManagerNative
} else {
crashTime = null;
}
+
+ if (isPossibleThemeCrash(shortMsg)) sendAppFailureBroadcast(app.info.packageName);
+
if (crashTime != null && now < crashTime+ProcessList.MIN_CRASH_INTERVAL) {
// This process loses!
Slog.w(TAG, "Process " + app.info.processName
@@ -12801,6 +13035,9 @@ public final class ActivityManagerService extends ActivityManagerNative
|| (!allUids && app.uid != callingUid)) {
continue;
}
+ if (app.processName.equals("system")) {
+ continue;
+ }
if ((app.thread != null) && (!app.crashing && !app.notResponding)) {
// Generate process state info for running application
ActivityManager.RunningAppProcessInfo currApp =
@@ -15652,6 +15889,7 @@ public final class ActivityManagerService extends ActivityManagerNative
mProcessesOnHold.remove(app);
if (app == mHomeProcess) {
+ mHomeProcessName = mHomeProcess.processName;
mHomeProcess = null;
}
if (app == mPreviousProcess) {
@@ -17307,6 +17545,9 @@ public final class ActivityManagerService extends ActivityManagerNative
synchronized(this) {
ci = new Configuration(mConfiguration);
ci.userSetLocale = false;
+ if (ci.themeConfig == null) {
+ ci.themeConfig = ThemeConfig.getBootTheme(mContext.getContentResolver());
+ }
}
return ci;
}
@@ -17396,6 +17637,11 @@ public final class ActivityManagerService extends ActivityManagerNative
values.locale));
}
+ if (values.themeConfig != null) {
+ saveThemeResourceLocked(values.themeConfig,
+ !values.themeConfig.equals(mConfiguration.themeConfig));
+ }
+
mConfigurationSeq++;
if (mConfigurationSeq <= 0) {
mConfigurationSeq = 1;
@@ -17451,6 +17697,10 @@ public final class ActivityManagerService extends ActivityManagerNative
null, AppOpsManager.OP_NONE, null, false, false,
MY_PID, Process.SYSTEM_UID, UserHandle.USER_ALL);
if ((changes&ActivityInfo.CONFIG_LOCALE) != 0) {
+ // if locale changed, time format may have changed
+ final int is24Hour = android.text.format.DateFormat.is24HourFormat(mContext) ? 1 : 0;
+ mHandler.sendMessage(mHandler.obtainMessage(UPDATE_TIME, is24Hour, 0));
+ // now send general broadcast
intent = new Intent(Intent.ACTION_LOCALE_CHANGED);
intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
if (!mProcessesReady) {
@@ -17548,6 +17798,14 @@ public final class ActivityManagerService extends ActivityManagerNative
return srec.launchedFromPackage;
}
+ private void saveThemeResourceLocked(ThemeConfig t, boolean isDiff){
+ if(isDiff) {
+ Settings.Secure.putStringForUser(mContext.getContentResolver(),
+ Configuration.THEME_PKG_CONFIGURATION_PERSISTENCE_PROPERTY, t.toJson(),
+ UserHandle.USER_CURRENT);
+ }
+ }
+
// =========================================================
// LIFETIME MANAGEMENT
// =========================================================
@@ -17707,6 +17965,10 @@ public final class ActivityManagerService extends ActivityManagerNative
app.adjType = "top-activity";
foregroundActivities = true;
procState = PROCESS_STATE_TOP;
+ if(app == mHomeProcess) {
+ mHomeKilled = false;
+ mHomeProcessName = mHomeProcess.processName;
+ }
} else if (app.instrumentationClass != null) {
// Don't want to kill running instrumentation.
adj = ProcessList.FOREGROUND_APP_ADJ;
@@ -17742,6 +18004,14 @@ public final class ActivityManagerService extends ActivityManagerNative
app.cached = true;
app.empty = true;
app.adjType = "cch-empty";
+
+ if (mHomeKilled && app.processName.equals(mHomeProcessName)) {
+ adj = ProcessList.PERSISTENT_PROC_ADJ;
+ schedGroup = Process.THREAD_GROUP_DEFAULT;
+ app.cached = false;
+ app.empty = false;
+ app.adjType = "top-activity";
+ }
}
// Examine all activities if not already foreground.
@@ -18665,6 +18935,18 @@ public final class ActivityManagerService extends ActivityManagerNative
boolean success = true;
if (app.curRawAdj != app.setRawAdj) {
+ String seempStr = "app_uid=" + app.uid
+ + ",app_pid=" + app.pid + ",oom_adj=" + app.curAdj
+ + ",setAdj=" + app.setAdj + ",hasShownUi=" + (app.hasShownUi ? 1 : 0)
+ + ",cached=" + (app.cached ? 1 : 0)
+ + ",fA=" + (app.foregroundActivities ? 1 : 0)
+ + ",fS=" + (app.foregroundServices ? 1 : 0)
+ + ",systemNoUi=" + (app.systemNoUi ? 1 : 0)
+ + ",curSchedGroup=" + app.curSchedGroup
+ + ",curProcState=" + app.curProcState + ",setProcState=" + app.setProcState
+ + ",killed=" + (app.killed ? 1 : 0) + ",killedByAm=" + (app.killedByAm ? 1 : 0)
+ + ",debugging=" + (app.debugging ? 1 : 0);
+ android.util.SeempLog.record_str(385, seempStr);
app.setRawAdj = app.curRawAdj;
}
@@ -18840,6 +19122,12 @@ public final class ActivityManagerService extends ActivityManagerNative
item.changes |= changes;
item.processState = app.repProcState;
item.foregroundActivities = app.repForegroundActivities;
+ if (item.foregroundActivities) {
+ Object[] o = new Object[]{item.pid, item.uid, item.foregroundActivities};
+ mForegroundActivitiesList.put(item.pid, o);
+ } else if (!item.foregroundActivities && mForegroundActivitiesList.get(item.pid) != null) {
+ mForegroundActivitiesList.remove(item.pid);
+ }
if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
"Item " + Integer.toHexString(System.identityHashCode(item))
+ " " + app.toShortString() + ": changes=" + item.changes
@@ -19119,8 +19407,39 @@ public final class ActivityManagerService extends ActivityManagerNative
int nextCachedAdj = curCachedAdj+1;
int curEmptyAdj = ProcessList.CACHED_APP_MIN_ADJ;
int nextEmptyAdj = curEmptyAdj+2;
+ ProcessRecord selectedAppRecord = null;
+ long serviceLastActivity = 0;
+ int numBServices = 0;
for (int i=N-1; i>=0; i--) {
ProcessRecord app = mLruProcesses.get(i);
+ if (mEnableBServicePropagation && app.serviceb
+ && (app.curAdj == ProcessList.SERVICE_B_ADJ)) {
+ numBServices++;
+ for (int s = app.services.size() - 1; s >= 0; s--) {
+ ServiceRecord sr = app.services.valueAt(s);
+ if (DEBUG_OOM_ADJ) Slog.d(TAG,"app.processName = " + app.processName
+ + " serviceb = " + app.serviceb + " s = " + s + " sr.lastActivity = "
+ + sr.lastActivity + " packageName = " + sr.packageName
+ + " processName = " + sr.processName);
+ if (SystemClock.uptimeMillis() - sr.lastActivity
+ < mMinBServiceAgingTime) {
+ if (DEBUG_OOM_ADJ) {
+ Slog.d(TAG,"Not aged enough!!!");
+ }
+ continue;
+ }
+ if (serviceLastActivity == 0) {
+ serviceLastActivity = sr.lastActivity;
+ selectedAppRecord = app;
+ } else if (sr.lastActivity < serviceLastActivity) {
+ serviceLastActivity = sr.lastActivity;
+ selectedAppRecord = app;
+ }
+ }
+ }
+ if (DEBUG_OOM_ADJ && selectedAppRecord != null) Slog.d(TAG,
+ "Identified app.processName = " + selectedAppRecord.processName
+ + " app.pid = " + selectedAppRecord.pid);
if (!app.killedByAm && app.thread != null) {
app.procStateChanged = false;
computeOomAdjLocked(app, ProcessList.UNKNOWN_ADJ, TOP_APP, true, now);
@@ -19229,6 +19548,14 @@ public final class ActivityManagerService extends ActivityManagerNative
}
}
}
+ if ((numBServices > mBServiceAppThreshold) && (true == mAllowLowerMemLevel)
+ && (selectedAppRecord != null)) {
+ ProcessList.setOomAdj(selectedAppRecord.pid, selectedAppRecord.info.uid,
+ ProcessList.CACHED_APP_MAX_ADJ);
+ selectedAppRecord.setAdj = selectedAppRecord.curAdj;
+ if (DEBUG_OOM_ADJ) Slog.d(TAG,"app.processName = " + selectedAppRecord.processName
+ + " app.pid = " + selectedAppRecord.pid + " is moved to higher adj");
+ }
mNumServiceProcs = mNewNumServiceProcs;
@@ -20245,7 +20572,7 @@ public final class ActivityManagerService extends ActivityManagerNative
broadcastIntentLocked(null, null, intent,
null, null, 0, null, null,
new String[] {android.Manifest.permission.RECEIVE_BOOT_COMPLETED},
- AppOpsManager.OP_NONE, null, true, false, MY_PID, Process.SYSTEM_UID,
+ AppOpsManager.OP_BOOT_COMPLETED, null, true, false, MY_PID, Process.SYSTEM_UID,
userId);
}
}
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 6e34876..cc86695 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -40,6 +40,7 @@ import android.app.Activity;
import android.app.ActivityManager;
import android.app.ActivityOptions;
import android.app.AppGlobals;
+import android.app.AppOpsManager;
import android.app.IActivityController;
import android.app.ResultInfo;
import android.app.ActivityManager.RunningTaskInfo;
@@ -67,6 +68,10 @@ import android.util.EventLog;
import android.util.Slog;
import android.view.Display;
+import com.android.server.LocalServices;
+
+import cyanogenmod.power.PerformanceManagerInternal;
+
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.lang.ref.WeakReference;
@@ -264,6 +269,8 @@ final class ActivityStack {
}
}
+ private final PerformanceManagerInternal mPerf;
+
final Handler mHandler;
final class ActivityStackHandler extends Handler {
@@ -362,6 +369,7 @@ final class ActivityStack {
mCurrentUser = mService.mCurrentUserId;
mRecentTasks = recentTasks;
mOverrideConfig = Configuration.EMPTY;
+ mPerf = LocalServices.getService(PerformanceManagerInternal.class);
}
boolean okToShowLocked(ActivityRecord r) {
@@ -941,10 +949,13 @@ final class ActivityStack {
r.userId, System.identityHashCode(r), r.shortComponentName,
mPausingActivity != null
? mPausingActivity.shortComponentName : "(none)");
- if (r.finishing && r.state == ActivityState.PAUSING) {
- if (DEBUG_PAUSE) Slog.v(TAG,
- "Executing finish of failed to pause activity: " + r);
- finishCurrentActivityLocked(r, FINISH_AFTER_VISIBLE, false);
+ if (r.state == ActivityState.PAUSING) {
+ r.state = ActivityState.PAUSED;
+ if (r.finishing) {
+ if (DEBUG_PAUSE) Slog.v(TAG,
+ "Executing finish of failed to pause activity: " + r);
+ finishCurrentActivityLocked(r, FINISH_AFTER_VISIBLE, false);
+ }
}
}
}
@@ -1130,6 +1141,8 @@ final class ActivityStack {
// When resuming an activity, require it to call requestVisibleBehind() again.
mActivityContainer.mActivityDisplay.setVisibleBehindActivity(null);
}
+
+ updatePrivacyGuardNotificationLocked(next);
}
private void setVisible(ActivityRecord r, boolean visible) {
@@ -1682,6 +1695,11 @@ final class ActivityStack {
if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Resuming " + next);
+ // Some activities may want to alter the system power management
+ if (mStackSupervisor.mPerf != null) {
+ mStackSupervisor.mPerf.activityResumed(next.intent);
+ }
+
// If we are currently pausing an activity, then don't do anything
// until that is done.
if (!mStackSupervisor.allPausedActivitiesComplete()) {
@@ -1814,6 +1832,11 @@ final class ActivityStack {
mWindowManager.prepareAppTransition(prev.task == next.task
? AppTransition.TRANSIT_ACTIVITY_CLOSE
: AppTransition.TRANSIT_TASK_CLOSE, false);
+ if (prev.task != next.task) {
+ if (mStackSupervisor.mPerf != null) {
+ mStackSupervisor.mPerf.cpuBoost(2000 * 1000);
+ }
+ }
}
mWindowManager.setAppWillBeHidden(prev.appToken);
mWindowManager.setAppVisibility(prev.appToken, false);
@@ -1829,6 +1852,11 @@ final class ActivityStack {
: next.mLaunchTaskBehind
? AppTransition.TRANSIT_TASK_OPEN_BEHIND
: AppTransition.TRANSIT_TASK_OPEN, false);
+ if (prev.task != next.task) {
+ if (mStackSupervisor.mPerf != null) {
+ mStackSupervisor.mPerf.cpuBoost(2000 * 1000);
+ }
+ }
}
}
if (false) {
@@ -2071,6 +2099,29 @@ final class ActivityStack {
updateTaskMovement(task, true);
}
+ private final void updatePrivacyGuardNotificationLocked(ActivityRecord next) {
+
+ String privacyGuardPackageName = mStackSupervisor.mPrivacyGuardPackageName;
+ if (privacyGuardPackageName != null && privacyGuardPackageName.equals(next.packageName)) {
+ return;
+ }
+
+ boolean privacy = mService.mAppOpsService.getPrivacyGuardSettingForPackage(
+ next.app.uid, next.packageName);
+
+ if (privacyGuardPackageName != null && !privacy) {
+ Message msg = mService.mHandler.obtainMessage(
+ ActivityManagerService.CANCEL_PRIVACY_NOTIFICATION_MSG, next.userId);
+ msg.sendToTarget();
+ mStackSupervisor.mPrivacyGuardPackageName = null;
+ } else if (privacy) {
+ Message msg = mService.mHandler.obtainMessage(
+ ActivityManagerService.POST_PRIVACY_NOTIFICATION_MSG, next);
+ msg.sendToTarget();
+ mStackSupervisor.mPrivacyGuardPackageName = next.packageName;
+ }
+ }
+
final void startActivityLocked(ActivityRecord r, boolean newTask,
boolean doResume, boolean keepCurTransition, Bundle options) {
TaskRecord rTask = r.task;
@@ -2620,7 +2671,23 @@ final class ActivityStack {
final String myReason = reason + " adjustFocus";
if (next != r) {
final TaskRecord task = r.task;
- if (r.frontOfTask && task == topTask() && task.isOverHomeStack()) {
+ boolean adjust = false;
+ if ((next == null || next.task != task) && r.frontOfTask) {
+ if (task.isOverHomeStack() && task == topTask()) {
+ adjust = true;
+ } else {
+ for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
+ final TaskRecord tr = mTaskHistory.get(taskNdx);
+ if (tr.getTopActivity() != null) {
+ break;
+ } else if (tr.isOverHomeStack()) {
+ adjust = true;
+ break;
+ }
+ }
+ }
+ }
+ if (adjust) {
// For non-fullscreen stack, we want to move the focus to the next visible
// stack to prevent the home screen from moving to the top and obscuring
// other visible stacks.
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 17a86ca..be90dc8 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -101,12 +101,12 @@ import android.util.ArraySet;
import android.util.EventLog;
import android.util.Slog;
import android.util.SparseArray;
-
import android.util.SparseIntArray;
import android.view.Display;
import android.view.DisplayInfo;
import android.view.InputEvent;
import android.view.Surface;
+
import com.android.internal.app.HeavyWeightSwitcherActivity;
import com.android.internal.app.IVoiceInteractor;
import com.android.internal.content.ReferrerIntent;
@@ -118,6 +118,7 @@ import com.android.server.LocalServices;
import com.android.server.am.ActivityStack.ActivityState;
import com.android.server.wm.WindowManagerService;
+import cyanogenmod.power.PerformanceManagerInternal;
import java.io.FileDescriptor;
import java.io.IOException;
@@ -273,6 +274,15 @@ public final class ActivityStackSupervisor implements DisplayListener {
* setWindowManager is called. **/
private boolean mLeanbackOnlyDevice;
+ PowerManager mPm;
+
+ PerformanceManagerInternal mPerf;
+
+ /**
+ * Is the privacy guard currently enabled? Shared between ActivityStacks
+ */
+ String mPrivacyGuardPackageName = null;
+
/**
* We don't want to allow the device to go to sleep while in the process
* of launching an activity. This is primarily to allow alarm intent
@@ -344,14 +354,25 @@ public final class ActivityStackSupervisor implements DisplayListener {
mHandler = new ActivityStackSupervisorHandler(mService.mHandler.getLooper());
}
+ private void launchBoost() {
+ if (mPerf == null) {
+ mPerf = LocalServices.getService(PerformanceManagerInternal.class);
+ }
+ if (mPerf == null) {
+ Slog.e(TAG, "PerformanceManager not ready!");
+ } else {
+ mPerf.launchBoost();
+ }
+ }
+
/**
* At the time when the constructor runs, the power manager has not yet been
* initialized. So we initialize our wakelocks afterwards.
*/
void initPowerManagement() {
- PowerManager pm = (PowerManager)mService.mContext.getSystemService(Context.POWER_SERVICE);
- mGoingToSleep = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Sleep");
- mLaunchingActivity = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*launch*");
+ mPm = (PowerManager)mService.mContext.getSystemService(Context.POWER_SERVICE);
+ mGoingToSleep = mPm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Sleep");
+ mLaunchingActivity = mPm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*launch*");
mLaunchingActivity.setReferenceCounted(false);
}
@@ -511,7 +532,8 @@ public final class ActivityStackSupervisor implements DisplayListener {
mHomeStack.moveHomeStackTaskToTop(homeStackTaskType);
ActivityRecord r = getHomeActivity();
- if (r != null) {
+ // Only resume home activity if isn't finishing.
+ if (r != null && !r.finishing) {
mService.setFocusedActivityLocked(r, reason);
return resumeTopActivitiesLocked(mHomeStack, prev, null);
}
@@ -1429,6 +1451,8 @@ public final class ActivityStackSupervisor implements DisplayListener {
Display.DEFAULT_DISPLAY : mFocusedStack.mDisplayId) :
(container.mActivityDisplay == null ? Display.DEFAULT_DISPLAY :
container.mActivityDisplay.mDisplayId)));
+ /* Acquire perf lock during new app launch */
+ launchBoost();
}
ActivityRecord sourceRecord = null;
@@ -1481,6 +1505,11 @@ public final class ActivityStackSupervisor implements DisplayListener {
if (err == ActivityManager.START_SUCCESS && intent.getComponent() == null) {
// We couldn't find a class that can handle the given Intent.
// That's the end of that!
+ final Uri data = intent.getData();
+ final String strData = data != null ? data.toSafeString() : null;
+ EventLog.writeEvent(EventLogTags.AM_INTENT_NOT_RESOLVED, callingPackage,
+ intent.getAction(), intent.getType(), strData, intent.getFlags());
+
err = ActivityManager.START_INTENT_NOT_RESOLVED;
}
@@ -2674,8 +2703,7 @@ public final class ActivityStackSupervisor implements DisplayListener {
boolean didSomething = false;
for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
- final int numStacks = stacks.size();
- for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
+ for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
final ActivityStack stack = stacks.get(stackNdx);
if (stack.finishDisabledPackageActivitiesLocked(
packageName, filterByClasses, doit, evenPersistent, userId)) {
@@ -2774,6 +2802,12 @@ public final class ActivityStackSupervisor implements DisplayListener {
}
void findTaskToMoveToFrontLocked(TaskRecord task, int flags, Bundle options, String reason) {
+ ActivityRecord top = task.stack.topRunningActivityLocked(null);
+ /* App is launching from recent apps and it's a new process */
+ if(top != null && top.state == ActivityState.DESTROYED) {
+ launchBoost();
+ }
+
if ((flags & ActivityManager.MOVE_TASK_NO_USER_ACTION) == 0) {
mUserLeaving = true;
}
@@ -3055,11 +3089,16 @@ public final class ActivityStackSupervisor implements DisplayListener {
}
final ActivityRecord ar = stack.findTaskLocked(r);
if (ar != null) {
+ if (ar.state == ActivityState.DESTROYED) {
+ launchBoost();
+ }
return ar;
}
}
}
if (DEBUG_TASKS) Slog.d(TAG_TASKS, "No task found");
+ launchBoost();
+
return null;
}
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index 6de8579..589a4b8 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -142,6 +142,11 @@ public final class BroadcastQueue {
*/
BroadcastRecord mPendingBroadcast = null;
+ /**
+ * Intent broadcast that we are currently processing
+ */
+ BroadcastRecord mCurrentBroadcast = null;
+
/**
* The receiver index that is pending, to restart the broadcast if needed.
*/
@@ -636,6 +641,10 @@ public final class BroadcastQueue {
.sendToTarget();
}
+ BroadcastRecord getProcessingBroadcast() {
+ return mCurrentBroadcast;
+ }
+
final void processNextBroadcast(boolean fromMsg) {
synchronized(mService) {
BroadcastRecord r;
@@ -656,6 +665,7 @@ public final class BroadcastQueue {
r = mParallelBroadcasts.remove(0);
r.dispatchTime = SystemClock.uptimeMillis();
r.dispatchClockTime = System.currentTimeMillis();
+ mCurrentBroadcast = r;
final int N = r.receivers.size();
if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST, "Processing parallel broadcast ["
+ mQueueName + "] " + r);
@@ -669,6 +679,7 @@ public final class BroadcastQueue {
addBroadcastToHistoryLocked(r);
if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST, "Done with parallel broadcast ["
+ mQueueName + "] " + r);
+ mCurrentBroadcast = null;
}
// Now take care of the next serialized one...
@@ -714,6 +725,7 @@ public final class BroadcastQueue {
return;
}
r = mOrderedBroadcasts.get(0);
+ mCurrentBroadcast = r;
boolean forceReceive = false;
// Ensure that even if something goes awry with the timeout
@@ -784,6 +796,7 @@ public final class BroadcastQueue {
// ... and on to the next...
addBroadcastToHistoryLocked(r);
mOrderedBroadcasts.remove(0);
+ mCurrentBroadcast = null;
r = null;
looped = true;
continue;
diff --git a/services/core/java/com/android/server/am/EventLogTags.logtags b/services/core/java/com/android/server/am/EventLogTags.logtags
index 9a645df..33fa714 100644
--- a/services/core/java/com/android/server/am/EventLogTags.logtags
+++ b/services/core/java/com/android/server/am/EventLogTags.logtags
@@ -78,6 +78,8 @@ option java_package com.android.server.am
30036 am_provider_lost_process (User|1|5),(Package Name|3),(UID|1|5),(Name|3)
# The activity manager gave up on a new process taking too long to start
30037 am_process_start_timeout (User|1|5),(PID|1|5),(UID|1|5),(Process Name|3)
+# The activity manager was unable to resolve the intent to an Activity
+30038 am_intent_not_resolved (Calling Package Name|3),(Action|3),(MIME Type|3),(URI|3),(Flags|1|5)
# Unhandled exception
30039 am_crash (User|1|5),(PID|1|5),(Process Name|3),(Flags|1|5),(Exception|3),(Message|3),(File|3),(Line|1|5)
diff --git a/services/core/java/com/android/server/am/LockTaskNotify.java b/services/core/java/com/android/server/am/LockTaskNotify.java
index afde322..d1917db 100644
--- a/services/core/java/com/android/server/am/LockTaskNotify.java
+++ b/services/core/java/com/android/server/am/LockTaskNotify.java
@@ -20,7 +20,10 @@ import android.app.ActivityManager;
import android.content.Context;
import android.os.Handler;
import android.os.Message;
+import android.os.RemoteException;
+import android.view.IWindowManager;
import android.view.WindowManager;
+import android.view.WindowManagerGlobal;
import android.view.accessibility.AccessibilityManager;
import android.widget.Toast;
@@ -37,12 +40,23 @@ public class LockTaskNotify {
private final H mHandler;
private AccessibilityManager mAccessibilityManager;
private Toast mLastToast;
+ private final IWindowManager mWindowManagerService;
public LockTaskNotify(Context context) {
mContext = context;
mAccessibilityManager = (AccessibilityManager)
mContext.getSystemService(Context.ACCESSIBILITY_SERVICE);
mHandler = new H();
+ mWindowManagerService = WindowManagerGlobal.getWindowManagerService();
+ }
+
+ private boolean hasNavigationBar() {
+ try {
+ return mWindowManagerService.hasNavigationBar();
+ } catch (RemoteException e) {
+ //ignore
+ }
+ return false;
}
public void showToast(int lockTaskModeState) {
@@ -50,20 +64,20 @@ public class LockTaskNotify {
}
public void handleShowToast(int lockTaskModeState) {
- String text = null;
+ final int textResId;
if (lockTaskModeState == ActivityManager.LOCK_TASK_MODE_LOCKED) {
- text = mContext.getString(R.string.lock_to_app_toast_locked);
+ textResId = R.string.lock_to_app_toast_locked;
} else if (lockTaskModeState == ActivityManager.LOCK_TASK_MODE_PINNED) {
- text = mContext.getString(mAccessibilityManager.isEnabled()
- ? R.string.lock_to_app_toast_accessible : R.string.lock_to_app_toast);
- }
- if (text == null) {
- return;
+ textResId = mAccessibilityManager.isEnabled()
+ ? R.string.lock_to_app_toast_accessible : R.string.lock_to_app_toast;
+ } else {
+ textResId = hasNavigationBar()
+ ? R.string.lock_to_app_toast : R.string.lock_to_app_toast_no_navbar;
}
if (mLastToast != null) {
mLastToast.cancel();
}
- mLastToast = makeAllUserToastAndShow(text);
+ mLastToast = makeAllUserToastAndShow(mContext.getString(textResId));
}
public void show(boolean starting) {
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 0e24952..9c9a421 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -32,6 +32,7 @@ import com.android.server.wm.WindowManagerService;
import android.content.res.Resources;
import android.graphics.Point;
import android.os.SystemProperties;
+import android.os.Process;
import android.net.LocalSocketAddress;
import android.net.LocalSocket;
import android.util.Slog;
@@ -133,7 +134,17 @@ final class ProcessList {
// we have no limit on the number of service, visible, foreground, or other such
// processes and the number of those processes does not count against the cached
// process limit.
- static final int MAX_CACHED_APPS = 32;
+ static final int MAX_CACHED_APPS = SystemProperties.getInt("ro.sys.fw.bg_apps_limit",32);
+ static final boolean USE_TRIM_SETTINGS =
+ SystemProperties.getBoolean("ro.sys.fw.use_trim_settings",false);
+ static final int EMPTY_APP_PERCENT = SystemProperties.getInt("ro.sys.fw.empty_app_percent",50);
+ static final int TRIM_EMPTY_PERCENT =
+ SystemProperties.getInt("ro.sys.fw.trim_empty_percent",100);
+ static final int TRIM_CACHE_PERCENT =
+ SystemProperties.getInt("ro.sys.fw.trim_cache_percent",100);
+ static final long TRIM_ENABLE_MEMORY =
+ SystemProperties.getLong("ro.sys.fw.trim_enable_memory",1073741824);
+ public static boolean allowTrim() { return Process.getTotalMemory() < TRIM_ENABLE_MEMORY ; }
// We allow empty processes to stick around for at most 30 minutes.
static final long MAX_EMPTY_TIME = 30*60*1000;
@@ -143,11 +154,25 @@ final class ProcessList {
// The number of empty apps at which we don't consider it necessary to do
// memory trimming.
- static final int TRIM_EMPTY_APPS = MAX_EMPTY_APPS/2;
+ public static int computeTrimEmptyApps() {
+ if (USE_TRIM_SETTINGS && allowTrim()) {
+ return MAX_EMPTY_APPS*TRIM_EMPTY_PERCENT/100;
+ } else {
+ return MAX_EMPTY_APPS/2;
+ }
+ }
+ static final int TRIM_EMPTY_APPS = computeTrimEmptyApps();
// The number of cached at which we don't consider it necessary to do
// memory trimming.
- static final int TRIM_CACHED_APPS = (MAX_CACHED_APPS-MAX_EMPTY_APPS)/3;
+ public static int computeTrimCachedApps() {
+ if (USE_TRIM_SETTINGS && allowTrim()) {
+ return MAX_CACHED_APPS*TRIM_CACHE_PERCENT/100;
+ } else {
+ return (MAX_CACHED_APPS-MAX_EMPTY_APPS)/3;
+ }
+ }
+ static final int TRIM_CACHED_APPS = computeTrimCachedApps();
// Threshold of number of cached+empty where we consider memory critical.
static final int TRIM_CRITICAL_THRESHOLD = 3;
@@ -172,6 +197,17 @@ final class ProcessList {
FOREGROUND_APP_ADJ, VISIBLE_APP_ADJ, PERCEPTIBLE_APP_ADJ,
BACKUP_APP_ADJ, CACHED_APP_MIN_ADJ, CACHED_APP_MAX_ADJ
};
+
+ // These are the low-end OOM level limits for 32bit 1 GB RAM
+ private final int[] mOomMinFreeLow32Bit = new int[] {
+ 12288, 18432, 24576,
+ 36864, 43008, 49152
+ };
+ // These are the high-end OOM level limits for 32bit 1 GB RAM
+ private final int[] mOomMinFreeHigh32Bit = new int[] {
+ 61440, 76800, 92160,
+ 107520, 137660, 174948
+ };
// These are the low-end OOM level limits. This is appropriate for an
// HVGA or smaller phone with less than 512MB. Values are in KB.
private final int[] mOomMinFreeLow = new int[] {
@@ -240,15 +276,24 @@ final class ProcessList {
Slog.i("XXXXXX", "minfree_adj=" + minfree_adj + " minfree_abs=" + minfree_abs);
}
+ // We've now baked in the increase to the basic oom values above, since
+ // they seem to be useful more generally for devices that are tight on
+ // memory than just for 64 bit. This should probably have some more
+ // tuning done, so not deleting it quite yet...
final boolean is64bit = Build.SUPPORTED_64_BIT_ABIS.length > 0;
for (int i=0; i<mOomAdj.length; i++) {
int low = mOomMinFreeLow[i];
int high = mOomMinFreeHigh[i];
if (is64bit) {
+ Slog.i("XXXXXX", "choosing minFree values for 64 Bit");
// Increase the high min-free levels for cached processes for 64-bit
if (i == 4) high = (high*3)/2;
else if (i == 5) high = (high*7)/4;
+ } else {
+ Slog.i("XXXXXX", "choosing minFree values for 32 Bit");
+ low = mOomMinFreeLow32Bit[i];
+ high = mOomMinFreeHigh32Bit[i];
}
mOomMinFree[i] = (int)(low + ((high-low)*scale));
}
@@ -308,7 +353,11 @@ final class ProcessList {
}
public static int computeEmptyProcessLimit(int totalProcessLimit) {
- return totalProcessLimit/2;
+ if(USE_TRIM_SETTINGS && allowTrim()) {
+ return totalProcessLimit*EMPTY_APP_PERCENT/100;
+ } else {
+ return totalProcessLimit/2;
+ }
}
private static String buildOomTag(String prefix, String space, int val, int base) {
@@ -671,16 +720,15 @@ final class ProcessList {
}
private static void writeLmkd(ByteBuffer buf) {
-
for (int i = 0; i < 3; i++) {
if (sLmkdSocket == null) {
- if (openLmkdSocket() == false) {
- try {
- Thread.sleep(1000);
- } catch (InterruptedException ie) {
- }
- continue;
+ if (openLmkdSocket() == false) {
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException ie) {
}
+ continue;
+ }
}
try {
@@ -698,4 +746,55 @@ final class ProcessList {
}
}
}
+
+ private static final int[] PROCESS_STATS_FORMAT;
+ static {
+ PROCESS_STATS_FORMAT = new int[31];
+ java.util.Arrays.fill(PROCESS_STATS_FORMAT, android.os.Process.PROC_SPACE_TERM);
+ // Process name enclosed in parentheses
+ PROCESS_STATS_FORMAT[1] |= android.os.Process.PROC_PARENS;
+ // Process state (D/R/S/T/Z)
+ PROCESS_STATS_FORMAT[2] |= android.os.Process.PROC_OUT_STRING;
+ // Bit mask of pending signals
+ PROCESS_STATS_FORMAT[30] |= android.os.Process.PROC_OUT_STRING;
+ }
+
+ static boolean isAlive(int pid, boolean noisy) {
+ final String[] procStats = new String[2];
+ final String stat = "/proc/" + pid + "/stat";
+ if (android.os.Process.readProcFile(stat, PROCESS_STATS_FORMAT,
+ procStats, null, null)) {
+ if ("Z".equals(procStats[0])) {
+ if (noisy) {
+ Slog.i(TAG, pid + " is zombie state");
+ }
+ return false;
+ }
+ try {
+ int pendingSignals = Integer.parseInt(procStats[1]);
+ if ((pendingSignals & (1 << 8)) != 0) {
+ if (noisy) {
+ Slog.i(TAG, pid + " has pending signal 9");
+ }
+ return false;
+ }
+ } catch (NumberFormatException e) {
+ Slog.w(TAG, "Unknown pending signals " + procStats[1] + " of " + pid);
+ }
+ } else {
+ boolean exists = false;
+ try {
+ exists = libcore.io.Libcore.os.access(stat, android.system.OsConstants.F_OK);
+ } catch (android.system.ErrnoException e) {
+ exists = e.errno != android.system.OsConstants.ENOENT;
+ }
+ if (!exists) {
+ if (noisy) {
+ Slog.i(TAG, stat + " does not exist");
+ }
+ return false;
+ }
+ }
+ return true;
+ }
}
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index 697b4e2..9cab95b 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -432,6 +432,18 @@ final class ProcessRecord {
}
public void makeActive(IApplicationThread _thread, ProcessStatsService tracker) {
+ String seempStr = "app_uid=" + uid
+ + ",app_pid=" + pid + ",oom_adj=" + curAdj
+ + ",setAdj=" + setAdj + ",hasShownUi=" + (hasShownUi ? 1 : 0)
+ + ",cached=" + (cached ? 1 : 0)
+ + ",fA=" + (foregroundActivities ? 1 : 0)
+ + ",fS=" + (foregroundServices ? 1 : 0)
+ + ",systemNoUi=" + (systemNoUi ? 1 : 0)
+ + ",curSchedGroup=" + curSchedGroup
+ + ",curProcState=" + curProcState + ",setProcState=" + setProcState
+ + ",killed=" + (killed ? 1 : 0) + ",killedByAm=" + (killedByAm ? 1 : 0)
+ + ",debugging=" + (debugging ? 1 : 0);
+ android.util.SeempLog.record_str(386, seempStr);
if (thread == null) {
final ProcessStats.ProcessState origBase = baseProcessTracker;
if (origBase != null) {
@@ -458,6 +470,18 @@ final class ProcessRecord {
}
public void makeInactive(ProcessStatsService tracker) {
+ String seempStr = "app_uid=" + uid
+ + ",app_pid=" + pid + ",oom_adj=" + curAdj
+ + ",setAdj=" + setAdj + ",hasShownUi=" + (hasShownUi ? 1 : 0)
+ + ",cached=" + (cached ? 1 : 0)
+ + ",fA=" + (foregroundActivities ? 1 : 0)
+ + ",fS=" + (foregroundServices ? 1 : 0)
+ + ",systemNoUi=" + (systemNoUi ? 1 : 0)
+ + ",curSchedGroup=" + curSchedGroup
+ + ",curProcState=" + curProcState + ",setProcState=" + setProcState
+ + ",killed=" + (killed ? 1 : 0) + ",killedByAm=" + (killedByAm ? 1 : 0)
+ + ",debugging=" + (debugging ? 1 : 0);
+ android.util.SeempLog.record_str(387, seempStr);
thread = null;
final ProcessStats.ProcessState origBase = baseProcessTracker;
if (origBase != null) {
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 152ff30..c7e08bb 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -59,6 +59,7 @@ import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioManagerInternal;
import android.media.AudioPort;
+import android.media.AudioRecord;
import android.media.AudioRoutesInfo;
import android.media.IAudioFocusDispatcher;
import android.media.IAudioRoutesObserver;
@@ -171,6 +172,27 @@ public class AudioService extends IAudioService.Stub {
// the platform type affects volume and silent mode behavior
private final int mPlatformType;
+ private static final ArrayList<MediaPlayerInfo> mMediaPlayers =
+ new ArrayList<MediaPlayerInfo>();
+
+ private class MediaPlayerInfo {
+ private String mPackageName;
+ private boolean mIsfocussed;
+ public MediaPlayerInfo(String packageName, boolean isfocussed) {
+ mPackageName = packageName;
+ mIsfocussed = isfocussed;
+ }
+ public boolean isFocussed() {
+ return mIsfocussed;
+ }
+ public void setFocus(boolean focus) {
+ mIsfocussed = focus;
+ }
+ public String getPackageName() {
+ return mPackageName;
+ }
+ }
+
private boolean isPlatformVoice() {
return mPlatformType == AudioSystem.PLATFORM_VOICE;
}
@@ -384,6 +406,15 @@ public class AudioService extends IAudioService.Stub {
* @see System#MUTE_STREAMS_AFFECTED */
private int mMuteAffectedStreams;
+ /** @see #handleHotwordInput **/
+ private Object mHotwordInputLock = new Object();
+
+ /** The package name of the application that is
+ * currently using the HOTWORD input.
+ */
+ // protected by mHotwordInputLock
+ private String mHotwordAudioInputPackage;
+
/**
* NOTE: setVibrateSetting(), getVibrateSetting(), shouldVibrate() are deprecated.
* mVibrateSetting is just maintained during deprecation period but vibration policy is
@@ -424,6 +455,11 @@ public class AudioService extends IAudioService.Stub {
private final ArrayMap<String, DeviceListSpec> mConnectedDevices = new ArrayMap<>();
+ private String mA2dpConnectedDevice = ""; //Used for BT a2dp connection
+ //Add connected A2dp devices in this list
+ private ArrayList<BluetoothDevice> mConnectedBTDevicesList =
+ new ArrayList<BluetoothDevice>();
+
// Forced device usage for communications
private int mForcedUseForComm;
@@ -515,7 +551,6 @@ public class AudioService extends IAudioService.Stub {
// Devices for which the volume is fixed and VolumePanel slider should be disabled
int mFixedVolumeDevices = AudioSystem.DEVICE_OUT_HDMI |
AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET |
- AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET |
AudioSystem.DEVICE_OUT_HDMI_ARC |
AudioSystem.DEVICE_OUT_SPDIF |
AudioSystem.DEVICE_OUT_AUX_LINE;
@@ -527,6 +562,9 @@ public class AudioService extends IAudioService.Stub {
private boolean mDockAudioMediaEnabled = true;
+ private boolean mForceAnalogDeskDock;
+ private boolean mForceAnalogCarDock;
+
private int mDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
// Used when safe volume warning message display is requested by setStreamVolume(). In this
@@ -628,6 +666,11 @@ public class AudioService extends IAudioService.Stub {
mUseFixedVolume = mContext.getResources().getBoolean(
com.android.internal.R.bool.config_useFixedVolume);
+ mForceAnalogDeskDock = mContext.getResources().getBoolean(
+ com.android.internal.R.bool.config_forceAnalogDeskDock);
+ mForceAnalogCarDock = mContext.getResources().getBoolean(
+ com.android.internal.R.bool.config_forceAnalogCarDock);
+
// must be called before readPersistedSettings() which needs a valid mStreamVolumeAlias[]
// array initialized by updateStreamVolumeAlias()
updateStreamVolumeAlias(false /*updateVolumes*/, TAG);
@@ -850,6 +893,100 @@ public class AudioService extends IAudioService.Stub {
}
}
+ /**
+ * @hide
+ */
+ public void addMediaPlayerAndUpdateRemoteController (String packageName) {
+ Log.v(TAG, "addMediaPlayerAndUpdateRemoteController: size of existing list: " +
+ mMediaPlayers.size());
+ boolean playerToAdd = true;
+ if (mMediaPlayers.size() > 0) {
+ final Iterator<MediaPlayerInfo> rccIterator = mMediaPlayers.iterator();
+ while (rccIterator.hasNext()) {
+ final MediaPlayerInfo player = rccIterator.next();
+ if (packageName.equals(player.getPackageName())) {
+ Log.e(TAG, "Player entry present, no need to add");
+ playerToAdd = false;
+ player.setFocus(true);
+ } else {
+ Log.e(TAG, "Player: " + player.getPackageName()+ "Lost Focus");
+ player.setFocus(false);
+ }
+ }
+ }
+ if (playerToAdd) {
+ Log.e(TAG, "Adding Player: " + packageName + " to available player list");
+ mMediaPlayers.add(new MediaPlayerInfo(packageName, true));
+ }
+ Intent intent = new Intent(AudioManager.RCC_CHANGED_ACTION);
+ intent.putExtra(AudioManager.EXTRA_CALLING_PACKAGE_NAME, packageName);
+ intent.putExtra(AudioManager.EXTRA_FOCUS_CHANGED_VALUE, true);
+ intent.putExtra(AudioManager.EXTRA_AVAILABLITY_CHANGED_VALUE, true);
+ sendBroadcastToAll(intent);
+ Log.v(TAG, "updating focussed RCC change to RCD: CallingPackageName:"
+ + packageName);
+ }
+
+ /**
+ * @hide
+ */
+ public void updateRemoteControllerOnExistingMediaPlayers() {
+ Log.v(TAG, "updateRemoteControllerOnExistingMediaPlayers: size of Player list: " +
+ mMediaPlayers.size());
+ if (mMediaPlayers.size() > 0) {
+ Log.v(TAG, "Inform RemoteController regarding existing RCC entry");
+ final Iterator<MediaPlayerInfo> rccIterator = mMediaPlayers.iterator();
+ while (rccIterator.hasNext()) {
+ final MediaPlayerInfo player = rccIterator.next();
+ Intent intent = new Intent(AudioManager.RCC_CHANGED_ACTION);
+ intent.putExtra(AudioManager.EXTRA_CALLING_PACKAGE_NAME,
+ player.getPackageName());
+ intent.putExtra(AudioManager.EXTRA_FOCUS_CHANGED_VALUE,
+ player.isFocussed());
+ intent.putExtra(AudioManager.EXTRA_AVAILABLITY_CHANGED_VALUE, true);
+ sendBroadcastToAll(intent);
+ Log.v(TAG, "updating RCC change: CallingPackageName:" +
+ player.getPackageName());
+ }
+ } else {
+ Log.e(TAG, "No RCC entry present to update");
+ }
+ }
+
+ /**
+ * @hide
+ */
+ public void removeMediaPlayerAndUpdateRemoteController (String packageName) {
+ Log.v(TAG, "removeMediaPlayerAndUpdateRemoteController: size of existing list: " +
+ mMediaPlayers.size());
+ boolean playerToRemove = false;
+ int index = -1;
+ if (mMediaPlayers.size() > 0) {
+ final Iterator<MediaPlayerInfo> rccIterator = mMediaPlayers.iterator();
+ while (rccIterator.hasNext()) {
+ index++;
+ final MediaPlayerInfo player = rccIterator.next();
+ if (packageName.equals(player.getPackageName())) {
+ Log.v(TAG, "Player entry present remove and update RemoteController");
+ playerToRemove = true;
+ break;
+ } else {
+ Log.v(TAG, "Player entry for " + player.getPackageName()+ " is not present");
+ }
+ }
+ }
+ if (playerToRemove) {
+ Log.e(TAG, "Removing Player: " + packageName + " from index" + index);
+ mMediaPlayers.remove(index);
+ }
+ Intent intent = new Intent(AudioManager.RCC_CHANGED_ACTION);
+ intent.putExtra(AudioManager.EXTRA_CALLING_PACKAGE_NAME, packageName);
+ intent.putExtra(AudioManager.EXTRA_FOCUS_CHANGED_VALUE, false);
+ intent.putExtra(AudioManager.EXTRA_AVAILABLITY_CHANGED_VALUE, false);
+ sendBroadcastToAll(intent);
+ Log.v(TAG, "Updated List size: " + mMediaPlayers.size());
+ }
+
private void checkAllAliasStreamVolumes() {
synchronized (VolumeStreamState.class) {
int numStreamTypes = AudioSystem.getNumStreamTypes();
@@ -1451,6 +1588,46 @@ public class AudioService extends IAudioService.Stub {
sendVolumeUpdate(streamType, oldIndex, index, flags);
}
+ /**
+ * Retrieve the package name of the application that currently controls
+ * the {@link android.media.MediaRecorder.AudioSource#HOTWORD} input.
+ * @return The package name of the application that controls the input
+ * or null if no package currently controls it.
+ */
+ public String getCurrentHotwordInputPackageName() {
+ return mHotwordAudioInputPackage;
+ }
+
+ /**
+ * Handle the change of state of the HOTWORD input.
+ *
+ * When the {@link android.media.MediaRecorder.AudioSource#HOTWORD} input is
+ * in use, send a broadcast to alert the new state and store the name of the current
+ * package that controls the input in mHotwordAudioInputPackage.
+ * @param listening Whether the input is being listened to.
+ */
+ public void handleHotwordInput(boolean listening) {
+ synchronized (mHotwordInputLock) {
+ Intent broadcastIntent = new Intent(Intent.ACTION_HOTWORD_INPUT_CHANGED);
+ String[] packages = mContext.getPackageManager().getPackagesForUid(
+ Binder.getCallingUid());
+ if (packages.length > 0) {
+ if (listening) {
+ mHotwordAudioInputPackage = packages[0];
+ }
+ broadcastIntent.putExtra(Intent.EXTRA_CURRENT_PACKAGE_NAME, packages[0]);
+ }
+ broadcastIntent.putExtra(Intent.EXTRA_HOTWORD_INPUT_STATE,
+ listening ? AudioRecord.RECORDSTATE_RECORDING :
+ AudioRecord.RECORDSTATE_STOPPED);
+ // Set the currently listening package to null if listening has stopped.
+ if (!listening) {
+ mHotwordAudioInputPackage = null;
+ }
+ sendBroadcastToAll(broadcastIntent, Manifest.permission.CAPTURE_AUDIO_HOTWORD);
+ }
+ }
+
/** @see AudioManager#forceVolumeControlStream(int) */
public void forceVolumeControlStream(int streamType, IBinder cb) {
synchronized(mForceControlStreamLock) {
@@ -1503,11 +1680,15 @@ public class AudioService extends IAudioService.Stub {
}
private void sendBroadcastToAll(Intent intent) {
+ sendBroadcastToAll(intent, null);
+ }
+
+ private void sendBroadcastToAll(Intent intent, String receiverPermission) {
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
final long ident = Binder.clearCallingIdentity();
try {
- mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
+ mContext.sendBroadcastAsUser(intent, UserHandle.ALL, receiverPermission);
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -2938,9 +3119,18 @@ public class AudioService extends IAudioService.Stub {
synchronized (mConnectedDevices) {
synchronized (mA2dpAvrcpLock) {
mA2dp = (BluetoothA2dp) proxy;
+ if (mConnectedBTDevicesList.size() > 0) {
+ Log.d(TAG,"A2dp connection list not empty, purge it, size " +
+ mConnectedBTDevicesList.size());
+ mConnectedBTDevicesList.clear();
+ }
+ //In Dual A2dp, we can have two devices connected
deviceList = mA2dp.getConnectedDevices();
- if (deviceList.size() > 0) {
- btDevice = deviceList.get(0);
+ Log.d(TAG, "onServiceConnected: A2dp Service connected: " +
+ deviceList.size());
+ for (int i = 0; i < deviceList.size(); i++) {
+ //Add the device in Connected list
+ btDevice = deviceList.get(i);
int state = mA2dp.getConnectionState(btDevice);
int delay = checkSendBecomingNoisyIntent(
AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
@@ -3038,6 +3228,10 @@ public class AudioService extends IAudioService.Stub {
case BluetoothProfile.A2DP:
synchronized (mConnectedDevices) {
synchronized (mA2dpAvrcpLock) {
+ Log.d(TAG,"mConnectedBTDevicesList size " + mConnectedBTDevicesList.size());
+ if (mConnectedBTDevicesList.size() > 0) {
+ mConnectedBTDevicesList.clear();
+ }
// Disconnect ALL DEVICE_OUT_BLUETOOTH_A2DP devices
for (int i = 0; i < mConnectedDevices.size(); i++) {
DeviceListSpec deviceSpec = mConnectedDevices.valueAt(i);
@@ -3593,10 +3787,41 @@ public class AudioService extends IAudioService.Stub {
public int setBluetoothA2dpDeviceConnectionState(BluetoothDevice device, int state, int profile)
{
- int delay;
+ int delay = 0;
if (profile != BluetoothProfile.A2DP && profile != BluetoothProfile.A2DP_SINK) {
throw new IllegalArgumentException("invalid profile " + profile);
}
+ /*check the state of the currnt device*/
+ if (state == BluetoothA2dp.STATE_CONNECTING) {
+ Log.d(TAG, "Device is still connecting ");
+ return delay;
+ }
+ if ((mConnectedBTDevicesList.contains(device) &&
+ (state == BluetoothA2dp.STATE_CONNECTED))) {
+ Log.d(TAG, "Device conn is updated again, ignore ");
+ return delay;
+ }
+ if (!mConnectedBTDevicesList.contains(device) &&
+ (state == BluetoothA2dp.STATE_CONNECTED)) {
+ /*add the device in the list*/
+ Log.d(TAG, "Add new connected device in the list: " + device);
+ mConnectedBTDevicesList.add(device);
+ if (mConnectedBTDevicesList.size() > 1) {
+ Log.d(TAG, "Second device connected, add new device ");
+ return delay;
+ }
+ } else if ((state == BluetoothA2dp.STATE_DISCONNECTED) ||
+ (state == BluetoothA2dp.STATE_DISCONNECTING)) {
+ Log.d(TAG, "Device is getting disconnected: " + device);
+ if (mConnectedBTDevicesList.contains(device)) {
+ Log.d(TAG, "Remove the BT device ");
+ mConnectedBTDevicesList.remove(device);
+ }
+ if (mConnectedBTDevicesList.size() > 0) {
+ Log.d(TAG, "Not all are disconnected ");
+ return delay;
+ }
+ }
synchronized (mConnectedDevices) {
if (profile == BluetoothProfile.A2DP) {
delay = checkSendBecomingNoisyIntent(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
@@ -4610,11 +4835,12 @@ public class AudioService extends IAudioService.Stub {
// introduction of a delay for transient disconnections of docks when
// power is rapidly turned off/on, this message will be canceled if
// we reconnect the dock under a preset delay
- makeA2dpDeviceUnavailableLater(address, BTA2DP_DOCK_TIMEOUT_MILLIS);
+ makeA2dpDeviceUnavailableLater(btDevice.getAddress(), BTA2DP_DOCK_TIMEOUT_MILLIS);
// the next time isConnected is evaluated, it will be false for the dock
}
} else {
- makeA2dpDeviceUnavailableNow(address);
+ Log.d(TAG, "All devices are disconneted, update Policymanager ");
+ makeA2dpDeviceUnavailableNow(btDevice.getAddress());
}
synchronized (mCurAudioRoutes) {
if (mCurAudioRoutes.bluetoothName != null) {
@@ -4624,21 +4850,24 @@ public class AudioService extends IAudioService.Stub {
}
}
} else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) {
+ //This function is not implemented
+ mA2dpConnectedDevice = "BluetoothA2dp"; // Add this String
if (btDevice.isBluetoothDock()) {
// this could be a reconnection after a transient disconnection
cancelA2dpDeviceTimeout();
- mDockAddress = address;
+ mDockAddress = mA2dpConnectedDevice;
} else {
// this could be a connection of another A2DP device before the timeout of
// a dock: cancel the dock timeout, and make the dock unavailable now
if(hasScheduledA2dpDockTimeout()) {
cancelA2dpDeviceTimeout();
- makeA2dpDeviceUnavailableNow(mDockAddress);
+ makeA2dpDeviceUnavailableNow(btDevice.getAddress());
}
}
- makeA2dpDeviceAvailable(address, btDevice.getName());
+ makeA2dpDeviceAvailable(btDevice.getAddress(), btDevice.getName());
+ //Updated the Router for a2dp device
synchronized (mCurAudioRoutes) {
- String name = btDevice.getAliasName();
+ String name = mA2dpConnectedDevice;
if (!TextUtils.equals(mCurAudioRoutes.bluetoothName, name)) {
mCurAudioRoutes.bluetoothName = name;
sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
@@ -4655,6 +4884,7 @@ public class AudioService extends IAudioService.Stub {
Log.d(TAG, "onSetA2dpSourceConnectionState btDevice="+btDevice+" state="+state);
}
if (btDevice == null) {
+ Log.d(TAG, "onSetA2dpSourceConnectionState device is null"); //gasati
return;
}
String address = btDevice.getAddress();
@@ -4738,8 +4968,14 @@ public class AudioService extends IAudioService.Stub {
// Called synchronized on mConnectedDevices
private int checkSendBecomingNoisyIntent(int device, int state) {
int delay = 0;
+ if (mConnectedBTDevicesList.size() > 1) {
+ Log.d(TAG, "checkSendBecomingNoisyIntent on state: " + state);
+ return delay;
+ }
+
if ((state == 0) && ((device & mBecomingNoisyIntentDevices) != 0)) {
int devices = 0;
+ Log.d(TAG, "checkSendBecomingNoisyIntent update the noise");
for (int i = 0; i < mConnectedDevices.size(); i++) {
int dev = mConnectedDevices.valueAt(i).mDeviceType;
if (((dev & AudioSystem.DEVICE_BIT_IN) == 0)
@@ -4962,10 +5198,12 @@ public class AudioService extends IAudioService.Stub {
int config;
switch (dockState) {
case Intent.EXTRA_DOCK_STATE_DESK:
- config = AudioSystem.FORCE_BT_DESK_DOCK;
+ config = mForceAnalogDeskDock ? AudioSystem.FORCE_ANALOG_DOCK :
+ AudioSystem.FORCE_BT_DESK_DOCK;
break;
case Intent.EXTRA_DOCK_STATE_CAR:
- config = AudioSystem.FORCE_BT_CAR_DOCK;
+ config = mForceAnalogCarDock ? AudioSystem.FORCE_ANALOG_DOCK :
+ AudioSystem.FORCE_BT_CAR_DOCK;
break;
case Intent.EXTRA_DOCK_STATE_LE_DESK:
config = AudioSystem.FORCE_ANALOG_DOCK;
@@ -5159,6 +5397,18 @@ public class AudioService extends IAudioService.Stub {
mMediaFocusControl.remoteControlDisplayWantsPlaybackPositionSync(rcd, wantsSync);
}
+ public void setRemoteControlClientPlayItem(long uid, int scope) {
+ mMediaFocusControl.setRemoteControlClientPlayItem(uid, scope);
+ }
+
+ public void getRemoteControlClientNowPlayingEntries() {
+ mMediaFocusControl.getRemoteControlClientNowPlayingEntries();
+ }
+
+ public void setRemoteControlClientBrowsedPlayer() {
+ mMediaFocusControl.setRemoteControlClientBrowsedPlayer();
+ }
+
@Override
public void setRemoteStreamVolume(int index) {
enforceVolumeController("set the remote stream volume");
diff --git a/services/core/java/com/android/server/audio/MediaFocusControl.java b/services/core/java/com/android/server/audio/MediaFocusControl.java
index f72b598..af880bd 100644
--- a/services/core/java/com/android/server/audio/MediaFocusControl.java
+++ b/services/core/java/com/android/server/audio/MediaFocusControl.java
@@ -335,6 +335,9 @@ public class MediaFocusControl implements OnFinished {
private static final int MSG_RCDISPLAY_INIT_INFO = 9;
private static final int MSG_REEVALUATE_RCD = 10;
private static final int MSG_UNREGISTER_MEDIABUTTONINTENT = 11;
+ private static final int MSG_RCC_SET_BROWSED_PLAYER = 12;
+ private static final int MSG_RCC_SET_PLAY_ITEM = 13;
+ private static final int MSG_RCC_GET_NOW_PLAYING_ENTRIES = 14;
// sendMsg() flags
/** If the msg is already queued, replace it with this one. */
@@ -382,6 +385,22 @@ public class MediaFocusControl implements OnFinished {
(IRemoteVolumeObserver)msg.obj /* rvo */);
break;
+ case MSG_RCC_SET_PLAY_ITEM:
+ Log.d(TAG, "MSG_RCC_SET_PLAY_ITEM: "+ ((Long)msg.obj).longValue());
+ onSetRemoteControlClientPlayItem(msg.arg2 /* scope */,
+ ((Long)msg.obj).longValue() /* uid */);
+ break;
+
+ case MSG_RCC_GET_NOW_PLAYING_ENTRIES:
+ Log.d(TAG, "MSG_RCC_GET_NOW_PLAYING_ENTRIES: ");
+ onGetRemoteControlClientNowPlayingEntries();
+ break;
+
+ case MSG_RCC_SET_BROWSED_PLAYER:
+ Log.d(TAG, "MSG_RCC_SET_BROWSED_PLAYER: ");
+ onSetRemoteControlClientBrowsedPlayer();
+ break;
+
case MSG_RCDISPLAY_INIT_INFO:
// msg.obj is guaranteed to be non null
onRcDisplayInitInfo((IRemoteControlDisplay)msg.obj /*newRcd*/,
@@ -2052,6 +2071,66 @@ public class MediaFocusControl implements OnFinished {
}
}
+ public void setRemoteControlClientPlayItem(long uid, int scope) {
+ sendMsg(mEventHandler, MSG_RCC_SET_PLAY_ITEM, SENDMSG_REPLACE, 0 /* arg1 */,
+ scope /* arg2*/, new Long(uid) /* obj */, 0 /* delay */);
+ }
+
+ private void onSetRemoteControlClientPlayItem(int scope, Long uid) {
+ Log.d(TAG, "onSetRemoteControlClientPlayItem: "+ uid);
+ synchronized(mCurrentRcLock) {
+ if (mCurrentRcClient != null) {
+ try {
+ mCurrentRcClient.setPlayItem(scope, uid);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Current valid remote client is dead: "+e);
+ mCurrentRcClient = null;
+ }
+ }
+ }
+ }
+
+ public void getRemoteControlClientNowPlayingEntries() {
+ sendMsg(mEventHandler, MSG_RCC_GET_NOW_PLAYING_ENTRIES, SENDMSG_REPLACE,
+ 0 /* arg1 */, 0 /* arg2 ignored*/, 0 /* obj */, 0 /* delay */);
+ }
+
+ private void onGetRemoteControlClientNowPlayingEntries() {
+ Log.d(TAG, "onGetRemoteControlClientNowPlayingEntries: ");
+ synchronized(mCurrentRcLock) {
+ if (mCurrentRcClient != null) {
+ try {
+ mCurrentRcClient.getNowPlayingEntries();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Current valid remote client is dead: "+e);
+ mCurrentRcClient = null;
+ }
+ }
+ }
+ }
+
+ public void setRemoteControlClientBrowsedPlayer() {
+ Log.d(TAG, "setRemoteControlClientBrowsedPlayer: ");
+ sendMsg(mEventHandler, MSG_RCC_SET_BROWSED_PLAYER, SENDMSG_REPLACE, 0/* arg1 */,
+ 0 /* arg2 ignored*/, 0 /* obj */, 0 /* delay */);
+ }
+
+ private void onSetRemoteControlClientBrowsedPlayer() {
+ Log.d(TAG, "onSetRemoteControlClientBrowsedPlayer: ");
+ PlayerRecord prse = mPRStack.peek();
+ if (prse.getRcc() == null) {
+ Log.d(TAG, "can not proceed with setBrowsedPlayer");
+ } else {
+ Log.d(TAG, "proceed with setBrowsedPlayer");
+ try {
+ Log.d(TAG, "Calling setBrowsedPlayer");
+ prse.getRcc().setBrowsedPlayer();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Current valid remote client is dead: "+ e);
+ }
+ }
+ }
+
// handler for MSG_RCC_NEW_VOLUME_OBS
private void onRegisterVolumeObserverForRcc(int rccId, IRemoteVolumeObserver rvo) {
synchronized(mPRStack) {
diff --git a/services/core/java/com/android/server/connectivity/Nat464Xlat.java b/services/core/java/com/android/server/connectivity/Nat464Xlat.java
index a9eaeee..89569ec 100644
--- a/services/core/java/com/android/server/connectivity/Nat464Xlat.java
+++ b/services/core/java/com/android/server/connectivity/Nat464Xlat.java
@@ -31,6 +31,7 @@ import android.os.Handler;
import android.os.Message;
import android.os.INetworkManagementService;
import android.os.RemoteException;
+import android.os.SystemProperties;
import android.util.Slog;
import com.android.server.net.BaseNetworkObserver;
@@ -90,7 +91,12 @@ public class Nat464Xlat extends BaseNetworkObserver {
(nai.linkProperties != null) ? nai.linkProperties.hasIPv4Address() : false;
// Only support clat on mobile and wifi for now, because these are the only IPv6-only
// networks we can connect to.
- return connected && !hasIPv4Address && (netType == TYPE_MOBILE || netType == TYPE_WIFI);
+ boolean doXlat = SystemProperties.getBoolean("persist.net.doxlat",true);
+ if(!doXlat) {
+ Slog.i(TAG, "Android Xlat is disabled");
+ }
+ return connected && !hasIPv4Address && (((netType == TYPE_MOBILE) && doXlat )
+ || netType == TYPE_WIFI);
}
/**
@@ -125,6 +131,7 @@ public class Nat464Xlat extends BaseNetworkObserver {
}
try {
+ mNMService.unregisterObserver(this);
mNMService.registerObserver(this);
} catch(RemoteException e) {
Slog.e(TAG, "startClat: Can't register interface observer for clat on " + mNetwork);
@@ -233,16 +240,12 @@ public class Nat464Xlat extends BaseNetworkObserver {
}
@Override
- public void interfaceLinkStateChanged(String iface, boolean up) {
+ public void addressUpdated(String iface, LinkAddress clatAddress) {
// Called by the InterfaceObserver on its own thread, so can race with stop().
- if (isStarted() && up && mIface.equals(iface)) {
+ if (isStarted() && mIface.equals(iface) && clatAddress != null) {
Slog.i(TAG, "interface " + iface + " is up, mIsRunning " + mIsRunning + "->true");
if (!mIsRunning) {
- LinkAddress clatAddress = getLinkAddress(iface);
- if (clatAddress == null) {
- return;
- }
mIsRunning = true;
maybeSetIpv6NdOffload(mBaseIface, false);
LinkProperties lp = new LinkProperties(mNetwork.linkProperties);
diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java
index c1aaf07..9ead529 100644
--- a/services/core/java/com/android/server/connectivity/Tethering.java
+++ b/services/core/java/com/android/server/connectivity/Tethering.java
@@ -36,11 +36,14 @@ import android.net.Network;
import android.net.NetworkInfo;
import android.net.NetworkUtils;
import android.net.RouteInfo;
+import android.net.wifi.WifiDevice;
import android.os.Binder;
import android.os.INetworkManagementService;
import android.os.Looper;
import android.os.Message;
+import android.os.SystemProperties;
import android.os.UserHandle;
+import android.os.SystemProperties;
import android.telephony.TelephonyManager;
import android.util.Log;
@@ -64,9 +67,22 @@ import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
+import java.util.List;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
+import java.io.BufferedReader;
+import java.io.DataInputStream;
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+
+import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLED;
+import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLED;
+import static android.net.wifi.WifiManager.WIFI_AP_STATE_CHANGED_ACTION;
+
/**
* @hide
@@ -137,6 +153,17 @@ public class Tethering extends BaseNetworkObserver {
private boolean mUsbTetherRequested; // true if USB tethering should be started
// when RNDIS is enabled
+ // Once STA established connection to hostapd, it will be added
+ // to mL2ConnectedDeviceMap. Then after deviceinfo update from dnsmasq,
+ // it will be added to mConnectedDeviceMap
+ private HashMap<String, WifiDevice> mL2ConnectedDeviceMap = new HashMap<String, WifiDevice>();
+ private HashMap<String, WifiDevice> mConnectedDeviceMap = new HashMap<String, WifiDevice>();
+ private static final String dhcpLocation = "/data/misc/dhcp/dnsmasq.leases";
+
+ // Device name polling interval(ms) and max times
+ private static final int DNSMASQ_POLLING_INTERVAL = 1000;
+ private static final int DNSMASQ_POLLING_MAX_TIMES = 10;
+
public Tethering(Context context, INetworkManagementService nmService,
INetworkStatsService statsService, Looper looper) {
mContext = context;
@@ -158,6 +185,8 @@ public class Tethering extends BaseNetworkObserver {
filter.addAction(UsbManager.ACTION_USB_STATE);
filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
+ filter.addAction(WIFI_AP_STATE_CHANGED_ACTION);
+
mContext.registerReceiver(mStateReceiver, filter);
filter = new IntentFilter();
@@ -190,11 +219,17 @@ public class Tethering extends BaseNetworkObserver {
void updateConfiguration() {
String[] tetherableUsbRegexs = mContext.getResources().getStringArray(
com.android.internal.R.array.config_tether_usb_regexs);
- String[] tetherableWifiRegexs = mContext.getResources().getStringArray(
- com.android.internal.R.array.config_tether_wifi_regexs);
+ String[] tetherableWifiRegexs;
String[] tetherableBluetoothRegexs = mContext.getResources().getStringArray(
com.android.internal.R.array.config_tether_bluetooth_regexs);
+ if (SystemProperties.getInt("persist.fst.rate.upgrade.en", 0) == 1) {
+ tetherableWifiRegexs = new String[] {"bond0"};
+ } else {
+ tetherableWifiRegexs = mContext.getResources().getStringArray(
+ com.android.internal.R.array.config_tether_wifi_regexs);
+ }
+
int ifaceTypes[] = mContext.getResources().getIntArray(
com.android.internal.R.array.config_tether_upstream_types);
Collection<Integer> upstreamIfaceTypes = new ArrayList();
@@ -326,6 +361,168 @@ public class Tethering extends BaseNetworkObserver {
}
}
+ public List<WifiDevice> getTetherConnectedSta() {
+ Iterator it;
+ List<WifiDevice> TetherConnectedStaList = new ArrayList<WifiDevice>();
+
+ if (mContext.getResources().getBoolean(com.android.internal.R.bool.config_softap_extention)) {
+ it = mConnectedDeviceMap.keySet().iterator();
+ while(it.hasNext()) {
+ String key = (String)it.next();
+ WifiDevice device = (WifiDevice)mConnectedDeviceMap.get(key);
+ if (VDBG) {
+ Log.d(TAG, "getTetherConnectedSta: addr=" + key + " name=" + device.deviceName);
+ }
+ TetherConnectedStaList.add(device);
+ }
+ }
+
+ return TetherConnectedStaList;
+ }
+
+ private void sendTetherConnectStateChangedBroadcast() {
+ if (!getConnectivityManager().isTetheringSupported()) return;
+
+ Intent broadcast = new Intent(ConnectivityManager.TETHER_CONNECT_STATE_CHANGED);
+ broadcast.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING |
+ Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+
+ mContext.sendStickyBroadcastAsUser(broadcast, UserHandle.ALL);
+
+ showTetheredNotification(com.android.internal.R.drawable.stat_sys_tether_wifi);
+ }
+
+ private boolean readDeviceInfoFromDnsmasq(WifiDevice device) {
+ boolean result = false;
+ FileInputStream fstream = null;
+ String line;
+
+ try {
+ fstream = new FileInputStream(dhcpLocation);
+ DataInputStream in = new DataInputStream(fstream);
+ BufferedReader br = new BufferedReader(new InputStreamReader(in));
+
+ while ((null != (line = br.readLine())) && (line.length() != 0)) {
+ String[] fields = line.split(" ");
+
+ // 949295 00:0a:f5:6a:bf:70 192.168.43.32 android-93de88df9ec61bac *
+ if (fields.length > 3) {
+ String addr = fields[1];
+ String name = fields[3];
+
+ if (addr.equals(device.deviceAddress)) {
+ device.deviceName = name;
+ result = true;
+ break;
+ }
+ }
+ }
+ } catch (IOException ex) {
+ Log.e(TAG, "readDeviceNameFromDnsmasq: " + ex);
+ } finally {
+ if (fstream != null) {
+ try {
+ fstream.close();
+ } catch (IOException ex) {}
+ }
+ }
+
+ return result;
+ }
+
+ /*
+ * DnsmasqThread is used to read the Device info from dnsmasq.
+ */
+ private static class DnsmasqThread extends Thread {
+ private final Tethering mTethering;
+ private int mInterval;
+ private int mMaxTimes;
+ private WifiDevice mDevice;
+
+ public DnsmasqThread(Tethering tethering, WifiDevice device,
+ int interval, int maxTimes) {
+ super("Tethering");
+ mTethering = tethering;
+ mInterval = interval;
+ mMaxTimes = maxTimes;
+ mDevice = device;
+ }
+
+ public void run() {
+ boolean result = false;
+
+ try {
+ while (mMaxTimes > 0) {
+ result = mTethering.readDeviceInfoFromDnsmasq(mDevice);
+ if (result) {
+ if (DBG) Log.d(TAG, "Successfully poll device info for " + mDevice.deviceAddress);
+ break;
+ }
+
+ mMaxTimes --;
+ Thread.sleep(mInterval);
+ }
+ } catch (Exception ex) {
+ result = false;
+ Log.e(TAG, "Pulling " + mDevice.deviceAddress + "error" + ex);
+ }
+
+ if (!result) {
+ if (DBG) Log.d(TAG, "Pulling timeout, suppose STA uses static ip " + mDevice.deviceAddress);
+ }
+
+ // When STA uses static ip, device info will be unavaiable from dnsmasq,
+ // thus no matter the result is success or failure, we will broadcast the event.
+ // But if the device is not in L2 connected state, it means the hostapd connection is
+ // disconnected before dnsmasq get device info, so in this case, don't broadcast
+ // connection event.
+ WifiDevice other = mTethering.mL2ConnectedDeviceMap.get(mDevice.deviceAddress);
+ if (other != null && other.deviceState == WifiDevice.CONNECTED) {
+ mTethering.mConnectedDeviceMap.put(mDevice.deviceAddress, mDevice);
+ mTethering.sendTetherConnectStateChangedBroadcast();
+ } else {
+ if (DBG) Log.d(TAG, "Device " + mDevice.deviceAddress + "already disconnected, ignoring");
+ }
+ }
+ }
+
+ public void interfaceMessageRecevied(String message) {
+ // if softap extension feature not enabled, do nothing
+ if (!mContext.getResources().getBoolean(com.android.internal.R.bool.config_softap_extention)) {
+ return;
+ }
+
+ if (DBG) Log.d(TAG, "interfaceMessageRecevied: message=" + message);
+
+ try {
+ WifiDevice device = new WifiDevice(message);
+
+ if (device.deviceState == WifiDevice.CONNECTED) {
+ mL2ConnectedDeviceMap.put(device.deviceAddress, device);
+
+ // When hostapd reported STA-connection event, it is possible that device
+ // info can't fetched from dnsmasq, then we start a thread to poll the
+ // device info, the thread will exit after device info avaiable.
+ // For static ip case, dnsmasq don't hold the device info, thus thread
+ // will exit after a timeout.
+ if (readDeviceInfoFromDnsmasq(device)) {
+ mConnectedDeviceMap.put(device.deviceAddress, device);
+ sendTetherConnectStateChangedBroadcast();
+ } else {
+ if (DBG) Log.d(TAG, "Starting poll device info for " + device.deviceAddress);
+ new DnsmasqThread(this, device,
+ DNSMASQ_POLLING_INTERVAL, DNSMASQ_POLLING_MAX_TIMES).start();
+ }
+ } else if (device.deviceState == WifiDevice.DISCONNECTED) {
+ mL2ConnectedDeviceMap.remove(device.deviceAddress);
+ mConnectedDeviceMap.remove(device.deviceAddress);
+ sendTetherConnectStateChangedBroadcast();
+ }
+ } catch (IllegalArgumentException ex) {
+ Log.e(TAG, "WifiDevice IllegalArgument: " + ex);
+ }
+ }
+
public int tether(String iface) {
if (DBG) Log.d(TAG, "Tethering " + iface);
TetherInterfaceSM sm = null;
@@ -469,8 +666,24 @@ public class Tethering extends BaseNetworkObserver {
Resources r = Resources.getSystem();
CharSequence title = r.getText(com.android.internal.R.string.tethered_notification_title);
- CharSequence message = r.getText(com.android.internal.R.string.
- tethered_notification_message);
+
+ CharSequence message;
+ int size = mConnectedDeviceMap.size();
+
+ if (mContext.getResources().getBoolean(com.android.internal.R.bool.config_softap_extention)
+ && icon == com.android.internal.R.drawable.stat_sys_tether_wifi) {
+ if (size == 0) {
+ message = r.getText(com.android.internal.R.string.tethered_notification_no_device_message);
+ } else if (size == 1) {
+ message = String.format((r.getText(com.android.internal.R.string.tethered_notification_one_device_message)).toString(),
+ size);
+ } else {
+ message = String.format((r.getText(com.android.internal.R.string.tethered_notification_multi_device_message)).toString(),
+ size);
+ }
+ } else {
+ message = r.getText(com.android.internal.R.string.tethered_notification_message);
+ }
if (mTetheredNotificationBuilder == null) {
mTetheredNotificationBuilder = new Notification.Builder(mContext);
@@ -485,10 +698,18 @@ public class Tethering extends BaseNetworkObserver {
.setContentTitle(title)
.setContentText(message)
.setContentIntent(pi);
+ if (mContext.getResources().getBoolean(com.android.internal.R.bool.config_softap_extention)
+ && icon == com.android.internal.R.drawable.stat_sys_tether_wifi
+ && size > 0) {
+ mTetheredNotificationBuilder.setContentText(message);
+ } else {
+ mTetheredNotificationBuilder.setContentTitle(title);
+ }
mLastNotificationId = icon;
notificationManager.notifyAsUser(null, mLastNotificationId,
mTetheredNotificationBuilder.build(), UserHandle.ALL);
+
}
private void clearTetheredNotification() {
@@ -526,6 +747,14 @@ public class Tethering extends BaseNetworkObserver {
}
} else if (action.equals(Intent.ACTION_CONFIGURATION_CHANGED)) {
updateConfiguration();
+ } else if(action.equals(WIFI_AP_STATE_CHANGED_ACTION)){
+ int wifiApState = intent.getIntExtra("wifi_state", WIFI_AP_STATE_DISABLED);
+ if (DBG) Log.d(TAG, "WIFI_AP_STATE_CHANGED: wifiApState=" + wifiApState);
+ if(wifiApState == WIFI_AP_STATE_ENABLED ||
+ wifiApState == WIFI_AP_STATE_DISABLED) {
+ mConnectedDeviceMap.clear();
+ mL2ConnectedDeviceMap.clear();
+ }
}
}
}
@@ -644,6 +873,10 @@ public class Tethering extends BaseNetworkObserver {
if (tm != null) {
secureSetting = tm.getTetherApnRequired();
}
+ // Allow override of TETHER_DUN_REQUIRED via prop
+ int prop = SystemProperties.getInt("persist.sys.dun.override", -1);
+ secureSetting = ((prop < 3) && (prop >= 0)) ? prop : secureSetting;
+
synchronized (mPublicSync) {
// 2 = not set, 0 = DUN not required, 1 = DUN required
if (secureSetting != 2) {
diff --git a/services/core/java/com/android/server/display/AutomaticBrightnessController.java b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
index e15bca6..575701a 100644
--- a/services/core/java/com/android/server/display/AutomaticBrightnessController.java
+++ b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
@@ -22,6 +22,8 @@ import com.android.server.twilight.TwilightListener;
import com.android.server.twilight.TwilightManager;
import com.android.server.twilight.TwilightState;
+import android.content.Context;
+import android.content.res.Resources;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
@@ -193,11 +195,18 @@ class AutomaticBrightnessController {
private int mBrightnessAdjustmentSampleOldBrightness;
private float mBrightnessAdjustmentSampleOldGamma;
- public AutomaticBrightnessController(Callbacks callbacks, Looper looper,
+ // Night mode color temperature adjustments
+ private final LiveDisplayController mLiveDisplay;
+
+ private final Context mContext;
+
+ public AutomaticBrightnessController(Context context, Callbacks callbacks, Looper looper,
SensorManager sensorManager, Spline autoBrightnessSpline, int lightSensorWarmUpTime,
int brightnessMin, int brightnessMax, float dozeScaleFactor,
int lightSensorRate, long brighteningLightDebounceConfig,
- long darkeningLightDebounceConfig, boolean resetAmbientLuxAfterWarmUpConfig) {
+ long darkeningLightDebounceConfig, boolean resetAmbientLuxAfterWarmUpConfig,
+ LiveDisplayController ldc) {
+ mContext = context;
mCallbacks = callbacks;
mTwilight = LocalServices.getService(TwilightManager.class);
mSensorManager = sensorManager;
@@ -210,6 +219,7 @@ class AutomaticBrightnessController {
mBrighteningLightDebounceConfig = brighteningLightDebounceConfig;
mDarkeningLightDebounceConfig = darkeningLightDebounceConfig;
mResetAmbientLuxAfterWarmUpConfig = resetAmbientLuxAfterWarmUpConfig;
+ mLiveDisplay = ldc;
mHandler = new AutomaticBrightnessHandler(looper);
mAmbientLightRingBuffer = new AmbientLightRingBuffer(mLightSensorRate);
@@ -478,6 +488,9 @@ class AutomaticBrightnessController {
}
}
+ // Update LiveDisplay with the current lux
+ mLiveDisplay.updateLiveDisplay(mAmbientLux);
+
if (USE_TWILIGHT_ADJUSTMENT) {
TwilightState state = mTwilight.getCurrentState();
if (state != null && state.isNight()) {
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index 6a6570b..e8a857b 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -287,6 +287,8 @@ public final class DisplayManagerService extends SystemService {
mOnlyCore = onlyCore;
}
+ mDisplayPowerController.systemReady();
+
mHandler.sendEmptyMessage(MSG_REGISTER_ADDITIONAL_DISPLAY_ADAPTERS);
}
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 7b49530..38c4180 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -19,6 +19,7 @@ package com.android.server.display;
import com.android.internal.app.IBatteryStats;
import com.android.server.LocalServices;
import com.android.server.am.BatteryStatsService;
+import com.android.server.lights.LightsManager;
import android.animation.Animator;
import android.animation.ObjectAnimator;
@@ -124,6 +125,9 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
// Battery stats.
private final IBatteryStats mBatteryStats;
+ // The lights service.
+ private final LightsManager mLights;
+
// The sensor manager.
private final SensorManager mSensorManager;
@@ -247,6 +251,9 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
// The controller for the automatic brightness level.
private AutomaticBrightnessController mAutomaticBrightnessController;
+ // The controller for LiveDisplay
+ private final LiveDisplayController mLiveDisplayController;
+
// Animators.
private ObjectAnimator mColorFadeOnAnimator;
private ObjectAnimator mColorFadeOffAnimator;
@@ -262,11 +269,14 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
mCallbacks = callbacks;
mBatteryStats = BatteryStatsService.getService();
+ mLights = LocalServices.getService(LightsManager.class);
mSensorManager = sensorManager;
mWindowManagerPolicy = LocalServices.getService(WindowManagerPolicy.class);
mBlanker = blanker;
mContext = context;
+ mLiveDisplayController = new LiveDisplayController(context, handler.getLooper());
+
final Resources resources = context.getResources();
final int screenBrightnessSettingMinimum = clampAbsoluteBrightness(resources.getInteger(
com.android.internal.R.integer.config_screenBrightnessSettingMinimum));
@@ -343,12 +353,12 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
if (bottom < screenBrightnessRangeMinimum) {
screenBrightnessRangeMinimum = bottom;
}
- mAutomaticBrightnessController = new AutomaticBrightnessController(this,
+ mAutomaticBrightnessController = new AutomaticBrightnessController(mContext, this,
handler.getLooper(), sensorManager, screenAutoBrightnessSpline,
lightSensorWarmUpTimeConfig, screenBrightnessRangeMinimum,
mScreenBrightnessRangeMaximum, dozeScaleFactor, lightSensorRate,
brighteningLightDebounce, darkeningLightDebounce,
- autoBrightnessResetAmbientLuxAfterWarmUp);
+ autoBrightnessResetAmbientLuxAfterWarmUp, mLiveDisplayController);
}
}
@@ -573,6 +583,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
} else {
setProximitySensorEnabled(false);
mWaitingForNegativeProximity = false;
+ mProximity = PROXIMITY_UNKNOWN;
}
if (mScreenOffBecauseOfProximity
&& mProximity != PROXIMITY_POSITIVE) {
@@ -595,6 +606,14 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
// Use zero brightness when screen is off.
if (state == Display.STATE_OFF) {
brightness = PowerManager.BRIGHTNESS_OFF;
+ mLights.getLight(LightsManager.LIGHT_ID_BUTTONS).setBrightness(brightness);
+ mLights.getLight(LightsManager.LIGHT_ID_KEYBOARD).setBrightness(brightness);
+ }
+
+ // Disable button lights when dozing
+ if (state == Display.STATE_DOZE || state == Display.STATE_DOZE_SUSPEND) {
+ mLights.getLight(LightsManager.LIGHT_ID_BUTTONS).setBrightness(PowerManager.BRIGHTNESS_OFF);
+ mLights.getLight(LightsManager.LIGHT_ID_KEYBOARD).setBrightness(PowerManager.BRIGHTNESS_OFF);
}
// Configure auto-brightness.
@@ -692,6 +711,9 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
}
}
+ // Update LiveDisplay now
+ mLiveDisplayController.updateLiveDisplay();
+
// Determine whether the display is ready for use in the newly requested state.
// Note that we do not wait for the brightness ramp animation to complete before
// reporting the display is ready because we only need to ensure the screen is in the
@@ -1131,6 +1153,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
mAutomaticBrightnessController.dump(pw);
}
+ mLiveDisplayController.dump(pw);
}
private static String proximityToString(int state) {
@@ -1192,6 +1215,10 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
return MathUtils.constrain(value, PowerManager.BRIGHTNESS_OFF, PowerManager.BRIGHTNESS_ON);
}
+ void systemReady() {
+ mLiveDisplayController.systemReady();
+ }
+
private final class DisplayControllerHandler extends Handler {
public DisplayControllerHandler(Looper looper) {
super(looper, null, true /*async*/);
diff --git a/services/core/java/com/android/server/display/ExtendedRemoteDisplayHelper.java b/services/core/java/com/android/server/display/ExtendedRemoteDisplayHelper.java
new file mode 100644
index 0000000..1be474b
--- /dev/null
+++ b/services/core/java/com/android/server/display/ExtendedRemoteDisplayHelper.java
@@ -0,0 +1,163 @@
+/*
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.android.server.display;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import android.media.RemoteDisplay;
+import android.os.Handler;
+import android.util.Slog;
+import android.content.Context;
+
+class ExtendedRemoteDisplayHelper {
+ private static final String TAG = "ExtendedRemoteDisplayHelper";
+
+ // ExtendedRemoteDisplay class
+ // ExtendedRemoteDisplay is an enhanced RemoteDisplay. It has
+ // similar interface as RemoteDisplay class
+ private static Class sExtRemoteDisplayClass;
+
+ // Method object for the API ExtendedRemoteDisplay.Listen
+ // ExtendedRemoteDisplay.Listen has the same API signature as
+ // RemoteDisplay.Listen except for an additional argument to pass the
+ // Context
+ private static Method sExtRemoteDisplayListen;
+
+ // Method Object for the API ExtendedRemoteDisplay.Dispose
+ // ExtendedRemoteDisplay.Dispose follows the same API signature as
+ // RemoteDisplay.Dispose
+ private static Method sExtRemoteDisplayDispose;
+
+ static {
+ //Check availability of ExtendedRemoteDisplay runtime
+ try {
+ sExtRemoteDisplayClass = Class.forName("com.qualcomm.wfd.ExtendedRemoteDisplay");
+ } catch (Throwable t) {
+ Slog.i(TAG, "ExtendedRemoteDisplay Not available.");
+ }
+
+ if(sExtRemoteDisplayClass != null) {
+ // If ExtendedRemoteDisplay is available find the methods
+ Slog.i(TAG, "ExtendedRemoteDisplay Is available. Find Methods");
+ try {
+ Class args[] = {
+ String.class,
+ RemoteDisplay.Listener.class,
+ Handler.class, Context.class
+ };
+ sExtRemoteDisplayListen = sExtRemoteDisplayClass.getDeclaredMethod("listen", args);
+ } catch (Throwable t) {
+ Slog.i(TAG, "ExtendedRemoteDisplay.listen Not available.");
+ }
+
+ try {
+ Class args[] = {};
+ sExtRemoteDisplayDispose = sExtRemoteDisplayClass.getDeclaredMethod("dispose", args);
+ } catch (Throwable t) {
+ Slog.i(TAG, "ExtendedRemoteDisplay.dispose Not available.");
+ }
+ }
+ }
+
+ /**
+ * Starts listening for displays to be connected on the specified interface.
+ *
+ * @param iface The interface address and port in the form "x.x.x.x:y".
+ * @param listener The listener to invoke
+ * when displays are connected or disconnected.
+ * @param handler The handler on which to invoke the listener.
+ * @param context The current service context
+ * */
+ public static Object listen(String iface, RemoteDisplay.Listener listener,
+ Handler handler, Context context)
+ {
+ Object extRemoteDisplay = null;
+ Slog.i(TAG, "ExtendedRemoteDisplay.listen");
+
+ if(sExtRemoteDisplayListen != null && sExtRemoteDisplayDispose != null){
+ try {
+ extRemoteDisplay = sExtRemoteDisplayListen.invoke(null,
+ iface, listener, handler, context);
+ } catch (InvocationTargetException e) {
+ Slog.i(TAG, "ExtendedRemoteDisplay.listen - InvocationTargetException");
+ Throwable cause = e.getCause();
+ if (cause instanceof RuntimeException) {
+ throw (RuntimeException) cause;
+ } else if (cause instanceof Error) {
+ throw (Error) cause;
+ } else {
+ throw new RuntimeException(e);
+ }
+ } catch (IllegalAccessException e) {
+ Slog.i(TAG, "ExtendedRemoteDisplay.listen -IllegalAccessException");
+ e.printStackTrace();
+ }
+ }
+ return extRemoteDisplay;
+ }
+
+ /**
+ * Disconnects the remote display and stops listening for new connections.
+ */
+ public static void dispose(Object extRemoteDisplay) {
+ Slog.i(TAG, "ExtendedRemoteDisplay.dispose");
+ try{
+ sExtRemoteDisplayDispose.invoke(extRemoteDisplay);
+ } catch (InvocationTargetException e) {
+ Slog.i(TAG, "ExtendedRemoteDisplay.dispose - InvocationTargetException");
+ Throwable cause = e.getCause();
+ if (cause instanceof RuntimeException) {
+ throw (RuntimeException) cause;
+ } else if (cause instanceof Error) {
+ throw (Error) cause;
+ } else {
+ throw new RuntimeException(e);
+ }
+ } catch (IllegalAccessException e) {
+ Slog.i(TAG, "ExtendedRemoteDisplay.dispose-IllegalAccessException");
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Checks if ExtendedRemoteDisplay is available
+ */
+ public static boolean isAvailable()
+ {
+ if(sExtRemoteDisplayClass != null &&
+ sExtRemoteDisplayDispose != null &&
+ sExtRemoteDisplayListen != null) {
+ Slog.i(TAG, "ExtendedRemoteDisplay isAvailable() : Available.");
+ return true;
+ }
+ Slog.i(TAG, "ExtendedRemoteDisplay isAvailable() : Not Available.");
+ return false;
+ }
+}
diff --git a/services/core/java/com/android/server/display/LiveDisplayController.java b/services/core/java/com/android/server/display/LiveDisplayController.java
new file mode 100644
index 0000000..be26c57
--- /dev/null
+++ b/services/core/java/com/android/server/display/LiveDisplayController.java
@@ -0,0 +1,825 @@
+/*
+ * Copyright (C) 2015 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 com.android.server.display;
+
+import android.animation.ValueAnimator;
+import android.animation.ValueAnimator.AnimatorUpdateListener;
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+import android.os.Parcel;
+import android.os.PowerManagerInternal;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.text.TextUtils;
+import android.text.format.DateUtils;
+import android.util.MathUtils;
+import android.util.Slog;
+
+import com.android.server.LocalServices;
+import com.android.server.accessibility.DisplayAdjustmentUtils;
+import com.android.server.twilight.TwilightListener;
+import com.android.server.twilight.TwilightManager;
+import com.android.server.twilight.TwilightState;
+
+import cyanogenmod.hardware.CMHardwareManager;
+import cyanogenmod.providers.CMSettings;
+
+import java.io.PrintWriter;
+
+public class LiveDisplayController {
+
+ private static final String TAG = "LiveDisplay";
+
+ private static final long TWILIGHT_ADJUSTMENT_TIME = DateUtils.HOUR_IN_MILLIS * 1;
+
+ private static final int OFF_TEMPERATURE = 6500;
+
+ public static final int MODE_OFF = 0;
+ public static final int MODE_NIGHT = 1;
+ public static final int MODE_AUTO = 2;
+ public static final int MODE_OUTDOOR = 3;
+ public static final int MODE_DAY = 4;
+
+ private int mColorTemperature = OFF_TEMPERATURE;
+ private float mCurrentLux = 0.0f;
+
+ private int mHintCounter;
+ private int mMode;
+
+ private boolean mOutdoorMode;
+ private boolean mColorEnhancement;
+ private boolean mLowPower;
+
+ private final Context mContext;
+ private final Handler mHandler;
+
+ private CMHardwareManager mHardware;
+
+ private int mDayTemperature;
+ private int mNightTemperature;
+
+ private boolean mUseOutdoorMode;
+ private boolean mUseColorEnhancement;
+ private boolean mUseLowPower;
+
+ private final float[] mColorAdjustment = new float[] { 1.0f, 1.0f, 1.0f };
+ private final float[] mRGB = new float[] { 0.0f, 0.0f, 0.0f };
+
+ private TwilightManager mTwilightManager;
+ private boolean mSunset = false;
+
+ private SettingsObserver mObserver;
+
+ private ValueAnimator mAnimator;
+
+ private int mDefaultDayTemperature;
+ private int mDefaultNightTemperature;
+ private int mDefaultOutdoorLux;
+
+ private boolean mInitialized = false;
+
+ private static final int MSG_UPDATE_LIVE_DISPLAY = 1;
+
+ // Display postprocessing can have power impact. Disable it if powersave mode is on.
+ private boolean mLowPerformance = false;
+ private PowerManagerInternal.LowPowerModeListener mLowPowerModeListener =
+ new PowerManagerInternal.LowPowerModeListener() {
+ @Override
+ public void onLowPowerModeChanged(boolean enabled) {
+ mLowPerformance = enabled;
+ updateLiveDisplay(mCurrentLux);
+ }
+ };
+
+ LiveDisplayController(Context context, Looper looper) {
+ mContext = context;
+ mHandler = new LiveDisplayHandler(looper);
+ }
+
+ void systemReady() {
+ mHardware = CMHardwareManager.getInstance(mContext);
+
+ mDefaultDayTemperature = mContext.getResources().getInteger(
+ org.cyanogenmod.platform.internal.R.integer.config_dayColorTemperature);
+ mDefaultNightTemperature = mContext.getResources().getInteger(
+ org.cyanogenmod.platform.internal.R.integer.config_nightColorTemperature);
+ mDefaultOutdoorLux = mContext.getResources().getInteger(
+ org.cyanogenmod.platform.internal.R.integer.config_outdoorAmbientLux);
+
+ // Counter used to determine when we should tell the user about this feature.
+ // If it's not used after 3 sunsets, we'll show the hint once.
+ mHintCounter = CMSettings.System.getIntForUser(mContext.getContentResolver(),
+ CMSettings.System.LIVE_DISPLAY_HINTED,
+ -3,
+ UserHandle.USER_CURRENT);
+
+ mUseOutdoorMode =
+ mHardware.isSupported(CMHardwareManager.FEATURE_SUNLIGHT_ENHANCEMENT);
+
+ mUseLowPower =
+ mHardware.isSupported(CMHardwareManager.FEATURE_ADAPTIVE_BACKLIGHT);
+ if (mUseLowPower) {
+ mLowPower = mHardware.get(CMHardwareManager.FEATURE_ADAPTIVE_BACKLIGHT);
+ }
+
+ mUseColorEnhancement =
+ mHardware.isSupported(CMHardwareManager.FEATURE_COLOR_ENHANCEMENT);
+ if (mUseColorEnhancement) {
+ mColorEnhancement =
+ mHardware.get(CMHardwareManager.FEATURE_COLOR_ENHANCEMENT);
+ }
+
+ updateSettings();
+
+ mObserver = new SettingsObserver();
+ mObserver.register(true);
+
+ PowerManagerInternal pmi = LocalServices.getService(PowerManagerInternal.class);
+ pmi.registerLowPowerModeObserver(mLowPowerModeListener);
+ mLowPerformance = pmi.getLowPowerModeEnabled();
+
+ mTwilightManager = LocalServices.getService(TwilightManager.class);
+ mTwilightManager.registerListener(mTwilightListener, mHandler);
+
+ mInitialized = true;
+ }
+
+ private void updateSettings() {
+ mDayTemperature = CMSettings.System.getIntForUser(mContext.getContentResolver(),
+ CMSettings.System.DISPLAY_TEMPERATURE_DAY,
+ mDefaultDayTemperature,
+ UserHandle.USER_CURRENT);
+ mNightTemperature = CMSettings.System.getIntForUser(mContext.getContentResolver(),
+ CMSettings.System.DISPLAY_TEMPERATURE_NIGHT,
+ mDefaultNightTemperature,
+ UserHandle.USER_CURRENT);
+ mMode = CMSettings.System.getIntForUser(mContext.getContentResolver(),
+ CMSettings.System.DISPLAY_TEMPERATURE_MODE,
+ MODE_OFF,
+ UserHandle.USER_CURRENT);
+
+ // Clear the hint forever
+ if (mMode != MODE_OFF) {
+ saveUserHint(1);
+ }
+
+ // Manual color adjustment will be set as a space separated string of float values
+ String colorAdjustmentTemp = CMSettings.System.getStringForUser(mContext.getContentResolver(),
+ CMSettings.System.DISPLAY_COLOR_ADJUSTMENT,
+ UserHandle.USER_CURRENT);
+ String[] colorAdjustment = colorAdjustmentTemp == null ?
+ null : colorAdjustmentTemp.split(" ");
+ if (colorAdjustment == null || colorAdjustment.length != 3) {
+ colorAdjustment = new String[] { "1.0", "1.0", "1.0" };
+ }
+ try {
+ mColorAdjustment[0] = Float.parseFloat(colorAdjustment[0]);
+ mColorAdjustment[1] = Float.parseFloat(colorAdjustment[1]);
+ mColorAdjustment[2] = Float.parseFloat(colorAdjustment[2]);
+ } catch (NumberFormatException e) {
+ Slog.e(TAG, e.getMessage(), e);
+ mColorAdjustment[0] = 1.0f;
+ mColorAdjustment[1] = 1.0f;
+ mColorAdjustment[2] = 1.0f;
+ }
+
+ updateLiveDisplay(mCurrentLux);
+ }
+
+ private final class SettingsObserver extends ContentObserver {
+ private final Uri DISPLAY_TEMPERATURE_DAY_URI =
+ CMSettings.System.getUriFor(CMSettings.System.DISPLAY_TEMPERATURE_DAY);
+ private final Uri DISPLAY_TEMPERATURE_NIGHT_URI =
+ CMSettings.System.getUriFor(CMSettings.System.DISPLAY_TEMPERATURE_NIGHT);
+ private final Uri DISPLAY_TEMPERATURE_MODE_URI =
+ CMSettings.System.getUriFor(CMSettings.System.DISPLAY_TEMPERATURE_MODE);
+ private final Uri DISPLAY_AUTO_OUTDOOR_MODE_URI =
+ CMSettings.System.getUriFor(CMSettings.System.DISPLAY_AUTO_OUTDOOR_MODE);
+ private final Uri DISPLAY_LOW_POWER_URI =
+ CMSettings.System.getUriFor(CMSettings.System.DISPLAY_LOW_POWER);
+ private final Uri DISPLAY_COLOR_ENHANCE_URI =
+ CMSettings.System.getUriFor(CMSettings.System.DISPLAY_COLOR_ENHANCE);
+ private final Uri DISPLAY_COLOR_ADJUSTMENT_URI =
+ CMSettings.System.getUriFor(CMSettings.System.DISPLAY_COLOR_ADJUSTMENT);
+ public SettingsObserver() {
+ super(mHandler);
+ }
+
+ public void register(boolean register) {
+ final ContentResolver cr = mContext.getContentResolver();
+ if (register) {
+ cr.registerContentObserver(DISPLAY_TEMPERATURE_DAY_URI, false, this, UserHandle.USER_ALL);
+ cr.registerContentObserver(DISPLAY_TEMPERATURE_NIGHT_URI, false, this, UserHandle.USER_ALL);
+ cr.registerContentObserver(DISPLAY_TEMPERATURE_MODE_URI, false, this, UserHandle.USER_ALL);
+ cr.registerContentObserver(DISPLAY_AUTO_OUTDOOR_MODE_URI, false, this, UserHandle.USER_ALL);
+ cr.registerContentObserver(DISPLAY_LOW_POWER_URI, false, this, UserHandle.USER_ALL);
+ cr.registerContentObserver(DISPLAY_COLOR_ENHANCE_URI, false, this, UserHandle.USER_ALL);
+ cr.registerContentObserver(DISPLAY_COLOR_ADJUSTMENT_URI, false, this, UserHandle.USER_ALL);
+ } else {
+ cr.unregisterContentObserver(this);
+ }
+ }
+
+ @Override
+ public void onChange(boolean selfChange, Uri uri) {
+ super.onChange(selfChange, uri);
+ updateSettings();
+ }
+ }
+
+ public void updateLiveDisplay() {
+ updateLiveDisplay(mCurrentLux);
+ }
+
+ synchronized void updateLiveDisplay(float lux) {
+ mCurrentLux = lux;
+ mHandler.removeMessages(MSG_UPDATE_LIVE_DISPLAY);
+ mHandler.sendEmptyMessage(MSG_UPDATE_LIVE_DISPLAY);
+ }
+
+ private synchronized void updateColorTemperature(TwilightState twilight) {
+ int temperature = mDayTemperature;
+ if (mMode == MODE_OFF || mLowPerformance) {
+ temperature = OFF_TEMPERATURE;
+ } else if (mMode == MODE_NIGHT) {
+ temperature = mNightTemperature;
+ } else if (mMode == MODE_AUTO) {
+ temperature = getTwilightK(twilight);
+ }
+
+ if (mAnimator != null) {
+ mAnimator.cancel();
+ }
+ mAnimator = ValueAnimator.ofInt(mColorTemperature, temperature);
+ mAnimator.setDuration(Math.abs(mColorTemperature - temperature) / 2);
+ mAnimator.addUpdateListener(new AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ setDisplayTemperature((Integer)animation.getAnimatedValue());
+ }
+ });
+ mAnimator.start();
+ }
+
+ private synchronized void setDisplayTemperature(int temperature) {
+ mColorTemperature = temperature;
+
+ final float[] rgb = temperatureToRGB(temperature);
+
+ if (!mLowPerformance) {
+ rgb[0] *= mColorAdjustment[0];
+ rgb[1] *= mColorAdjustment[1];
+ rgb[2] *= mColorAdjustment[2];
+ }
+
+ if (rgb[0] == mRGB[0] && rgb[1] == mRGB[1] && rgb[2] == mRGB[2]) {
+ // no changes
+ return;
+ }
+
+ System.arraycopy(rgb, 0, mRGB, 0, 3);
+
+ Slog.d(TAG, "Adjust display temperature to " + temperature +
+ "K [r=" + rgb[0] + " g=" + rgb[1] + " b=" + rgb[2] + "]");
+
+ if (mHardware.isSupported(CMHardwareManager.FEATURE_DISPLAY_COLOR_CALIBRATION)) {
+ // Clear this out in case of an upgrade
+ CMSettings.Secure.putStringForUser(mContext.getContentResolver(),
+ CMSettings.Secure.LIVE_DISPLAY_COLOR_MATRIX,
+ null,
+ UserHandle.USER_CURRENT);
+
+ int max = mHardware.getDisplayColorCalibrationMax();
+ mHardware.setDisplayColorCalibration(new int[] {
+ (int) Math.ceil(rgb[0] * max),
+ (int) Math.ceil(rgb[1] * max),
+ (int) Math.ceil(rgb[2] * max)
+ });
+ screenRefresh();
+ } else {
+ String colorMatrixStr = null;
+ if (rgb[0] != 1.0f || rgb[1] != 1.0f || rgb[2] != 1.0f) {
+ final Float[] colorMatrix = new Float[] {
+ rgb[0], 0.0f, 0.0f, 0.0f,
+ 0.0f, rgb[1], 0.0f, 0.0f,
+ 0.0f, 0.0f, rgb[2], 0.0f,
+ 0.0f, 0.0f, 0.0f, 1.0f };
+ colorMatrixStr = TextUtils.join(" ", colorMatrix);
+ }
+
+ // For GPU color transform, go thru DisplayAdjustmentUtils in
+ // order to coexist with accessibility settings
+ CMSettings.Secure.putStringForUser(mContext.getContentResolver(),
+ CMSettings.Secure.LIVE_DISPLAY_COLOR_MATRIX,
+ colorMatrixStr,
+ UserHandle.USER_CURRENT);
+
+ DisplayAdjustmentUtils.applyAdjustments(mContext, UserHandle.USER_CURRENT);
+ }
+ }
+
+ /**
+ * Outdoor mode is optionally enabled when ambient lux > 10000 and it's daytime
+ * Melt faces!
+ *
+ * TODO: Use the camera or RGB sensor to determine if it's really sunlight
+ */
+ private synchronized void updateOutdoorMode(TwilightState twilight) {
+ if (!mUseOutdoorMode) {
+ return;
+ }
+
+ boolean value = CMSettings.System.getIntForUser(mContext.getContentResolver(),
+ CMSettings.System.DISPLAY_AUTO_OUTDOOR_MODE,
+ 1,
+ UserHandle.USER_CURRENT) == 1;
+
+ boolean enabled = !mLowPerformance &&
+ ((mMode == MODE_OUTDOOR) ||
+ (value && mMode == MODE_AUTO &&
+ twilight != null && !twilight.isNight() &&
+ mCurrentLux > mDefaultOutdoorLux));
+
+ if (enabled == mOutdoorMode) {
+ return;
+ }
+
+ mHardware.set(CMHardwareManager.FEATURE_SUNLIGHT_ENHANCEMENT, enabled);
+ mOutdoorMode = enabled;
+ }
+
+ /**
+ * Color enhancement is optional, but can look bad with night mode
+ */
+ private synchronized void updateColorEnhancement(TwilightState twilight) {
+ if (!mUseColorEnhancement) {
+ return;
+ }
+
+ boolean value = CMSettings.System.getIntForUser(mContext.getContentResolver(),
+ CMSettings.System.DISPLAY_COLOR_ENHANCE,
+ 1,
+ UserHandle.USER_CURRENT) == 1;
+
+ boolean enabled = !mLowPerformance && value &&
+ !(mMode == MODE_NIGHT ||
+ (mMode == MODE_AUTO && twilight != null && twilight.isNight()));
+
+ if (enabled == mColorEnhancement) {
+ return;
+ }
+
+ mHardware.set(CMHardwareManager.FEATURE_COLOR_ENHANCEMENT, enabled);
+ mColorEnhancement = enabled;
+ }
+
+ /**
+ * Adaptive backlight / low power mode. Turn it off when under very bright light.
+ */
+ private synchronized void updateLowPowerMode() {
+ if (!mUseLowPower) {
+ return;
+ }
+
+ boolean value = CMSettings.System.getIntForUser(mContext.getContentResolver(),
+ CMSettings.System.DISPLAY_LOW_POWER,
+ 1,
+ UserHandle.USER_CURRENT) == 1;
+
+ boolean enabled = value && (mCurrentLux < mDefaultOutdoorLux);
+
+ if (enabled == mLowPower) {
+ return;
+ }
+
+ mHardware.set(CMHardwareManager.FEATURE_ADAPTIVE_BACKLIGHT, enabled);
+ mLowPower = enabled;
+ }
+
+ /**
+ * Convert a color temperature value (in Kelvin) to a RGB units as floats.
+ * This can be used in a transform matrix or hardware gamma control.
+ *
+ * @param tempK
+ * @return
+ */
+ private static float[] temperatureToRGB(int degreesK) {
+ int k = MathUtils.constrain(degreesK, 1000, 20000);
+ float a = (k % 100) / 100.0f;
+ int i = ((k - 1000)/ 100) * 3;
+
+ return new float[] { interp(i, a), interp(i+1, a), interp(i+2, a) };
+ }
+
+ private static float interp(int i, float a) {
+ return MathUtils.lerp((float)sColorTable[i], (float)sColorTable[i+3], a);
+ }
+
+ /**
+ * Where is the sun anyway? This calculation determines day or night, and scales
+ * the value around sunset/sunrise for a smooth transition.
+ *
+ * @param now
+ * @param sunset
+ * @param sunrise
+ * @return float between 0 and 1
+ */
+ private static float adj(long now, long sunset, long sunrise) {
+ if (sunset < 0 || sunrise < 0
+ || now < sunset || now > sunrise) {
+ return 1.0f;
+ }
+
+ if (now < sunset + TWILIGHT_ADJUSTMENT_TIME) {
+ return MathUtils.lerp(1.0f, 0.0f,
+ (float)(now - sunset) / TWILIGHT_ADJUSTMENT_TIME);
+ }
+
+ if (now > sunrise - TWILIGHT_ADJUSTMENT_TIME) {
+ return MathUtils.lerp(1.0f, 0.0f,
+ (float)(sunrise - now) / TWILIGHT_ADJUSTMENT_TIME);
+ }
+
+ return 0.0f;
+ }
+
+ /**
+ * Determine the color temperature we should use for the display based on
+ * the position of the sun.
+ *
+ * @param state
+ * @return color temperature in Kelvin
+ */
+ private int getTwilightK(TwilightState state) {
+ float adjustment = 1.0f;
+
+ if (state != null) {
+ final long now = System.currentTimeMillis();
+ adjustment = adj(now, state.getYesterdaySunset(), state.getTodaySunrise()) *
+ adj(now, state.getTodaySunset(), state.getTomorrowSunrise());
+ }
+
+ return (int)MathUtils.lerp(mNightTemperature, mDayTemperature, adjustment);
+ }
+
+ /**
+ * Tell SurfaceFlinger to repaint the screen. This is called after updating
+ * hardware registers for display calibration to have an immediate effect.
+ */
+ private static void screenRefresh() {
+ try {
+ final IBinder flinger = ServiceManager.getService("SurfaceFlinger");
+ if (flinger != null) {
+ final Parcel data = Parcel.obtain();
+ data.writeInterfaceToken("android.ui.ISurfaceComposer");
+ flinger.transact(1004, data, null, 0);
+ data.recycle();
+ }
+ } catch (RemoteException ex) {
+ Slog.e(TAG, "Failed to refresh screen", ex);
+ }
+ }
+
+ private void saveUserHint(int value) {
+ if (mHintCounter == value) {
+ return;
+ }
+ CMSettings.System.putIntForUser(mContext.getContentResolver(),
+ CMSettings.System.LIVE_DISPLAY_HINTED,
+ value,
+ UserHandle.USER_CURRENT);
+ mHintCounter = value;
+ }
+
+ /**
+ * Show a friendly notification to the user about the potential benefits of decreasing
+ * blue light at night. Do this only once if the feature has not been used after
+ * three sunsets. It would be great to enable this by default, but we don't want
+ * the change of screen color to be considered a "bug" by a user who doesn't
+ * understand what's happening.
+ *
+ * @param state
+ */
+ private void updateUserHint(TwilightState state) {
+ // check if we should send the hint only once after sunset
+ if (state == null || mHintCounter == 1) {
+ return;
+ }
+ boolean transition = state.isNight() && !mSunset;
+ mSunset = state.isNight();
+ if (!transition) {
+ return;
+ }
+
+ if (mHintCounter <= 0) {
+ mHintCounter++;
+ saveUserHint(mHintCounter);
+ }
+ if (mHintCounter == 0) {
+ //show the notification and don't come back here
+ final Intent intent = new Intent("android.settings.LIVEDISPLAY_SETTINGS");
+ PendingIntent result = PendingIntent.getActivity(
+ mContext, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
+ Notification.Builder builder = new Notification.Builder(mContext)
+ .setContentTitle(mContext.getResources().getString(
+ org.cyanogenmod.platform.internal.R.string.live_display_title))
+ .setContentText(mContext.getResources().getString(
+ org.cyanogenmod.platform.internal.R.string.live_display_hint))
+ .setSmallIcon(org.cyanogenmod.platform.internal.R.drawable.ic_livedisplay_notif)
+ .setStyle(new Notification.BigTextStyle().bigText(mContext.getResources()
+ .getString(
+ org.cyanogenmod.platform.internal.R.string.live_display_hint)))
+ .setContentIntent(result);
+
+ NotificationManager nm =
+ (NotificationManager)mContext.getSystemService(Context.NOTIFICATION_SERVICE);
+ nm.notifyAsUser(null, 1, builder.build(), UserHandle.CURRENT);
+
+ saveUserHint(1);
+ }
+ }
+
+ private final TwilightListener mTwilightListener = new TwilightListener() {
+ @Override
+ public void onTwilightStateChanged() {
+ updateLiveDisplay(mCurrentLux);
+ }
+ };
+
+ private final class LiveDisplayHandler extends Handler {
+ public LiveDisplayHandler(Looper looper) {
+ super(looper, null, true /*async*/);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_UPDATE_LIVE_DISPLAY:
+ if (!mInitialized) {
+ break;
+ }
+ TwilightState twilight = mTwilightManager.getCurrentState();
+
+ updateColorTemperature(twilight);
+ updateOutdoorMode(twilight);
+ updateColorEnhancement(twilight);
+ updateLowPowerMode();
+ updateUserHint(twilight);
+
+ boolean transition = mMode == MODE_AUTO &&
+ mColorTemperature != mDayTemperature &&
+ mColorTemperature != mNightTemperature;
+ if (transition) {
+ // fire again in a minute
+ sendEmptyMessageDelayed(MSG_UPDATE_LIVE_DISPLAY,
+ DateUtils.MINUTE_IN_MILLIS);
+ }
+ break;
+ }
+ }
+ }
+
+ public void dump(PrintWriter pw) {
+ pw.println();
+ pw.println("LiveDisplay Controller Configuration:");
+ pw.println(" mDayTemperature=" + mDayTemperature);
+ pw.println(" mNightTemperature=" + mNightTemperature);
+ pw.println();
+ pw.println("LiveDisplay Controller State:");
+ pw.println(" mMode=" + (mLowPerformance ? "disabled in powersave mode" : mMode));
+ pw.println(" mSunset=" + mSunset);
+ pw.println(" mColorTemperature=" + mColorTemperature);
+ pw.println(" mColorAdjustment=[r: " + mColorAdjustment[0] + " g:" + mColorAdjustment[1] +
+ " b:" + mColorAdjustment[2] + "]");
+ pw.println(" mRGB=[r:" + mRGB[0] + " g:" + mRGB[1] + " b:" + mRGB[2] + "]");
+ pw.println(" mOutdoorMode=" + (mUseOutdoorMode ? mOutdoorMode : "N/A"));
+ pw.println(" mColorEnhancement=" + (mUseColorEnhancement ? mColorEnhancement : "N/A"));
+ pw.println(" mLowPower=" + (mUseLowPower ? mLowPower : "N/A"));
+ }
+
+ /**
+ * This table is a modified version of the original blackbody chart, found here:
+ * http://www.vendian.org/mncharity/dir3/blackbody/UnstableURLs/bbr_color.html
+ *
+ * Created by Ingo Thiel.
+ */
+ private static final double[] sColorTable = new double[] {
+ 1.00000000, 0.18172716, 0.00000000,
+ 1.00000000, 0.25503671, 0.00000000,
+ 1.00000000, 0.30942099, 0.00000000,
+ 1.00000000, 0.35357379, 0.00000000,
+ 1.00000000, 0.39091524, 0.00000000,
+ 1.00000000, 0.42322816, 0.00000000,
+ 1.00000000, 0.45159884, 0.00000000,
+ 1.00000000, 0.47675916, 0.00000000,
+ 1.00000000, 0.49923747, 0.00000000,
+ 1.00000000, 0.51943421, 0.00000000,
+ 1.00000000, 0.54360078, 0.08679949,
+ 1.00000000, 0.56618736, 0.14065513,
+ 1.00000000, 0.58734976, 0.18362641,
+ 1.00000000, 0.60724493, 0.22137978,
+ 1.00000000, 0.62600248, 0.25591950,
+ 1.00000000, 0.64373109, 0.28819679,
+ 1.00000000, 0.66052319, 0.31873863,
+ 1.00000000, 0.67645822, 0.34786758,
+ 1.00000000, 0.69160518, 0.37579588,
+ 1.00000000, 0.70602449, 0.40267128,
+ 1.00000000, 0.71976951, 0.42860152,
+ 1.00000000, 0.73288760, 0.45366838,
+ 1.00000000, 0.74542112, 0.47793608,
+ 1.00000000, 0.75740814, 0.50145662,
+ 1.00000000, 0.76888303, 0.52427322,
+ 1.00000000, 0.77987699, 0.54642268,
+ 1.00000000, 0.79041843, 0.56793692,
+ 1.00000000, 0.80053332, 0.58884417,
+ 1.00000000, 0.81024551, 0.60916971,
+ 1.00000000, 0.81957693, 0.62893653,
+ 1.00000000, 0.82854786, 0.64816570,
+ 1.00000000, 0.83717703, 0.66687674,
+ 1.00000000, 0.84548188, 0.68508786,
+ 1.00000000, 0.85347859, 0.70281616,
+ 1.00000000, 0.86118227, 0.72007777,
+ 1.00000000, 0.86860704, 0.73688797,
+ 1.00000000, 0.87576611, 0.75326132,
+ 1.00000000, 0.88267187, 0.76921169,
+ 1.00000000, 0.88933596, 0.78475236,
+ 1.00000000, 0.89576933, 0.79989606,
+ 1.00000000, 0.90198230, 0.81465502,
+ 1.00000000, 0.90963069, 0.82838210,
+ 1.00000000, 0.91710889, 0.84190889,
+ 1.00000000, 0.92441842, 0.85523742,
+ 1.00000000, 0.93156127, 0.86836903,
+ 1.00000000, 0.93853986, 0.88130458,
+ 1.00000000, 0.94535695, 0.89404470,
+ 1.00000000, 0.95201559, 0.90658983,
+ 1.00000000, 0.95851906, 0.91894041,
+ 1.00000000, 0.96487079, 0.93109690,
+ 1.00000000, 0.97107439, 0.94305985,
+ 1.00000000, 0.97713351, 0.95482993,
+ 1.00000000, 0.98305189, 0.96640795,
+ 1.00000000, 0.98883326, 0.97779486,
+ 1.00000000, 0.99448139, 0.98899179,
+ 1.00000000, 1.00000000, 1.00000000,
+ 0.98947904, 0.99348723, 1.00000000,
+ 0.97940448, 0.98722715, 1.00000000,
+ 0.96975025, 0.98120637, 1.00000000,
+ 0.96049223, 0.97541240, 1.00000000,
+ 0.95160805, 0.96983355, 1.00000000,
+ 0.94303638, 0.96443333, 1.00000000,
+ 0.93480451, 0.95923080, 1.00000000,
+ 0.92689056, 0.95421394, 1.00000000,
+ 0.91927697, 0.94937330, 1.00000000,
+ 0.91194747, 0.94470005, 1.00000000,
+ 0.90488690, 0.94018594, 1.00000000,
+ 0.89808115, 0.93582323, 1.00000000,
+ 0.89151710, 0.93160469, 1.00000000,
+ 0.88518247, 0.92752354, 1.00000000,
+ 0.87906581, 0.92357340, 1.00000000,
+ 0.87315640, 0.91974827, 1.00000000,
+ 0.86744421, 0.91604254, 1.00000000,
+ 0.86191983, 0.91245088, 1.00000000,
+ 0.85657444, 0.90896831, 1.00000000,
+ 0.85139976, 0.90559011, 1.00000000,
+ 0.84638799, 0.90231183, 1.00000000,
+ 0.84153180, 0.89912926, 1.00000000,
+ 0.83682430, 0.89603843, 1.00000000,
+ 0.83225897, 0.89303558, 1.00000000,
+ 0.82782969, 0.89011714, 1.00000000,
+ 0.82353066, 0.88727974, 1.00000000,
+ 0.81935641, 0.88452017, 1.00000000,
+ 0.81530175, 0.88183541, 1.00000000,
+ 0.81136180, 0.87922257, 1.00000000,
+ 0.80753191, 0.87667891, 1.00000000,
+ 0.80380769, 0.87420182, 1.00000000,
+ 0.80018497, 0.87178882, 1.00000000,
+ 0.79665980, 0.86943756, 1.00000000,
+ 0.79322843, 0.86714579, 1.00000000,
+ 0.78988728, 0.86491137, 1.00000000,
+ 0.78663296, 0.86273225, 1.00000000,
+ 0.78346225, 0.86060650, 1.00000000,
+ 0.78037207, 0.85853224, 1.00000000,
+ 0.77735950, 0.85650771, 1.00000000,
+ 0.77442176, 0.85453121, 1.00000000,
+ 0.77155617, 0.85260112, 1.00000000,
+ 0.76876022, 0.85071588, 1.00000000,
+ 0.76603147, 0.84887402, 1.00000000,
+ 0.76336762, 0.84707411, 1.00000000,
+ 0.76076645, 0.84531479, 1.00000000,
+ 0.75822586, 0.84359476, 1.00000000,
+ 0.75574383, 0.84191277, 1.00000000,
+ 0.75331843, 0.84026762, 1.00000000,
+ 0.75094780, 0.83865816, 1.00000000,
+ 0.74863017, 0.83708329, 1.00000000,
+ 0.74636386, 0.83554194, 1.00000000,
+ 0.74414722, 0.83403311, 1.00000000,
+ 0.74197871, 0.83255582, 1.00000000,
+ 0.73985682, 0.83110912, 1.00000000,
+ 0.73778012, 0.82969211, 1.00000000,
+ 0.73574723, 0.82830393, 1.00000000,
+ 0.73375683, 0.82694373, 1.00000000,
+ 0.73180765, 0.82561071, 1.00000000,
+ 0.72989845, 0.82430410, 1.00000000,
+ 0.72802807, 0.82302316, 1.00000000,
+ 0.72619537, 0.82176715, 1.00000000,
+ 0.72439927, 0.82053539, 1.00000000,
+ 0.72263872, 0.81932722, 1.00000000,
+ 0.72091270, 0.81814197, 1.00000000,
+ 0.71922025, 0.81697905, 1.00000000,
+ 0.71756043, 0.81583783, 1.00000000,
+ 0.71593234, 0.81471775, 1.00000000,
+ 0.71433510, 0.81361825, 1.00000000,
+ 0.71276788, 0.81253878, 1.00000000,
+ 0.71122987, 0.81147883, 1.00000000,
+ 0.70972029, 0.81043789, 1.00000000,
+ 0.70823838, 0.80941546, 1.00000000,
+ 0.70678342, 0.80841109, 1.00000000,
+ 0.70535469, 0.80742432, 1.00000000,
+ 0.70395153, 0.80645469, 1.00000000,
+ 0.70257327, 0.80550180, 1.00000000,
+ 0.70121928, 0.80456522, 1.00000000,
+ 0.69988894, 0.80364455, 1.00000000,
+ 0.69858167, 0.80273941, 1.00000000,
+ 0.69729688, 0.80184943, 1.00000000,
+ 0.69603402, 0.80097423, 1.00000000,
+ 0.69479255, 0.80011347, 1.00000000,
+ 0.69357196, 0.79926681, 1.00000000,
+ 0.69237173, 0.79843391, 1.00000000,
+ 0.69119138, 0.79761446, 1.00000000,
+ 0.69003044, 0.79680814, 1.00000000,
+ 0.68888844, 0.79601466, 1.00000000,
+ 0.68776494, 0.79523371, 1.00000000,
+ 0.68665951, 0.79446502, 1.00000000,
+ 0.68557173, 0.79370830, 1.00000000,
+ 0.68450119, 0.79296330, 1.00000000,
+ 0.68344751, 0.79222975, 1.00000000,
+ 0.68241029, 0.79150740, 1.00000000,
+ 0.68138918, 0.79079600, 1.00000000,
+ 0.68038380, 0.79009531, 1.00000000,
+ 0.67939381, 0.78940511, 1.00000000,
+ 0.67841888, 0.78872517, 1.00000000,
+ 0.67745866, 0.78805526, 1.00000000,
+ 0.67651284, 0.78739518, 1.00000000,
+ 0.67558112, 0.78674472, 1.00000000,
+ 0.67466317, 0.78610368, 1.00000000,
+ 0.67375872, 0.78547186, 1.00000000,
+ 0.67286748, 0.78484907, 1.00000000,
+ 0.67198916, 0.78423512, 1.00000000,
+ 0.67112350, 0.78362984, 1.00000000,
+ 0.67027024, 0.78303305, 1.00000000,
+ 0.66942911, 0.78244457, 1.00000000,
+ 0.66859988, 0.78186425, 1.00000000,
+ 0.66778228, 0.78129191, 1.00000000,
+ 0.66697610, 0.78072740, 1.00000000,
+ 0.66618110, 0.78017057, 1.00000000,
+ 0.66539706, 0.77962127, 1.00000000,
+ 0.66462376, 0.77907934, 1.00000000,
+ 0.66386098, 0.77854465, 1.00000000,
+ 0.66310852, 0.77801705, 1.00000000,
+ 0.66236618, 0.77749642, 1.00000000,
+ 0.66163375, 0.77698261, 1.00000000,
+ 0.66091106, 0.77647551, 1.00000000,
+ 0.66019791, 0.77597498, 1.00000000,
+ 0.65949412, 0.77548090, 1.00000000,
+ 0.65879952, 0.77499315, 1.00000000,
+ 0.65811392, 0.77451161, 1.00000000,
+ 0.65743716, 0.77403618, 1.00000000,
+ 0.65676908, 0.77356673, 1.00000000,
+ 0.65610952, 0.77310316, 1.00000000,
+ 0.65545831, 0.77264537, 1.00000000,
+ 0.65481530, 0.77219324, 1.00000000,
+ 0.65418036, 0.77174669, 1.00000000,
+ 0.65355332, 0.77130560, 1.00000000,
+ 0.65293404, 0.77086988, 1.00000000,
+ 0.65232240, 0.77043944, 1.00000000,
+ 0.65171824, 0.77001419, 1.00000000,
+ 0.65112144, 0.76959404, 1.00000000,
+ 0.65053187, 0.76917889, 1.00000000,
+ 0.64994941, 0.76876866, 1.00000000,
+ 0.64937392, 0.76836326, 1.00000000
+ };
+}
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index 088d96e..b2207f3 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -58,6 +58,7 @@ final class LocalDisplayAdapter extends DisplayAdapter {
private static final int[] BUILT_IN_DISPLAY_IDS_TO_SCAN = new int[] {
SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN,
SurfaceControl.BUILT_IN_DISPLAY_ID_HDMI,
+ SurfaceControl.BUILT_IN_DISPLAY_ID_TERTIARY,
};
private final SparseArray<LocalDisplayDevice> mDevices =
diff --git a/services/core/java/com/android/server/display/WifiDisplayController.java b/services/core/java/com/android/server/display/WifiDisplayController.java
index 8932ca0..239f8cd 100644
--- a/services/core/java/com/android/server/display/WifiDisplayController.java
+++ b/services/core/java/com/android/server/display/WifiDisplayController.java
@@ -137,6 +137,10 @@ final class WifiDisplayController implements DumpUtils.Dump {
// Number of connection retries remaining.
private int mConnectionRetriesLeft;
+ // The Extended remote display that is listening on the connection.
+ // Created after the Wifi P2P network is connected.
+ private Object mExtRemoteDisplay;
+
// The remote display that is listening on the connection.
// Created after the Wifi P2P network is connected.
private RemoteDisplay mRemoteDisplay;
@@ -565,11 +569,19 @@ final class WifiDisplayController implements DumpUtils.Dump {
// Step 1. Before we try to connect to a new device, tell the system we
// have disconnected from the old one.
- if (mRemoteDisplay != null && mConnectedDevice != mDesiredDevice) {
- Slog.i(TAG, "Stopped listening for RTSP connection on " + mRemoteDisplayInterface
+ if ((mRemoteDisplay != null || mExtRemoteDisplay != null) &&
+ mConnectedDevice != mDesiredDevice) {
+ Slog.i(TAG, "Stopped listening for RTSP connection on "
+ + mRemoteDisplayInterface
+ " from Wifi display: " + mConnectedDevice.deviceName);
- mRemoteDisplay.dispose();
+ if(mRemoteDisplay != null) {
+ mRemoteDisplay.dispose();
+ } else if(mExtRemoteDisplay != null) {
+ ExtendedRemoteDisplayHelper.dispose(mExtRemoteDisplay);
+ }
+
+ mExtRemoteDisplay = null;
mRemoteDisplay = null;
mRemoteDisplayInterface = null;
mRemoteDisplayConnected = false;
@@ -717,7 +729,8 @@ final class WifiDisplayController implements DumpUtils.Dump {
}
// Step 6. Listen for incoming RTSP connection.
- if (mConnectedDevice != null && mRemoteDisplay == null) {
+ if (mConnectedDevice != null && mRemoteDisplay == null &&
+ mExtRemoteDisplay== null) {
Inet4Address addr = getInterfaceAddress(mConnectedDeviceGroupInfo);
if (addr == null) {
Slog.i(TAG, "Failed to get local interface address for communicating "
@@ -736,7 +749,7 @@ final class WifiDisplayController implements DumpUtils.Dump {
Slog.i(TAG, "Listening for RTSP connection on " + iface
+ " from Wifi display: " + mConnectedDevice.deviceName);
- mRemoteDisplay = RemoteDisplay.listen(iface, new RemoteDisplay.Listener() {
+ RemoteDisplay.Listener listener = new RemoteDisplay.Listener() {
@Override
public void onDisplayConnected(Surface surface,
int width, int height, int flags, int session) {
@@ -775,7 +788,14 @@ final class WifiDisplayController implements DumpUtils.Dump {
handleConnectionFailure(false);
}
}
- }, mHandler, mContext.getOpPackageName());
+ };
+ if(ExtendedRemoteDisplayHelper.isAvailable()){
+ mExtRemoteDisplay = ExtendedRemoteDisplayHelper.listen(iface,
+ listener, mHandler, mContext);
+ } else {
+ mRemoteDisplay = RemoteDisplay.listen(iface, listener,
+ mHandler, mContext.getOpPackageName());
+ }
// Use extended timeout value for certification, as some tests require user inputs
int rtspTimeout = mWifiDisplayCertMode ?
@@ -910,7 +930,8 @@ final class WifiDisplayController implements DumpUtils.Dump {
@Override
public void run() {
if (mConnectedDevice != null
- && mRemoteDisplay != null && !mRemoteDisplayConnected) {
+ && (mRemoteDisplay != null || mExtRemoteDisplay != null)
+ && !mRemoteDisplayConnected) {
Slog.i(TAG, "Timed out waiting for Wifi display RTSP connection after "
+ RTSP_TIMEOUT_SECONDS + " seconds: "
+ mConnectedDevice.deviceName);
diff --git a/services/core/java/com/android/server/dreams/DreamManagerService.java b/services/core/java/com/android/server/dreams/DreamManagerService.java
index 8813a61..7d1dbe1 100644
--- a/services/core/java/com/android/server/dreams/DreamManagerService.java
+++ b/services/core/java/com/android/server/dreams/DreamManagerService.java
@@ -18,6 +18,7 @@ package com.android.server.dreams;
import static android.Manifest.permission.BIND_DREAM_SERVICE;
+import android.view.WindowManagerPolicy;
import com.android.internal.util.DumpUtils;
import com.android.server.FgThread;
import com.android.server.SystemService;
@@ -84,6 +85,7 @@ public final class DreamManagerService extends SystemService {
private boolean mCurrentDreamIsWaking;
private int mCurrentDreamDozeScreenState = Display.STATE_UNKNOWN;
private int mCurrentDreamDozeScreenBrightness = PowerManager.BRIGHTNESS_DEFAULT;
+ private int mLidState = WindowManagerPolicy.WindowManagerFuncs.LID_ABSENT;
public DreamManagerService(Context context) {
super(context);
@@ -150,6 +152,12 @@ public final class DreamManagerService extends SystemService {
}
}
+ private boolean isDozingInternal() {
+ synchronized (mLock) {
+ return mCurrentDreamIsDozing;
+ }
+ }
+
private void requestDreamInternal() {
// Ask the power manager to nap. It will eventually call back into
// startDream() if/when it is appropriate to start dreaming.
@@ -219,7 +227,8 @@ public final class DreamManagerService extends SystemService {
}
synchronized (mLock) {
- if (mCurrentDreamToken == token && mCurrentDreamCanDoze) {
+ if (mCurrentDreamToken == token && mCurrentDreamCanDoze
+ && mLidState != WindowManagerPolicy.WindowManagerFuncs.LID_CLOSED) {
mCurrentDreamDozeScreenState = screenState;
mCurrentDreamDozeScreenBrightness = screenBrightness;
mPowerManagerInternal.setDozeOverrideFromDreamManager(
@@ -232,6 +241,40 @@ public final class DreamManagerService extends SystemService {
}
}
+ private int getLidStateInternal() {
+ return mLidState;
+ }
+
+ private void setLidStateInternal(int state) {
+ synchronized (mLock) {
+ mLidState = state;
+ }
+ switch (state) {
+ case WindowManagerPolicy.WindowManagerFuncs.LID_ABSENT:
+ // do nothing
+ break;
+ case WindowManagerPolicy.WindowManagerFuncs.LID_OPEN:
+ synchronized (mLock) {
+ mPowerManagerInternal.setDozeOverrideFromDreamManager(
+ Display.STATE_UNKNOWN, PowerManager.BRIGHTNESS_DEFAULT);
+ }
+ break;
+ case WindowManagerPolicy.WindowManagerFuncs.LID_CLOSED:
+ // mimicing logic from stopDozingInternal(), stop any thing when the lid is closed.
+ synchronized (mLock) {
+ if (mCurrentDreamIsDozing) {
+ mCurrentDreamIsDozing = false;
+ if (mDozeWakeLock.isHeld()) {
+ mDozeWakeLock.release();
+ }
+ mPowerManagerInternal.setDozeOverrideFromDreamManager(
+ Display.STATE_OFF, PowerManager.BRIGHTNESS_OFF);
+ }
+ }
+ break;
+ }
+ }
+
private void stopDozingInternal(IBinder token) {
if (DEBUG) {
Slog.d(TAG, "Dream requested to stop dozing: " + token);
@@ -530,6 +573,18 @@ public final class DreamManagerService extends SystemService {
}
@Override // Binder call
+ public boolean isDozing() {
+ checkPermission(android.Manifest.permission.READ_DREAM_STATE);
+
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ return isDozingInternal();
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ @Override // Binder call
public void dream() {
checkPermission(android.Manifest.permission.WRITE_DREAM_STATE);
@@ -621,6 +676,30 @@ public final class DreamManagerService extends SystemService {
Binder.restoreCallingIdentity(ident);
}
}
+
+ @Override
+ public void setLidState(int lidState) {
+ checkPermission(android.Manifest.permission.WRITE_DREAM_STATE);
+
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ setLidStateInternal(lidState);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ @Override
+ public int getLidState() {
+ checkPermission(Manifest.permission.READ_DREAM_STATE);
+
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ return getLidStateInternal();
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
}
private final class LocalService extends DreamManagerInternal {
@@ -638,6 +717,11 @@ public final class DreamManagerService extends SystemService {
public boolean isDreaming() {
return isDreamingInternal();
}
+
+ @Override
+ public boolean isDozing() {
+ return isDozingInternal();
+ }
}
private final Runnable mSystemPropertiesChanged = new Runnable() {
diff --git a/services/core/java/com/android/server/gesture/GestureInputFilter.java b/services/core/java/com/android/server/gesture/GestureInputFilter.java
new file mode 100644
index 0000000..e40761f
--- /dev/null
+++ b/services/core/java/com/android/server/gesture/GestureInputFilter.java
@@ -0,0 +1,333 @@
+/*
+ * Copyright (C) 2013 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 com.android.server.gesture;
+
+import android.app.PendingIntent;
+import android.app.PendingIntent.CanceledException;
+import android.content.Context;
+import android.hardware.input.InputManager;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.util.Slog;
+import android.view.Display;
+import android.view.GestureDetector;
+import android.view.GestureDetector.OnDoubleTapListener;
+import android.view.IInputFilter;
+import android.view.IInputFilterHost;
+import android.view.InputDevice;
+import android.view.InputEvent;
+import android.view.MotionEvent;
+import android.view.OrientationEventListener;
+import android.view.ViewConfiguration;
+import android.view.WindowManager;
+import java.io.PrintWriter;
+
+/**
+ * A simple input filter that listens for gesture sensor events and converts
+ * them to input events to be injected into the input stream.
+ */
+public class GestureInputFilter implements IInputFilter, GestureDetector.OnGestureListener, OnDoubleTapListener {
+
+ private static final String TAG = "GestureInputFilter";
+ private static final boolean DEBUG = false;
+
+ private IInputFilterHost mHost = null;
+
+ private GestureDetector mGestureDetector;
+ private InputManager mInputManager;
+ private OrientationEventListener mOrientationListener;
+ private final int mScreenWidth, mScreenHeight;
+ private float mGesturePadWidth, mGesturePadHeight;
+ private int mTouchSlop, mOrientation;
+ private Context mContext;
+ private PendingIntent mLongPressPendingIntent;
+ private PendingIntent mDoubleClickPendingIntent;
+
+ public GestureInputFilter(Context context) {
+ mInputManager = InputManager.getInstance();
+ mContext = context;
+ for (int id : mInputManager.getInputDeviceIds()) {
+ InputDevice inputDevice = mInputManager.getInputDevice(id);
+ if ((inputDevice.getSources() & InputDevice.SOURCE_GESTURE_SENSOR)
+ == mInputManager.getInputDevice(id).getSources()) {
+ mGesturePadWidth = inputDevice.getMotionRange(MotionEvent.AXIS_X).getMax();
+ mGesturePadHeight = inputDevice.getMotionRange(MotionEvent.AXIS_Y).getMax();
+ break;
+ }
+ }
+ ViewConfiguration vc = ViewConfiguration.get(context);
+ mTouchSlop = vc.getScaledTouchSlop();
+ WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
+ Display display = wm.getDefaultDisplay();
+ mScreenWidth = display.getWidth();
+ mScreenHeight = display.getHeight();
+ mGestureDetector = new GestureDetector(context, this);
+ mGestureDetector.setOnDoubleTapListener(this);
+ mOrientationListener = new OrientationEventListener(context) {
+ @Override
+ public void onOrientationChanged(int orientation) {
+ if (orientation == -1) {
+ return;
+ }
+ mOrientation = (orientation + 45) / 90 * 90;
+ }
+ };
+ }
+
+ /**
+ * Called to enqueue the input event for filtering.
+ * The event must be recycled after the input filter processed it.
+ * This method is guaranteed to be non-reentrant.
+ *
+ * @see InputFilter#filterInputEvent(InputEvent, int)
+ * @param event The input event to enqueue.
+ */
+ // called by the input dispatcher thread
+ public void filterInputEvent(InputEvent event, int policyFlags)
+ throws RemoteException {
+ if (DEBUG) Slog.d(TAG, event.toString());
+
+ try {
+ if (event.getSource() != InputDevice.SOURCE_GESTURE_SENSOR
+ || !(event instanceof MotionEvent)) {
+ try {
+ mHost.sendInputEvent(event, policyFlags);
+ } catch (RemoteException e) {
+ /* ignore */
+ }
+ return;
+ }
+
+ MotionEvent motionEvent = (MotionEvent) event;
+ mGestureDetector.onTouchEvent(motionEvent);
+ } finally {
+ event.recycle();
+ }
+ }
+
+ // called by the input dispatcher thread
+ public void install(IInputFilterHost host) throws RemoteException {
+ if (DEBUG) {
+ Slog.d(TAG, "Gesture input filter installed.");
+ }
+ mHost = host;
+ mOrientationListener.enable();
+ }
+
+ // called by the input dispatcher thread
+ public void uninstall() throws RemoteException {
+ if (DEBUG) {
+ Slog.d(TAG, "Gesture input filter uninstalled.");
+ }
+ mHost = null;
+ mOrientationListener.disable();
+ mContext = null;
+ }
+
+ // should never be called
+ public IBinder asBinder() {
+ throw new UnsupportedOperationException();
+ }
+
+ // called by a Binder thread
+ public void dump(PrintWriter pw, String prefix) {
+
+ }
+
+ private boolean generateSwipe(MotionEvent e1, MotionEvent e2) {
+ switch (mOrientation) {
+ case 90:
+ Slog.d(TAG, "Adjusting motion for 90 degrees");
+ e1.setLocation(e1.getY(), e1.getX());
+ e2.setLocation(e2.getY(), e2.getX());
+ break;
+ case 180:
+ Slog.d(TAG, "Adjusting motion for 180 degrees");
+ e1.setLocation(mGesturePadWidth - e1.getX(),
+ mGesturePadHeight - e1.getY());
+ e2.setLocation(mGesturePadWidth - e2.getX(),
+ mGesturePadHeight - e2.getY());
+ break;
+ case 270:
+ Slog.d(TAG, "Adjusting motion for 270 degrees");
+ e1.setLocation(mGesturePadHeight - e1.getY(),
+ e1.getX());
+ e2.setLocation(mGesturePadHeight - e2.getY(),
+ e2.getX());
+ break;
+ }
+
+ float deltaX = Math.abs(e1.getX() - e2.getX());
+ float deltaY = Math.abs(e1.getY() - e2.getY());
+
+ if (deltaX < mTouchSlop && deltaY < mTouchSlop) {
+ return false;
+ }
+
+ if (deltaX > deltaY) {
+ e2.setLocation(e2.getX(), e1.getY());
+ } else if (deltaY > deltaX) {
+ e2.setLocation(e1.getX(), e2.getY());
+ }
+
+ float scaleX = mScreenWidth / mGesturePadWidth;
+ float scaleY = mScreenHeight / mGesturePadHeight;
+
+ float magnitudeX = deltaX * scaleX;
+ float magnitudeY = deltaY * scaleY;
+
+ float origX = mScreenWidth / 2;
+ float origY = mScreenHeight / 2;
+ float endX = 0.0f;
+ float endY = 0.0f;
+
+ if (e2.getY() > e1.getY()) {
+ if (DEBUG) Slog.d(TAG, "Detected down motion");
+ // Ensure selection does not occur
+ endX = origX + mTouchSlop + 5;
+ endY = origY + magnitudeY;
+ } else if (e2.getY() < e1.getY()) {
+ if (DEBUG) Slog.d(TAG, "Detected up motion");
+ endX = origX + mTouchSlop + 5;
+ endY = origY - magnitudeY;
+ } else if (e2.getX() > e1.getX()) {
+ if (DEBUG) Slog.d(TAG, "Detected left motion");
+ endX = origX + magnitudeX;
+ endY = origY + mTouchSlop + 5;
+ } else if (e2.getX() < e1.getX()) {
+ if (DEBUG) Slog.d(TAG, "Detected right motion");
+ endX = origX - magnitudeX;
+ endY = origY + mTouchSlop + 5;
+ } else {
+ return false;
+ }
+
+ sendSwipe(origX, origY, endX, endY);
+ return true;
+ }
+
+ private void sendSwipe(float x1, float y1, float x2, float y2) {
+ final long duration = 100;
+ long now = SystemClock.uptimeMillis();
+ final long startTime = now;
+ final long endTime = startTime + duration;
+ sendMotionEvent(MotionEvent.ACTION_DOWN, now, x1, y1, 1.0f);
+
+ while (now < endTime) {
+ long elapsedTime = now - startTime;
+ float alpha = (float) elapsedTime / duration;
+ sendMotionEvent(MotionEvent.ACTION_MOVE, now,
+ lerp(x1, x2, alpha), lerp(y1, y2, alpha), 1.0f);
+ now = SystemClock.uptimeMillis();
+ }
+ sendMotionEvent(MotionEvent.ACTION_UP, now, x2, y2, 1.0f);
+ }
+
+ private void sendMotionEvent(int action, long when, float x, float y,
+ float pressure) {
+ final float DEFAULT_SIZE = 1.0f;
+ final int DEFAULT_META_STATE = 0;
+ final float DEFAULT_PRECISION_X = 1.0f;
+ final float DEFAULT_PRECISION_Y = 1.0f;
+ final int DEFAULT_DEVICE_ID = 0;
+ final int DEFAULT_EDGE_FLAGS = 0;
+
+ MotionEvent e = MotionEvent.obtain(when, when, action, x, y, pressure,
+ DEFAULT_SIZE, DEFAULT_META_STATE, DEFAULT_PRECISION_X,
+ DEFAULT_PRECISION_Y, DEFAULT_DEVICE_ID, DEFAULT_EDGE_FLAGS);
+ e.setSource(InputDevice.SOURCE_TOUCHSCREEN);
+ sendInputEvent(e);
+ }
+
+ private void sendInputEvent(InputEvent event) {
+ mInputManager.injectInputEvent(event,
+ InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH);
+ }
+
+ private static final float lerp(float a, float b, float alpha) {
+ return (b - a) * alpha + a;
+ }
+
+ @Override
+ public boolean onDown(MotionEvent e) {
+ return false;
+ }
+
+ @Override
+ public void onShowPress(MotionEvent e) {
+ }
+
+ @Override
+ public boolean onSingleTapUp(MotionEvent e) {
+ return false;
+ }
+
+ @Override
+ public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
+ float distanceY) {
+ return false;
+ }
+
+ @Override
+ public void onLongPress(MotionEvent e) {
+ if (mLongPressPendingIntent != null) {
+ try {
+ mLongPressPendingIntent.send();
+ } catch (CanceledException e1) {
+ e1.printStackTrace();
+ }
+ }
+ }
+
+ @Override
+ public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
+ float velocityY) {
+ return generateSwipe(e1, e2);
+ }
+
+ @Override
+ public boolean onSingleTapConfirmed(MotionEvent e) {
+ return false;
+ }
+
+ @Override
+ public boolean onDoubleTap(MotionEvent e) {
+ if (mDoubleClickPendingIntent != null) {
+ try {
+ mDoubleClickPendingIntent.send();
+ return true;
+ } catch (CanceledException e1) {
+ e1.printStackTrace();
+ }
+ }
+
+ return false;
+ }
+
+ @Override
+ public boolean onDoubleTapEvent(MotionEvent e) {
+ return false;
+ }
+
+ public void setOnLongPressPendingIntent(PendingIntent pendingIntent) {
+ mLongPressPendingIntent = pendingIntent;
+ }
+
+ public void setOnDoubleClickPendingIntent(PendingIntent pendingIntent) {
+ mDoubleClickPendingIntent = pendingIntent;
+ }
+}
diff --git a/services/core/java/com/android/server/gesture/GestureService.java b/services/core/java/com/android/server/gesture/GestureService.java
new file mode 100644
index 0000000..1a01e41
--- /dev/null
+++ b/services/core/java/com/android/server/gesture/GestureService.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2013 The CyanogenMod Project (Jens Doll)
+ *
+ * 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.gesture;
+
+import android.Manifest;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.service.gesture.IGestureService;
+import android.util.Slog;
+
+import com.android.server.input.InputManagerService;
+
+/**
+ * A system service to track gesture sensor gestures. This service is
+ * responsible for creating input events from motion events generated by
+ * gesture sensor input hardware:
+ * <li>Installing an input filter to listen for gesture sensor events</li>
+ * <li>Generating input events to be injected into the input stream</li>
+ */
+public class GestureService extends IGestureService.Stub {
+ public static final String TAG = "GestureService";
+ public static final boolean DEBUG = false;
+
+ private Context mContext;
+ private InputManagerService mInputManager;
+ private GestureInputFilter mInputFilter;
+
+ public GestureService(Context context, InputManagerService inputManager) {
+ mContext = context;
+ mInputManager = inputManager;
+ }
+
+ // called by system server
+ public void systemReady() {
+ if (DEBUG) Slog.d(TAG, "Starting Gesture Sensor service");
+ mInputFilter = new GestureInputFilter(mContext);
+ mInputManager.registerSecondaryInputFilter(mInputFilter);
+ }
+
+ public void setOnLongPressPendingIntent(PendingIntent pendingIntent) {
+ mInputFilter.setOnLongPressPendingIntent(pendingIntent);
+ }
+
+ public void setOnDoubleClickPendingIntent(PendingIntent pendingIntent) {
+ mInputFilter.setOnDoubleClickPendingIntent(pendingIntent);
+ }
+}
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index 0205a20..37326cc 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -97,6 +97,7 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
+import cyanogenmod.providers.CMSettings;
import libcore.io.Streams;
import libcore.util.Objects;
@@ -161,8 +162,9 @@ public class InputManagerService extends IInputManager.Stub
// State for the currently installed input filter.
final Object mInputFilterLock = new Object();
- IInputFilter mInputFilter; // guarded by mInputFilterLock
- InputFilterHost mInputFilterHost; // guarded by mInputFilterLock
+ ChainedInputFilterHost mInputFilterHost; // guarded by mInputFilterLock
+ ArrayList<ChainedInputFilterHost> mInputFilterChain =
+ new ArrayList<ChainedInputFilterHost>(); // guarded by mInputFilterLock
private static native long nativeInit(InputManagerService service,
Context context, MessageQueue messageQueue);
@@ -197,6 +199,8 @@ public class InputManagerService extends IInputManager.Stub
InputChannel fromChannel, InputChannel toChannel);
private static native void nativeSetPointerSpeed(long ptr, int speed);
private static native void nativeSetShowTouches(long ptr, boolean enabled);
+ private static native void nativeSetStylusIconEnabled(long ptr, boolean enabled);
+ private static native void nativeSetVolumeKeysRotation(long ptr, int mode);
private static native void nativeSetInteractive(long ptr, boolean interactive);
private static native void nativeReloadCalibration(long ptr);
private static native void nativeVibrate(long ptr, int deviceId, long[] pattern,
@@ -305,17 +309,22 @@ public class InputManagerService extends IInputManager.Stub
registerPointerSpeedSettingObserver();
registerShowTouchesSettingObserver();
+ registerStylusIconEnabledSettingObserver();
+ registerVolumeKeysRotationSettingObserver();
mContext.registerReceiver(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
updatePointerSpeedFromSettings();
updateShowTouchesFromSettings();
+ updateVolumeKeysRotationFromSettings();
}
}, new IntentFilter(Intent.ACTION_USER_SWITCHED), null, mHandler);
updatePointerSpeedFromSettings();
updateShowTouchesFromSettings();
+ updateStylusIconEnabledFromSettings();
+ updateVolumeKeysRotationFromSettings();
}
// TODO(BT) Pass in paramter for bluetooth system
@@ -512,34 +521,71 @@ public class InputManagerService extends IInputManager.Stub
*/
public void setInputFilter(IInputFilter filter) {
synchronized (mInputFilterLock) {
- final IInputFilter oldFilter = mInputFilter;
- if (oldFilter == filter) {
- return; // nothing to do
- }
-
- if (oldFilter != null) {
- mInputFilter = null;
+ if (mInputFilterHost != null) {
mInputFilterHost.disconnectLocked();
+ mInputFilterChain.remove(mInputFilterHost);
mInputFilterHost = null;
- try {
- oldFilter.uninstall();
- } catch (RemoteException re) {
- /* ignore */
- }
}
if (filter != null) {
- mInputFilter = filter;
- mInputFilterHost = new InputFilterHost();
- try {
- filter.install(mInputFilterHost);
- } catch (RemoteException re) {
- /* ignore */
+ ChainedInputFilterHost head = mInputFilterChain.isEmpty() ? null :
+ mInputFilterChain.get(0);
+ mInputFilterHost = new ChainedInputFilterHost(filter, head);
+ mInputFilterHost.connectLocked();
+ mInputFilterChain.add(0, mInputFilterHost);
+ }
+
+ nativeSetInputFilterEnabled(mPtr, !mInputFilterChain.isEmpty());
+ }
+ }
+
+ /**
+ * Registers a secondary input filter. These filters are always behind the "original"
+ * input filter. This ensures that all input events will be filtered by the
+ * {@code AccessibilityManagerService} first.
+ * <p>
+ * <b>Note:</b> Even though this implementation using AIDL interfaces, it is designed to only
+ * provide direct access. Therefore, any filter registering should reside in the
+ * system server DVM only!
+ *
+ * @param filter The input filter to register.
+ */
+ public void registerSecondaryInputFilter(IInputFilter filter) {
+ synchronized (mInputFilterLock) {
+ ChainedInputFilterHost host = new ChainedInputFilterHost(filter, null);
+ if (!mInputFilterChain.isEmpty()) {
+ mInputFilterChain.get(mInputFilterChain.size() - 1).mNext = host;
+ }
+ host.connectLocked();
+ mInputFilterChain.add(host);
+
+ nativeSetInputFilterEnabled(mPtr, !mInputFilterChain.isEmpty());
+ }
+ }
+
+ public void unregisterSecondaryInputFilter(IInputFilter filter) {
+ synchronized (mInputFilterLock) {
+ int index = findInputFilterIndexLocked(filter);
+ if (index >= 0) {
+ ChainedInputFilterHost host = mInputFilterChain.get(index);
+ host.disconnectLocked();
+ if (index >= 1) {
+ mInputFilterChain.get(index - 1).mNext = host.mNext;
}
+ mInputFilterChain.remove(index);
}
- nativeSetInputFilterEnabled(mPtr, filter != null);
+ nativeSetInputFilterEnabled(mPtr, !mInputFilterChain.isEmpty());
+ }
+ }
+
+ private int findInputFilterIndexLocked(IInputFilter filter) {
+ for (int i = 0; i < mInputFilterChain.size(); i++) {
+ if (mInputFilterChain.get(i).mInputFilter == filter) {
+ return i;
+ }
}
+ return -1;
}
@Override // Binder call
@@ -1357,6 +1403,58 @@ public class InputManagerService extends IInputManager.Stub
return result;
}
+ public void updateStylusIconEnabledFromSettings() {
+ int enabled = getStylusIconEnabled(0);
+ nativeSetStylusIconEnabled(mPtr, enabled != 0);
+ }
+
+ public void registerStylusIconEnabledSettingObserver() {
+ mContext.getContentResolver().registerContentObserver(
+ Settings.System.getUriFor(Settings.System.STYLUS_ICON_ENABLED), false,
+ new ContentObserver(mHandler) {
+ @Override
+ public void onChange(boolean selfChange) {
+ updateStylusIconEnabledFromSettings();
+ }
+ });
+ }
+
+ private int getStylusIconEnabled(int defaultValue) {
+ int result = defaultValue;
+ try {
+ result = Settings.System.getInt(mContext.getContentResolver(),
+ Settings.System.STYLUS_ICON_ENABLED);
+ } catch (SettingNotFoundException snfe) {
+ }
+ return result;
+ }
+
+ public void updateVolumeKeysRotationFromSettings() {
+ int mode = getVolumeKeysRotationSetting(0);
+ nativeSetVolumeKeysRotation(mPtr, mode);
+ }
+
+ public void registerVolumeKeysRotationSettingObserver() {
+ mContext.getContentResolver().registerContentObserver(
+ CMSettings.System.getUriFor(CMSettings.System.SWAP_VOLUME_KEYS_ON_ROTATION), false,
+ new ContentObserver(mHandler) {
+ @Override
+ public void onChange(boolean selfChange) {
+ updateVolumeKeysRotationFromSettings();
+ }
+ });
+ }
+
+ private int getVolumeKeysRotationSetting(int defaultValue) {
+ int result = defaultValue;
+ try {
+ result = CMSettings.System.getIntForUser(mContext.getContentResolver(),
+ CMSettings.System.SWAP_VOLUME_KEYS_ON_ROTATION, UserHandle.USER_CURRENT);
+ } catch (CMSettings.CMSettingNotFoundException snfe) {
+ }
+ return result;
+ }
+
// Binder call
@Override
public void vibrate(int deviceId, long[] pattern, int repeat, IBinder token) {
@@ -1521,15 +1619,22 @@ public class InputManagerService extends IInputManager.Stub
// Native callback.
final boolean filterInputEvent(InputEvent event, int policyFlags) {
+ ChainedInputFilterHost head = null;
synchronized (mInputFilterLock) {
- if (mInputFilter != null) {
- try {
- mInputFilter.filterInputEvent(event, policyFlags);
- } catch (RemoteException e) {
- /* ignore */
- }
- return false;
+ if (!mInputFilterChain.isEmpty()) {
+ head = mInputFilterChain.get(0);
+ }
+ }
+ // call filter input event outside of the lock.
+ // this is safe, because we know that mInputFilter never changes.
+ // we may loose a event, but this does not differ from the original implementation.
+ if (head != null) {
+ try {
+ head.mInputFilter.filterInputEvent(event, policyFlags);
+ } catch (RemoteException e) {
+ /* ignore */
}
+ return false;
}
event.recycle();
return true;
@@ -1786,6 +1891,66 @@ public class InputManagerService extends IInputManager.Stub
}
}
+ /**
+ * Hosting interface for input filters to call back into the input manager.
+ */
+ private final class ChainedInputFilterHost extends IInputFilterHost.Stub {
+ private final IInputFilter mInputFilter;
+ private ChainedInputFilterHost mNext;
+ private boolean mDisconnected;
+
+ private ChainedInputFilterHost(IInputFilter filter, ChainedInputFilterHost next) {
+ mInputFilter = filter;
+ mNext = next;
+ mDisconnected = false;
+ }
+
+ public void connectLocked() {
+ try {
+ mInputFilter.install(this);
+ } catch (RemoteException re) {
+ /* ignore */
+ }
+ }
+
+ public void disconnectLocked() {
+ try {
+ mInputFilter.uninstall();
+ } catch (RemoteException re) {
+ /* ignore */
+ }
+ // DO NOT set mInputFilter to null here! mInputFilter is used outside of the lock!
+ mDisconnected = true;
+ }
+
+ @Override
+ public void sendInputEvent(InputEvent event, int policyFlags) {
+ if (event == null) {
+ throw new IllegalArgumentException("event must not be null");
+ }
+
+ synchronized (mInputFilterLock) {
+ if (!mDisconnected) {
+ if (mNext == null) {
+ nativeInjectInputEvent(mPtr, event, Display.DEFAULT_DISPLAY, 0, 0,
+ InputManager.INJECT_INPUT_EVENT_MODE_ASYNC, 0,
+ policyFlags | WindowManagerPolicy.FLAG_FILTERED);
+ } else {
+ try {
+ // We need to pass a copy into filterInputEvent as it assumes
+ // the callee takes responsibility and recycles it - in case
+ // multiple filters are chained, calling into the second filter
+ // will cause event to be recycled twice
+ mNext.mInputFilter.filterInputEvent(event.copy(), policyFlags);
+ } catch (RemoteException e) {
+ /* ignore */
+ }
+ }
+ }
+ }
+ }
+ }
+
private static final class KeyboardLayoutDescriptor {
public String packageName;
public String receiverName;
diff --git a/services/core/java/com/android/server/lights/Light.java b/services/core/java/com/android/server/lights/Light.java
index b496b4c..3eb570c 100644
--- a/services/core/java/com/android/server/lights/Light.java
+++ b/services/core/java/com/android/server/lights/Light.java
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2013 The Android Open Source Project
+ * Copyright (C) 2015 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.
@@ -35,6 +36,7 @@ public abstract class Light {
public abstract void setBrightness(int brightness, int brightnessMode);
public abstract void setColor(int color);
public abstract void setFlashing(int color, int mode, int onMS, int offMS);
+ public abstract void setModes(int brightnessLevel, boolean multipleLeds);
public abstract void pulse();
public abstract void pulse(int color, int onMS);
public abstract void turnOff();
diff --git a/services/core/java/com/android/server/lights/LightsManager.java b/services/core/java/com/android/server/lights/LightsManager.java
index 2f20509..e1e5aa3 100644
--- a/services/core/java/com/android/server/lights/LightsManager.java
+++ b/services/core/java/com/android/server/lights/LightsManager.java
@@ -25,7 +25,9 @@ public abstract class LightsManager {
public static final int LIGHT_ID_ATTENTION = 5;
public static final int LIGHT_ID_BLUETOOTH = 6;
public static final int LIGHT_ID_WIFI = 7;
- public static final int LIGHT_ID_COUNT = 8;
+ public static final int LIGHT_ID_CAPS = 8;
+ public static final int LIGHT_ID_FUNC = 9;
+ public static final int LIGHT_ID_COUNT = 10;
public abstract Light getLight(int id);
}
diff --git a/services/core/java/com/android/server/lights/LightsService.java b/services/core/java/com/android/server/lights/LightsService.java
index ed884ef..16dde26 100644
--- a/services/core/java/com/android/server/lights/LightsService.java
+++ b/services/core/java/com/android/server/lights/LightsService.java
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2008 The Android Open Source Project
+ * Copyright (C) 2015 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.
@@ -34,6 +35,9 @@ public class LightsService extends SystemService {
private LightImpl(int id) {
mId = id;
+ mBrightnessLevel = 0xFF;
+ mModesUpdate = false;
+ mMultipleLeds = false;
}
@Override
@@ -65,6 +69,20 @@ public class LightsService extends SystemService {
}
@Override
+ public void setModes(int brightnessLevel, boolean multipleLeds) {
+ synchronized (this) {
+ if (mBrightnessLevel != brightnessLevel) {
+ mBrightnessLevel = brightnessLevel;
+ mModesUpdate = true;
+ }
+ if (mMultipleLeds != multipleLeds) {
+ mMultipleLeds = multipleLeds;
+ mModesUpdate = true;
+ }
+ }
+ }
+
+ @Override
public void pulse() {
pulse(0x00ffffff, 7);
}
@@ -94,17 +112,20 @@ public class LightsService extends SystemService {
}
private void setLightLocked(int color, int mode, int onMS, int offMS, int brightnessMode) {
- if (color != mColor || mode != mMode || onMS != mOnMS || offMS != mOffMS) {
+ if (mModesUpdate || color != mColor || mode != mMode || onMS != mOnMS ||
+ offMS != mOffMS) {
if (DEBUG) Slog.v(TAG, "setLight #" + mId + ": color=#"
+ Integer.toHexString(color));
mColor = color;
mMode = mode;
mOnMS = onMS;
mOffMS = offMS;
+ mModesUpdate = false;
Trace.traceBegin(Trace.TRACE_TAG_POWER, "setLight(" + mId + ", 0x"
+ Integer.toHexString(color) + ")");
try {
- setLight_native(mNativePointer, mId, color, mode, onMS, offMS, brightnessMode);
+ setLight_native(mNativePointer, mId, color, mode, onMS, offMS, brightnessMode,
+ mBrightnessLevel, mMultipleLeds ? 1 : 0);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_POWER);
}
@@ -116,7 +137,10 @@ public class LightsService extends SystemService {
private int mMode;
private int mOnMS;
private int mOffMS;
+ private int mBrightnessLevel;
private boolean mFlashing;
+ private boolean mModesUpdate;
+ private boolean mMultipleLeds;
}
public LightsService(Context context) {
@@ -163,7 +187,8 @@ public class LightsService extends SystemService {
private static native void finalize_native(long ptr);
static native void setLight_native(long ptr, int light, int color, int mode,
- int onMS, int offMS, int brightnessMode);
+ int onMS, int offMS, int brightnessMode, int brightnessLevel,
+ int mMultipleLeds);
private long mNativePointer;
}
diff --git a/services/core/java/com/android/server/location/GeoFencerBase.java b/services/core/java/com/android/server/location/GeoFencerBase.java
new file mode 100644
index 0000000..eec07ab
--- /dev/null
+++ b/services/core/java/com/android/server/location/GeoFencerBase.java
@@ -0,0 +1,147 @@
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+ *
+ * Not a Contribution, Apache license notifications and license are retained
+ * for attribution purposes only.
+ *
+ * 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 com.android.server.location;
+
+import android.os.Binder;
+import android.os.Parcelable;
+import android.util.Log;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.location.GeoFenceParams;
+import android.location.ILocationListener;
+import java.io.PrintWriter;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Collection;
+import java.util.ArrayList;
+
+/**
+ * This class defines a base class for GeoFencers
+ *
+ * @hide
+ */
+public abstract class GeoFencerBase {
+ private static final String TAG = "GeoFencerBase";
+ private HashMap<PendingIntent,GeoFenceParams> mGeoFences;
+
+ public GeoFencerBase() {
+ mGeoFences = new HashMap<PendingIntent,GeoFenceParams>();
+ }
+
+ public void add(double latitude, double longitude,
+ float radius, long expiration, PendingIntent intent,
+ String packageName) {
+ add(new GeoFenceParams(latitude, longitude, radius,
+ expiration, intent, packageName));
+ }
+
+ public void add(GeoFenceParams geoFence) {
+ synchronized(mGeoFences) {
+ mGeoFences.put(geoFence.mIntent, geoFence);
+ }
+ if (!start(geoFence)) {
+ synchronized(mGeoFences) {
+ mGeoFences.remove(geoFence.mIntent);
+ }
+ }
+ }
+
+ public void remove(PendingIntent intent) {
+ remove(intent, false);
+ }
+
+ public void remove(PendingIntent intent, boolean localOnly) {
+ GeoFenceParams geoFence = null;
+
+ synchronized(mGeoFences) {
+ geoFence = mGeoFences.remove(intent);
+ }
+
+ if (geoFence != null) {
+ if (!localOnly && !stop(intent)) {
+ synchronized(mGeoFences) {
+ mGeoFences.put(geoFence.mIntent, geoFence);
+ }
+ }
+ }
+ }
+
+ public int getNumbOfGeoFences() {
+ return mGeoFences.size();
+ }
+
+ public Collection<GeoFenceParams> getAllGeoFences() {
+ return mGeoFences.values();
+ }
+
+ public GeoFenceParams getGeoFence(PendingIntent intent) {
+ return mGeoFences.get(intent);
+ }
+
+ public boolean hasCaller(int uid) {
+ for (GeoFenceParams alert : mGeoFences.values()) {
+ if (alert.mUid == uid) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public void removeCaller(int uid) {
+ ArrayList<PendingIntent> removedFences = null;
+ for (GeoFenceParams alert : mGeoFences.values()) {
+ if (alert.mUid == uid) {
+ if (removedFences == null) {
+ removedFences = new ArrayList<PendingIntent>();
+ }
+ removedFences.add(alert.mIntent);
+ }
+ }
+ if (removedFences != null) {
+ for (int i = removedFences.size()-1; i>=0; i--) {
+ mGeoFences.remove(removedFences.get(i));
+ }
+ }
+ }
+
+ public void transferService(GeoFencerBase geofencer) {
+ for (GeoFenceParams alert : geofencer.mGeoFences.values()) {
+ geofencer.stop(alert.mIntent);
+ add(alert);
+ }
+ }
+
+ public void dump(PrintWriter pw, String prefix) {
+ if (mGeoFences.size() > 0) {
+ pw.println(prefix + " GeoFences:");
+ prefix += " ";
+ for (Map.Entry<PendingIntent, GeoFenceParams> i
+ : mGeoFences.entrySet()) {
+ pw.println(prefix + i.getKey() + ":");
+ i.getValue().dump(pw, prefix);
+ }
+ }
+ }
+
+ abstract protected boolean start(GeoFenceParams geoFence);
+ abstract protected boolean stop(PendingIntent intent);
+}
diff --git a/services/core/java/com/android/server/location/GeoFencerProxy.java b/services/core/java/com/android/server/location/GeoFencerProxy.java
new file mode 100644
index 0000000..8ffbe8c
--- /dev/null
+++ b/services/core/java/com/android/server/location/GeoFencerProxy.java
@@ -0,0 +1,149 @@
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+ *
+ * Not a Contribution, Apache license notifications and license are retained
+ * for attribution purposes only.
+ *
+ * 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 com.android.server.location;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.util.Log;
+import android.app.PendingIntent;
+import android.location.IGeoFencer;
+import android.location.IGeoFenceListener;
+import android.location.GeoFenceParams;
+
+/**
+ * A class for proxying IGeoFenceProvider implementations.
+ *
+ * {@hide}
+ */
+public class GeoFencerProxy extends GeoFencerBase {
+
+ private static final String TAG = "GeoFencerProxy";
+ private static final boolean LOGV_ENABLED = true;
+
+ private final Context mContext;
+ private final Intent mIntent;
+ private IGeoFencer mGeoFencer;
+
+ private final ServiceConnection mServiceConnection = new ServiceConnection() {
+ public void onServiceConnected(ComponentName className, IBinder service) {
+ synchronized (this) {
+ mGeoFencer = IGeoFencer.Stub.asInterface(service);
+ notifyAll();
+ }
+ Log.v(TAG, "onServiceConnected: mGeoFencer - "+mGeoFencer);
+ }
+ public void onServiceDisconnected(ComponentName className) {
+ synchronized (this) {
+ mGeoFencer = null;
+ }
+ Log.v(TAG, "onServiceDisconnected");
+ }
+ };
+
+ private final IGeoFenceListener.Stub mListener = new IGeoFenceListener.Stub() {
+ @Override
+ public void geoFenceExpired(PendingIntent intent) throws RemoteException {
+ logv("geoFenceExpired - "+intent);
+ remove(intent, true);
+ }
+ };
+
+ private static GeoFencerProxy mGeoFencerProxy;
+ public static GeoFencerProxy getGeoFencerProxy(Context context, String serviceName) {
+ if (mGeoFencerProxy == null) {
+ mGeoFencerProxy = new GeoFencerProxy(context, serviceName);
+ }
+ return mGeoFencerProxy;
+ }
+
+ private GeoFencerProxy(Context context, String serviceName) {
+ mContext = context;
+ mIntent = new Intent(IGeoFencer.class.getName());
+ mIntent.setPackage(serviceName);
+ mContext.bindService(mIntent, mServiceConnection,
+ Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND
+ | Context.BIND_ALLOW_OOM_MANAGEMENT);
+ }
+
+ public void removeCaller(int uid) {
+ super.removeCaller(uid);
+ if(mGeoFencer != null) {
+ try {
+ mGeoFencer.clearGeoFenceUser(uid);
+ } catch (RemoteException re) {
+ }
+ }
+ else
+ Log.e(TAG, "removeCaller - mGeoFencer is null");
+ }
+
+ private boolean ensureGeoFencer() {
+ if (mGeoFencer == null) {
+ try {
+ synchronized(mServiceConnection) {
+ logv("waiting...");
+ mServiceConnection.wait(60000);
+ logv("woke up!!!");
+ }
+ } catch (InterruptedException ie) {
+ Log.w(TAG, "Interrupted while waiting for GeoFencer");
+ return false;
+ }
+
+ if (mGeoFencer == null) {
+ Log.w(TAG, "Timed out. No GeoFencer connection");
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ protected boolean start(GeoFenceParams geofence) {
+ if (ensureGeoFencer()) {
+ try {
+ return mGeoFencer.setGeoFence(mListener, geofence);
+ } catch (RemoteException re) {
+ }
+ }
+ return false;
+ }
+
+ protected boolean stop(PendingIntent intent) {
+ if (ensureGeoFencer()) {
+ try {
+ mGeoFencer.clearGeoFence(mListener, intent);
+ return true;
+ } catch (RemoteException re) {
+ }
+ }
+ return false;
+ }
+
+ private void logv(String s) {
+ if (LOGV_ENABLED) Log.v(TAG, s);
+ }
+}
diff --git a/services/core/java/com/android/server/location/GpsLocationProvider.java b/services/core/java/com/android/server/location/GpsLocationProvider.java
index f671e64..42b8783 100644
--- a/services/core/java/com/android/server/location/GpsLocationProvider.java
+++ b/services/core/java/com/android/server/location/GpsLocationProvider.java
@@ -1930,7 +1930,7 @@ public class GpsLocationProvider implements LocationProviderInterface {
type = AGPS_REF_LOCATION_TYPE_GSM_CELLID;
}
native_agps_set_ref_location_cellid(type, mcc, mnc,
- gsm_cell.getLac(), gsm_cell.getCid());
+ gsm_cell.getLac(), gsm_cell.getCid(), gsm_cell.getPsc());
} else {
Log.e(TAG,"Error getting cell location info.");
}
@@ -2289,7 +2289,7 @@ public class GpsLocationProvider implements LocationProviderInterface {
// AGPS ril suport
private native void native_agps_set_ref_location_cellid(int type, int mcc, int mnc,
- int lac, int cid);
+ int lac, int cid, int psc);
private native void native_agps_set_id(int type, String setid);
private native void native_update_network_state(boolean connected, int type,
diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java
index f92f631..bc830f0 100644
--- a/services/core/java/com/android/server/media/MediaSessionRecord.java
+++ b/services/core/java/com/android/server/media/MediaSessionRecord.java
@@ -106,6 +106,9 @@ public class MediaSessionRecord implements IBinder.DeathRecipient {
private CharSequence mQueueTitle;
private int mRatingType;
private long mLastActiveTime;
+ private String mBrowsedPlayerURI;
+ private boolean mPlayItemStatus;
+ private long[] mNowPlayingList;
// End TransportPerformer fields
// Volume handling fields
@@ -518,6 +521,86 @@ public class MediaSessionRecord implements IBinder.DeathRecipient {
}
}
+ private void pushBrowsePlayerInfo() {
+ synchronized (mLock) {
+ if (mDestroyed) {
+ return;
+ }
+ for (int i = mControllerCallbacks.size() - 1; i >= 0; i--) {
+ ISessionControllerCallback cb = mControllerCallbacks.get(i);
+ try {
+ Log.d(TAG, "pushBrowsePlayerInfo");
+ cb.onUpdateFolderInfoBrowsedPlayer(mBrowsedPlayerURI);
+ } catch (DeadObjectException e) {
+ Log.w(TAG, "Removing dead callback in pushBrowsePlayerInfo. ", e);
+ mControllerCallbacks.remove(i);
+ } catch (RemoteException e) {
+ Log.w(TAG, "unexpected exception in pushBrowsePlayerInfo. ", e);
+ }
+ }
+ }
+ }
+
+ private void pushNowPlayingEntries() {
+ synchronized (mLock) {
+ if (mDestroyed) {
+ return;
+ }
+ for (int i = mControllerCallbacks.size() - 1; i >= 0; i--) {
+ ISessionControllerCallback cb = mControllerCallbacks.get(i);
+ try {
+ Log.d(TAG, "pushNowPlayingEntries");
+ cb.onUpdateNowPlayingEntries(mNowPlayingList);
+ } catch (DeadObjectException e) {
+ Log.w(TAG, "Removing dead callback in pushNowPlayingEntries. ", e);
+ mControllerCallbacks.remove(i);
+ } catch (RemoteException e) {
+ Log.w(TAG, "unexpected exception in pushNowPlayingEntries. ", e);
+ }
+ }
+ }
+ }
+
+ private void pushNowPlayingContentChange() {
+ synchronized (mLock) {
+ if (mDestroyed) {
+ return;
+ }
+ for (int i = mControllerCallbacks.size() - 1; i >= 0; i--) {
+ ISessionControllerCallback cb = mControllerCallbacks.get(i);
+ try {
+ Log.d(TAG, "pushNowPlayingContentChange");
+ cb.onUpdateNowPlayingContentChange();
+ } catch (DeadObjectException e) {
+ Log.w(TAG, "Removing dead callback in pushNowPlayingContentChange. ", e);
+ mControllerCallbacks.remove(i);
+ } catch (RemoteException e) {
+ Log.w(TAG, "unexpected exception in pushNowPlayingContentChange. ", e);
+ }
+ }
+ }
+ }
+
+ private void pushPlayItemResponse() {
+ synchronized (mLock) {
+ if (mDestroyed) {
+ return;
+ }
+ for (int i = mControllerCallbacks.size() - 1; i >= 0; i--) {
+ ISessionControllerCallback cb = mControllerCallbacks.get(i);
+ try {
+ Log.d(TAG, "pushPlayItemResponse");
+ cb.onPlayItemResponse(mPlayItemStatus);
+ } catch (DeadObjectException e) {
+ Log.w(TAG, "Removing dead callback in pushPlayItemResponse. ", e);
+ mControllerCallbacks.remove(i);
+ } catch (RemoteException e) {
+ Log.w(TAG, "unexpected exception in pushPlayItemResponse. ", e);
+ }
+ }
+ }
+ }
+
private void pushQueueUpdate() {
synchronized (mLock) {
if (mDestroyed) {
@@ -775,6 +858,33 @@ public class MediaSessionRecord implements IBinder.DeathRecipient {
}
@Override
+ public void updateFolderInfoBrowsedPlayer(String stringUri) {
+ Log.d(TAG, "SessionStub: updateFolderInfoBrowsedPlayer");
+ mBrowsedPlayerURI = stringUri;
+ mHandler.post(MessageHandler.MSG_FOLDER_INFO_BROWSED_PLAYER);
+ }
+
+ @Override
+ public void updateNowPlayingEntries(long[] playList) {
+ Log.d(TAG, "SessionStub: updateNowPlayingEntries");
+ mNowPlayingList = playList;
+ mHandler.post(MessageHandler.MSG_UPDATE_NOWPLAYING_ENTRIES);
+ }
+
+ @Override
+ public void updateNowPlayingContentChange() {
+ Log.d(TAG, "SessionStub: updateNowPlayingContentChange");
+ mHandler.post(MessageHandler.MSG_UPDATE_NOWPLAYING_CONTENT_CHANGE);
+ }
+
+ @Override
+ public void playItemResponse(boolean success) {
+ Log.d(TAG, "SessionStub: playItemResponse");
+ mPlayItemStatus = success;
+ mHandler.post(MessageHandler.MSG_PLAY_ITEM_RESPONSE);
+ }
+
+ @Override
public void setQueueTitle(CharSequence title) {
mQueueTitle = title;
mHandler.post(MessageHandler.MSG_UPDATE_QUEUE_TITLE);
@@ -957,6 +1067,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient {
}
public void seekTo(long pos) {
+ Slog.d(TAG, "seekTo in SessionCb");
try {
mCb.onSeekTo(pos);
} catch (RemoteException e) {
@@ -964,6 +1075,42 @@ public class MediaSessionRecord implements IBinder.DeathRecipient {
}
}
+ /**
+ * @hide
+ */
+ public void setRemoteControlClientBrowsedPlayer() {
+ Slog.d(TAG, "setRemoteControlClientBrowsedPlayer in SessionCb");
+ try {
+ mCb.setRemoteControlClientBrowsedPlayer();
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote failure in setRemoteControlClientBrowsedPlayer.", e);
+ }
+ }
+
+ /**
+ * @hide
+ */
+ public void setRemoteControlClientPlayItem(long uid, int scope) throws RemoteException {
+ Slog.d(TAG, "setRemoteControlClientPlayItem in SessionCb");
+ try {
+ mCb.setRemoteControlClientPlayItem(uid, scope);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote failure in setRemoteControlClientPlayItem.", e);
+ }
+ }
+
+ /**
+ * @hide
+ */
+ public void getRemoteControlClientNowPlayingEntries() throws RemoteException {
+ Slog.d(TAG, "getRemoteControlClientNowPlayingEntries in SessionCb");
+ try {
+ mCb.getRemoteControlClientNowPlayingEntries();
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote failure in getRemoteControlClientNowPlayingEntries.", e);
+ }
+ }
+
public void rate(Rating rating) {
try {
mCb.onRate(rating);
@@ -1157,10 +1304,29 @@ public class MediaSessionRecord implements IBinder.DeathRecipient {
@Override
public void seekTo(long pos) throws RemoteException {
+ Log.d(TAG, "seekTo in ControllerStub");
mSessionCb.seekTo(pos);
}
@Override
+ public void setRemoteControlClientBrowsedPlayer() throws RemoteException {
+ Log.d(TAG, "setRemoteControlClientBrowsedPlayer in ControllerStub");
+ mSessionCb.setRemoteControlClientBrowsedPlayer();
+ }
+
+ @Override
+ public void setRemoteControlClientPlayItem(long uid, int scope) throws RemoteException {
+ Log.d(TAG, "setRemoteControlClientPlayItem in ControllerStub");
+ mSessionCb.setRemoteControlClientPlayItem(uid, scope);
+ }
+
+ @Override
+ public void getRemoteControlClientNowPlayingEntries() throws RemoteException {
+ Log.d(TAG, "getRemoteControlClientNowPlayingEntries in ControllerStub");
+ mSessionCb.getRemoteControlClientNowPlayingEntries();
+ }
+
+ @Override
public void rate(Rating rating) throws RemoteException {
mSessionCb.rate(rating);
}
@@ -1224,6 +1390,10 @@ public class MediaSessionRecord implements IBinder.DeathRecipient {
private static final int MSG_UPDATE_SESSION_STATE = 7;
private static final int MSG_UPDATE_VOLUME = 8;
private static final int MSG_DESTROYED = 9;
+ private static final int MSG_FOLDER_INFO_BROWSED_PLAYER = 10;
+ private static final int MSG_UPDATE_NOWPLAYING_ENTRIES = 11;
+ private static final int MSG_UPDATE_NOWPLAYING_CONTENT_CHANGE = 12;
+ private static final int MSG_PLAY_ITEM_RESPONSE = 13;
public MessageHandler(Looper looper) {
super(looper);
@@ -1257,6 +1427,18 @@ public class MediaSessionRecord implements IBinder.DeathRecipient {
break;
case MSG_DESTROYED:
pushSessionDestroyed();
+ case MSG_FOLDER_INFO_BROWSED_PLAYER:
+ pushBrowsePlayerInfo();
+ break;
+ case MSG_UPDATE_NOWPLAYING_ENTRIES:
+ pushNowPlayingEntries();
+ break;
+ case MSG_UPDATE_NOWPLAYING_CONTENT_CHANGE:
+ pushNowPlayingContentChange();
+ break;
+ case MSG_PLAY_ITEM_RESPONSE:
+ pushPlayItemResponse();
+ break;
}
}
diff --git a/services/core/java/com/android/server/net/NetPluginDelegate.java b/services/core/java/com/android/server/net/NetPluginDelegate.java
new file mode 100644
index 0000000..6716a6b
--- /dev/null
+++ b/services/core/java/com/android/server/net/NetPluginDelegate.java
@@ -0,0 +1,101 @@
+/*
+ *Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ *
+ *Redistribution and use in source and binary forms, with or without
+ *modification, are permitted provided that the following conditions are
+ *met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ *THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ *WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ *ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ *BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ *CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ *SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ *BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ *WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ *OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ *IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.android.server.net;
+
+import dalvik.system.PathClassLoader;
+
+import java.lang.reflect.Constructor;
+
+import android.util.Slog;
+import android.net.NetworkStats;
+import android.util.Log;
+
+class NetPluginDelegate {
+
+ private static final String TAG = "ConnectivityExtension";
+ private static final boolean LOGV = false;
+
+ private static Class tetherExtensionClass = null;
+ private static Object tetherExtensionObj = null;
+
+ private static boolean extensionFailed;
+
+ static void getTetherStats(NetworkStats uidStats, NetworkStats devStats,
+ NetworkStats xtStats) {
+ if (!loadTetherExtJar()) {
+ return;
+ }
+ try {
+ tetherExtensionClass.getMethod("getTetherStats", NetworkStats.class,
+ NetworkStats.class, NetworkStats.class).invoke(tetherExtensionObj, uidStats,
+ devStats, xtStats);
+ } catch (Exception e) {
+ e.printStackTrace();
+ Log.w(TAG, "error in invoke method");
+ }
+ }
+
+ static void setQuota(String iface, long quota) {
+ if (!loadTetherExtJar()) {
+ return;
+ }
+ try {
+ tetherExtensionClass.getMethod("setQuota", String.class, long.class).invoke(
+ tetherExtensionObj, iface, quota);
+ } catch (Exception ex) {
+ Log.w(TAG, "Error calling setQuota Method on extension jar");
+ }
+ }
+
+
+
+ private static boolean loadTetherExtJar() {
+ final String realProvider = "com.qualcomm.qti.tetherstatsextension.TetherStatsReporting";
+ final String realProviderPath = "/system/framework/ConnectivityExt.jar";
+ if (!extensionFailed && tetherExtensionClass == null && tetherExtensionObj == null) {
+ if (LOGV) Slog.v(TAG, "loading ConnectivityExt jar");
+ try {
+
+ PathClassLoader classLoader = new PathClassLoader(realProviderPath,
+ ClassLoader.getSystemClassLoader());
+
+ tetherExtensionClass = classLoader.loadClass(realProvider);
+ tetherExtensionObj = tetherExtensionClass.newInstance();
+ if (LOGV)
+ Slog.v(TAG, "ConnectivityExt jar loaded");
+ extensionFailed = false;
+ } catch (Exception e) {
+ Log.w(TAG, "Connectivity extension is not available");
+ extensionFailed = true;
+ }
+ }
+ return !extensionFailed;
+ }
+}
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index b428322..bf7560e 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -804,7 +804,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
} else {
notifyUnderLimitLocked(policy.template);
- if (policy.isOverWarning(totalBytes) && policy.lastWarningSnooze < start) {
+ if (policy.isOverWarning(totalBytes) && policy.lastWarningSnooze < start
+ && policy.limitBytes != LIMIT_DISABLED) {
enqueueNotification(policy, TYPE_WARNING, totalBytes);
}
}
@@ -2439,6 +2440,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
private void setInterfaceQuota(String iface, long quotaBytes) {
try {
mNetworkManager.setInterfaceQuota(iface, quotaBytes);
+ NetPluginDelegate.setQuota(iface, quotaBytes);
} catch (IllegalStateException e) {
Log.wtf(TAG, "problem setting interface quota", e);
} catch (RemoteException e) {
diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java
index 8449348..acd05f7 100644
--- a/services/core/java/com/android/server/net/NetworkStatsService.java
+++ b/services/core/java/com/android/server/net/NetworkStatsService.java
@@ -971,7 +971,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
final NetworkStats uidSnapshot = getNetworkStatsUidDetail();
final NetworkStats xtSnapshot = mNetworkManager.getNetworkStatsSummaryXt();
final NetworkStats devSnapshot = mNetworkManager.getNetworkStatsSummaryDev();
-
+ NetPluginDelegate.getTetherStats(uidSnapshot, xtSnapshot, devSnapshot);
VpnInfo[] vpnArray = mConnManager.getAllVpnInfo();
mDevRecorder.recordSnapshotLocked(devSnapshot, mActiveIfaces, null, currentTime);
mXtRecorder.recordSnapshotLocked(xtSnapshot, mActiveIfaces, null, currentTime);
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 4351798..cb1cf47 100644..100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2007 The Android Open Source Project
+ * Copyright (C) 2015 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.
@@ -23,6 +24,7 @@ import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
import static org.xmlpull.v1.XmlPullParser.END_TAG;
import static org.xmlpull.v1.XmlPullParser.START_TAG;
+import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.ActivityManagerNative;
import android.app.AppGlobals;
@@ -30,6 +32,7 @@ import android.app.AppOpsManager;
import android.app.IActivityManager;
import android.app.INotificationManager;
import android.app.ITransientNotification;
+import android.app.KeyguardManager;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.NotificationManager.Policy;
@@ -41,7 +44,9 @@ import android.app.usage.UsageStatsManagerInternal;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentResolver;
+import android.content.ContentValues;
import android.content.Context;
+import android.database.Cursor;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
@@ -58,6 +63,9 @@ import android.media.AudioManager;
import android.media.AudioManagerInternal;
import android.media.AudioSystem;
import android.media.IRingtonePlayer;
+import android.media.session.MediaController;
+import android.media.session.MediaSessionManager;
+import android.media.session.PlaybackState;
import android.net.Uri;
import android.os.Binder;
import android.os.Build;
@@ -92,7 +100,9 @@ import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.AtomicFile;
import android.util.Log;
+import android.util.LruCache;
import android.util.Slog;
+import android.util.SparseIntArray;
import android.util.Xml;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
@@ -101,6 +111,9 @@ import android.widget.Toast;
import com.android.internal.R;
import com.android.internal.statusbar.NotificationVisibility;
import com.android.internal.util.FastXmlSerializer;
+import com.android.internal.util.cm.SpamFilter;
+import com.android.internal.util.cm.SpamFilter.SpamContract.NotificationTable;
+import com.android.internal.util.cm.SpamFilter.SpamContract.PackageTable;
import com.android.server.EventLogTags;
import com.android.server.LocalServices;
import com.android.server.SystemService;
@@ -110,6 +123,8 @@ import com.android.server.notification.ManagedServices.ManagedServiceInfo;
import com.android.server.notification.ManagedServices.UserProfiles;
import com.android.server.statusbar.StatusBarManagerInternal;
+import cyanogenmod.providers.CMSettings;
+
import libcore.io.IoUtils;
import org.json.JSONArray;
@@ -134,10 +149,15 @@ import java.nio.charset.StandardCharsets;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.HashSet;
+import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
+import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Future;
/** {@hide} */
public class NotificationManagerService extends SystemService {
@@ -170,6 +190,8 @@ public class NotificationManagerService extends SystemService {
static final int JUNK_SCORE = -1000;
static final int NOTIFICATION_PRIORITY_MULTIPLIER = 10;
static final int SCORE_DISPLAY_THRESHOLD = Notification.PRIORITY_MIN * NOTIFICATION_PRIORITY_MULTIPLIER;
+ private static final String IS_FILTERED_QUERY = NotificationTable.NORMALIZED_TEXT + "=? AND " +
+ PackageTable.PACKAGE_NAME + "=?";
// Notifications with scores below this will not interrupt the user, either via LED or
// sound or vibration
@@ -198,6 +220,9 @@ public class NotificationManagerService extends SystemService {
/** notification_enqueue status value for an ignored notification. */
private static final int EVENTLOG_ENQUEUE_STATUS_IGNORED = 2;
+ /** notification light maximum brightness value to use. */
+ private static final int LIGHT_BRIGHTNESS_MAXIMUM = 255;
+
private IActivityManager mAm;
AudioManager mAudioManager;
AudioManagerInternal mAudioManagerInternal;
@@ -217,10 +242,35 @@ public class NotificationManagerService extends SystemService {
private int mDefaultNotificationLedOff;
private long[] mDefaultVibrationPattern;
+ private boolean mAdjustableNotificationLedBrightness;
+ private int mNotificationLedBrightnessLevel = LIGHT_BRIGHTNESS_MAXIMUM;
+
+ private boolean mMultipleNotificationLeds;
+ private boolean mMultipleLedsEnabledSetting = false;
+
+ private boolean mScreenOnEnabled = false;
+ private boolean mScreenOnDefault = false;
+
private long[] mFallbackVibrationPattern;
private boolean mUseAttentionLight;
boolean mSystemReady;
+ private final SparseIntArray mSpamCache;
+ private ExecutorService mSpamExecutor = Executors.newSingleThreadExecutor();
+
+ private static final Uri FILTER_MSG_URI = new Uri.Builder()
+ .scheme(ContentResolver.SCHEME_CONTENT)
+ .authority(SpamFilter.AUTHORITY)
+ .appendPath("messages")
+ .build();
+
+ private static final Uri UPDATE_MSG_URI = new Uri.Builder()
+ .scheme(ContentResolver.SCHEME_CONTENT)
+ .authority(SpamFilter.AUTHORITY)
+ .appendPath(SpamFilter.MESSAGE_PATH)
+ .appendEncodedPath("inc_count")
+ .build();
+
private boolean mDisableNotificationEffects;
private int mCallState;
private String mSoundNotificationKey;
@@ -235,6 +285,11 @@ public class NotificationManagerService extends SystemService {
private boolean mScreenOn = true;
private boolean mInCall = false;
private boolean mNotificationPulseEnabled;
+ private HashMap<String, NotificationLedValues> mNotificationPulseCustomLedValues;
+ private Map<String, String> mPackageNameMappings;
+
+ // for checking lockscreen status
+ private KeyguardManager mKeyguardManager;
// used as a mutex for access to all active notifications & listeners
final ArrayList<NotificationRecord> mNotificationList =
@@ -275,6 +330,8 @@ public class NotificationManagerService extends SystemService {
private NotificationListeners mListeners;
private ConditionProviders mConditionProviders;
private NotificationUsageStats mUsageStats;
+ private boolean mDisableDuckingWhileMedia;
+ private boolean mActiveMedia;
private static final int MY_UID = Process.myUid();
private static final int MY_PID = Process.myPid();
@@ -487,6 +544,12 @@ public class NotificationManagerService extends SystemService {
}
}
+ class NotificationLedValues {
+ public int color;
+ public int onMS;
+ public int offMS;
+ }
+
private final NotificationDelegate mNotificationDelegate = new NotificationDelegate() {
@Override
@@ -610,9 +673,19 @@ public class NotificationManagerService extends SystemService {
Binder.restoreCallingIdentity(identity);
}
- // light
- mLights.clear();
- updateLightsLocked();
+ // lights
+ // clear only if lockscreen is not active
+ // and LED is not forced on by Settings app
+ if (mLights.size() > 0) {
+ final String owner = mLights.get(mLights.size() - 1);
+ NotificationRecord ledNotification = mNotificationsByKey.get(owner);
+ if (mKeyguardManager != null && !mKeyguardManager.isKeyguardLocked()) {
+ if (!isLedNotificationForcedOn(ledNotification)) {
+ mLights.clear();
+ }
+ updateLightsLocked();
+ }
+ }
}
}
@@ -774,12 +847,16 @@ public class NotificationManagerService extends SystemService {
}
} else if (action.equals(Intent.ACTION_USER_PRESENT)) {
// turn off LED when user passes through lock screen
- mNotificationLight.turnOff();
- mStatusBar.notificationLightOff();
+ // if lights with screen on is disabled.
+ if (!mScreenOnEnabled) {
+ mNotificationLight.turnOff();
+ mStatusBar.notificationLightOff();
+ }
} else if (action.equals(Intent.ACTION_USER_SWITCHED)) {
final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
// reload per-user settings
mSettingsObserver.update(null);
+ mSpamFilterObserver.update(null);
mUserProfiles.updateCache(context);
// Refresh managed services
mConditionProviders.onUserSwitched(user);
@@ -794,9 +871,103 @@ public class NotificationManagerService extends SystemService {
}
};
- private final class SettingsObserver extends ContentObserver {
+ class SpamFilterObserver extends ContentObserver {
+
+ private Future mTask;
+
+ public SpamFilterObserver(Handler handler) {
+ super(handler);
+ }
+
+ private void addToCache(Cursor c) {
+ int notifId = c.getInt(c.getColumnIndex(
+ NotificationTable.ID));
+ String pkgName = c.getString(c.getColumnIndex(
+ PackageTable.PACKAGE_NAME));
+ String normalizedText = c.getString(c.getColumnIndex(
+ NotificationTable.NORMALIZED_TEXT));
+ int hash = getSpamCacheHash(normalizedText, pkgName);
+ synchronized (mSpamCache) {
+ mSpamCache.put(hash, notifId);
+ }
+ }
+
+ private Runnable mFetchAllFilters = new Runnable() {
+ @Override
+ public void run() {
+ Cursor c = getContext().getContentResolver().query(FILTER_MSG_URI,
+ null, null, null, null);
+ if (c != null) {
+ synchronized (mSpamCache) {
+ mSpamCache.clear();
+ while (c.moveToNext()) {
+ addToCache(c);
+ if (Thread.interrupted()) {
+ break;
+ }
+ c.close();
+ }
+ }
+ }
+ }
+ };
+
+ @Override
+ public void onChange(boolean selfChange, Uri uri) {
+ update(uri);
+ }
+
+ void update(final Uri uri) {
+ if (mTask != null && !mTask.isDone()) {
+ mTask.cancel(true);
+ }
+ if (uri == null) {
+ mTask = mSpamExecutor.submit(mFetchAllFilters);
+ } else {
+ Runnable r = new Runnable() {
+ @Override
+ public void run() {
+ String id = uri.getLastPathSegment();
+ Cursor c = getContext().getContentResolver().query(
+ uri, null, null, null, null);
+
+ if (c != null) {
+ int index;
+ synchronized (mSpamCache) {
+ index = mSpamCache.indexOfValue(Integer.parseInt(id));
+ }
+ if (!c.moveToFirst()) {
+ synchronized (mSpamCache) {
+ // Filter was deleted
+ if (index >= 0) {
+ mSpamCache.removeAt(index);
+ }
+ }
+ } else if (index < 0) {
+ // Filter was added/updated
+ addToCache(c);
+ }
+ c.close();
+ }
+ }
+ };
+ mTask = mSpamExecutor.submit(r);
+ }
+ }
+
+ public void observe() {
+ ContentResolver resolver = getContext().getContentResolver();
+ resolver.registerContentObserver(SpamFilter.NOTIFICATION_URI,
+ true, this, UserHandle.USER_ALL);
+ update(null);
+ }
+ }
+
+ class SettingsObserver extends ContentObserver {
private final Uri NOTIFICATION_LIGHT_PULSE_URI
= Settings.System.getUriFor(Settings.System.NOTIFICATION_LIGHT_PULSE);
+ private final Uri ENABLED_NOTIFICATION_LISTENERS_URI
+ = Settings.Secure.getUriFor(Settings.Secure.ENABLED_NOTIFICATION_LISTENERS);
SettingsObserver(Handler handler) {
super(handler);
@@ -804,8 +975,41 @@ public class NotificationManagerService extends SystemService {
void observe() {
ContentResolver resolver = getContext().getContentResolver();
- resolver.registerContentObserver(NOTIFICATION_LIGHT_PULSE_URI,
+ resolver.registerContentObserver(
+ NOTIFICATION_LIGHT_PULSE_URI, false, this, UserHandle.USER_ALL);
+ resolver.registerContentObserver(
+ ENABLED_NOTIFICATION_LISTENERS_URI, false, this, UserHandle.USER_ALL);
+ resolver.registerContentObserver(CMSettings.System.getUriFor(
+ CMSettings.System.NOTIFICATION_LIGHT_PULSE_DEFAULT_COLOR),
+ false, this, UserHandle.USER_ALL);
+ resolver.registerContentObserver(CMSettings.System.getUriFor(
+ CMSettings.System.NOTIFICATION_LIGHT_PULSE_DEFAULT_LED_ON),
+ false, this, UserHandle.USER_ALL);
+ resolver.registerContentObserver(CMSettings.System.getUriFor(
+ CMSettings.System.NOTIFICATION_LIGHT_PULSE_DEFAULT_LED_OFF),
false, this, UserHandle.USER_ALL);
+ resolver.registerContentObserver(CMSettings.System.getUriFor(
+ CMSettings.System.NOTIFICATION_LIGHT_PULSE_CUSTOM_ENABLE),
+ false, this, UserHandle.USER_ALL);
+ resolver.registerContentObserver(CMSettings.System.getUriFor(
+ CMSettings.System.NOTIFICATION_LIGHT_PULSE_CUSTOM_VALUES),
+ false, this, UserHandle.USER_ALL);
+ resolver.registerContentObserver(CMSettings.System.getUriFor(
+ CMSettings.System.NOTIFICATION_LIGHT_SCREEN_ON),
+ false, this, UserHandle.USER_ALL);
+ resolver.registerContentObserver(CMSettings.Global.getUriFor(
+ CMSettings.Global.ZEN_DISABLE_DUCKING_DURING_MEDIA_PLAYBACK), false,
+ this, UserHandle.USER_ALL);
+ if (mAdjustableNotificationLedBrightness) {
+ resolver.registerContentObserver(CMSettings.System.getUriFor(
+ CMSettings.System.NOTIFICATION_LIGHT_BRIGHTNESS_LEVEL),
+ false, this, UserHandle.USER_ALL);
+ }
+ if (mMultipleNotificationLeds) {
+ resolver.registerContentObserver(CMSettings.System.getUriFor(
+ CMSettings.System.NOTIFICATION_LIGHT_MULTIPLE_LEDS_ENABLE),
+ false, this, UserHandle.USER_ALL);
+ }
update(null);
}
@@ -815,18 +1019,77 @@ public class NotificationManagerService extends SystemService {
public void update(Uri uri) {
ContentResolver resolver = getContext().getContentResolver();
- if (uri == null || NOTIFICATION_LIGHT_PULSE_URI.equals(uri)) {
- boolean pulseEnabled = Settings.System.getInt(resolver,
- Settings.System.NOTIFICATION_LIGHT_PULSE, 0) != 0;
- if (mNotificationPulseEnabled != pulseEnabled) {
- mNotificationPulseEnabled = pulseEnabled;
- updateNotificationPulse();
- }
+
+ // LED enabled
+ mNotificationPulseEnabled = Settings.System.getIntForUser(resolver,
+ Settings.System.NOTIFICATION_LIGHT_PULSE, 0, UserHandle.USER_CURRENT) != 0;
+
+ // LED default color
+ mDefaultNotificationColor = CMSettings.System.getIntForUser(resolver,
+ CMSettings.System.NOTIFICATION_LIGHT_PULSE_DEFAULT_COLOR,
+ mDefaultNotificationColor, UserHandle.USER_CURRENT);
+
+ // LED default on MS
+ mDefaultNotificationLedOn = CMSettings.System.getIntForUser(resolver,
+ CMSettings.System.NOTIFICATION_LIGHT_PULSE_DEFAULT_LED_ON,
+ mDefaultNotificationLedOn, UserHandle.USER_CURRENT);
+
+ // LED default off MS
+ mDefaultNotificationLedOff = CMSettings.System.getIntForUser(resolver,
+ CMSettings.System.NOTIFICATION_LIGHT_PULSE_DEFAULT_LED_OFF,
+ mDefaultNotificationLedOff, UserHandle.USER_CURRENT);
+
+ // LED custom notification colors
+ mNotificationPulseCustomLedValues.clear();
+ if (CMSettings.System.getIntForUser(resolver,
+ CMSettings.System.NOTIFICATION_LIGHT_PULSE_CUSTOM_ENABLE, 0,
+ UserHandle.USER_CURRENT) != 0) {
+ parseNotificationPulseCustomValuesString(CMSettings.System.getStringForUser(resolver,
+ CMSettings.System.NOTIFICATION_LIGHT_PULSE_CUSTOM_VALUES,
+ UserHandle.USER_CURRENT));
+ }
+
+ // Notification LED brightness
+ if (mAdjustableNotificationLedBrightness) {
+ mNotificationLedBrightnessLevel = CMSettings.System.getIntForUser(resolver,
+ CMSettings.System.NOTIFICATION_LIGHT_BRIGHTNESS_LEVEL,
+ LIGHT_BRIGHTNESS_MAXIMUM, UserHandle.USER_CURRENT);
}
+
+ // Multiple LEDs enabled
+ if (mMultipleNotificationLeds) {
+ mMultipleLedsEnabledSetting = (CMSettings.System.getIntForUser(resolver,
+ CMSettings.System.NOTIFICATION_LIGHT_MULTIPLE_LEDS_ENABLE,
+ mMultipleNotificationLeds ? 1 : 0, UserHandle.USER_CURRENT) != 0);
+ }
+
+ // Notification lights with screen on
+ mScreenOnEnabled = (CMSettings.System.getIntForUser(resolver,
+ CMSettings.System.NOTIFICATION_LIGHT_SCREEN_ON,
+ mScreenOnDefault ? 1 : 0, UserHandle.USER_CURRENT) != 0);
+
+ updateNotificationPulse();
+
+ mDisableDuckingWhileMedia = CMSettings.Global.getInt(resolver,
+ CMSettings.Global.ZEN_DISABLE_DUCKING_DURING_MEDIA_PLAYBACK, 0) == 1;
+ updateDisableDucking();
+ }
+ }
+
+ private void updateDisableDucking() {
+ if (!mSystemReady) {
+ return;
+ }
+ final MediaSessionManager mediaSessionManager = (MediaSessionManager) getContext()
+ .getSystemService(Context.MEDIA_SESSION_SERVICE);
+ mediaSessionManager.removeOnActiveSessionsChangedListener(mSessionListener);
+ if (mDisableDuckingWhileMedia) {
+ mediaSessionManager.addOnActiveSessionsChangedListener(mSessionListener, null);
}
}
private SettingsObserver mSettingsObserver;
+ private SpamFilterObserver mSpamFilterObserver;
private ZenModeHelper mZenModeHelper;
private final Runnable mBuzzBeepBlinked = new Runnable() {
@@ -851,6 +1114,7 @@ public class NotificationManagerService extends SystemService {
public NotificationManagerService(Context context) {
super(context);
+ mSpamCache = new SparseIntArray();
}
@Override
@@ -861,6 +1125,8 @@ public class NotificationManagerService extends SystemService {
mAppOps = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE);
mVibrator = (Vibrator) getContext().getSystemService(Context.VIBRATOR_SERVICE);
mAppUsageStats = LocalServices.getService(UsageStatsManagerInternal.class);
+ mKeyguardManager =
+ (KeyguardManager) getContext().getSystemService(Context.KEYGUARD_SERVICE);
mHandler = new WorkerHandler();
mRankingThread.start();
@@ -916,6 +1182,16 @@ public class NotificationManagerService extends SystemService {
mDefaultNotificationLedOff = resources.getInteger(
R.integer.config_defaultNotificationLedOff);
+ mNotificationPulseCustomLedValues = new HashMap<String, NotificationLedValues>();
+
+ mPackageNameMappings = new HashMap<String, String>();
+ final String[] defaultMapping = resources.getStringArray(
+ com.android.internal.R.array.notification_light_package_mapping);
+ for (String mapping : defaultMapping) {
+ String[] map = mapping.split("\\|");
+ mPackageNameMappings.put(map[0], map[1]);
+ }
+
mDefaultVibrationPattern = getLongArray(resources,
R.array.config_defaultNotificationVibePattern,
VIBRATE_PATTERN_MAXLEN,
@@ -926,6 +1202,11 @@ public class NotificationManagerService extends SystemService {
VIBRATE_PATTERN_MAXLEN,
DEFAULT_VIBRATE_PATTERN);
+ mAdjustableNotificationLedBrightness = resources.getBoolean(
+ org.cyanogenmod.platform.internal.R.bool.config_adjustableNotificationLedBrightness);
+ mMultipleNotificationLeds = resources.getBoolean(
+ org.cyanogenmod.platform.internal.R.bool.config_multipleNotificationLeds);
+
mUseAttentionLight = resources.getBoolean(R.bool.config_useAttentionLight);
// Don't start allowing notifications until the setup wizard has run once.
@@ -969,6 +1250,10 @@ public class NotificationManagerService extends SystemService {
null);
mSettingsObserver = new SettingsObserver(mHandler);
+ mSettingsObserver.observe();
+
+ mSpamFilterObserver = new SpamFilterObserver(mHandler);
+ mSpamFilterObserver.observe();
mArchive = new Archive(resources.getInteger(
R.integer.config_notificationServiceArchiveSize));
@@ -1011,10 +1296,13 @@ public class NotificationManagerService extends SystemService {
mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
mAudioManagerInternal = getLocalService(AudioManagerInternal.class);
mZenModeHelper.onSystemReady();
+
+ updateDisableDucking();
} else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
// This observer will force an update when observe is called, causing us to
// bind to listener services.
mSettingsObserver.observe();
+ mSpamFilterObserver.observe();
mListeners.onBootPhaseAppsCanStart();
mConditionProviders.onBootPhaseAppsCanStart();
}
@@ -2167,6 +2455,11 @@ public class NotificationManagerService extends SystemService {
return;
}
+ if (isNotificationSpam(notification, pkg)) {
+ mArchive.record(r.sbn);
+ return;
+ }
+
int index = indexOfNotificationLocked(n.getKey());
if (index < 0) {
mNotificationList.add(r);
@@ -2310,6 +2603,21 @@ public class NotificationManagerService extends SystemService {
return false;
}
+ private MediaSessionManager.OnActiveSessionsChangedListener mSessionListener =
+ new MediaSessionManager.OnActiveSessionsChangedListener() {
+ @Override
+ public void onActiveSessionsChanged(@Nullable List<MediaController> controllers) {
+ for (MediaController activeSession : controllers) {
+ PlaybackState playbackState = activeSession.getPlaybackState();
+ if (playbackState != null && playbackState.getState() == PlaybackState.STATE_PLAYING) {
+ mActiveMedia = true;
+ return;
+ }
+ }
+ mActiveMedia = false;
+ }
+ };
+
private void buzzBeepBlinkLocked(NotificationRecord record) {
boolean buzz = false;
boolean beep = false;
@@ -2339,7 +2647,9 @@ public class NotificationManagerService extends SystemService {
if (disableEffects != null) {
ZenLog.traceDisableEffects(record, disableEffects);
}
- if (disableEffects == null
+ boolean smsRingtone = getContext().getResources().getBoolean(
+ com.android.internal.R.bool.config_sms_ringtone_incall);
+ if ((disableEffects == null || (smsRingtone && mInCall))
&& (!(record.isUpdate
&& (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0 ))
&& (record.getUserId() == UserHandle.USER_ALL ||
@@ -2377,7 +2687,7 @@ public class NotificationManagerService extends SystemService {
hasValidSound = (soundUri != null);
}
- if (hasValidSound) {
+ if (hasValidSound && (!mDisableDuckingWhileMedia || !mActiveMedia)) {
boolean looping =
(notification.flags & Notification.FLAG_INSISTENT) != 0;
AudioAttributes audioAttributes = audioAttributesForNotification(notification);
@@ -2455,7 +2765,8 @@ public class NotificationManagerService extends SystemService {
// light
// release the light
boolean wasShowLights = mLights.remove(record.getKey());
- if ((notification.flags & Notification.FLAG_SHOW_LIGHTS) != 0 && aboveThreshold) {
+ final boolean aboveThresholdWithLight = aboveThreshold || isLedNotificationForcedOn(record);
+ if ((notification.flags & Notification.FLAG_SHOW_LIGHTS) != 0 && aboveThresholdWithLight) {
mLights.add(record.getKey());
updateLightsLocked();
if (mUseAttentionLight) {
@@ -2741,6 +3052,33 @@ public class NotificationManagerService extends SystemService {
return (x < low) ? low : ((x > high) ? high : x);
}
+ private int getSpamCacheHash(CharSequence message, String packageName) {
+ return (message + packageName).hashCode();
+ }
+
+ private boolean isNotificationSpam(Notification notification, String basePkg) {
+ CharSequence normalizedContent = SpamFilter
+ .getNormalizedNotificationContent(notification);
+ int notificationHash = getSpamCacheHash(normalizedContent, basePkg);
+ int notificationId;
+ synchronized (mSpamCache) {
+ notificationId = mSpamCache.get(notificationHash, -1);
+ }
+ if (notificationId != -1) {
+ final String notifIdString = String.valueOf(notificationId);
+ mSpamExecutor.submit(new Runnable() {
+ @Override
+ public void run() {
+ Uri updateUri = Uri.withAppendedPath(UPDATE_MSG_URI,
+ notifIdString);
+ getContext().getContentResolver().update(updateUri,
+ new ContentValues(), null, null);
+ }
+ });
+ }
+ return notificationId != -1;
+ }
+
void sendAccessibilityEvent(Notification notification, CharSequence packageName) {
AccessibilityManager manager = AccessibilityManager.getInstance(getContext());
if (!manager.isEnabled()) {
@@ -3040,6 +3378,16 @@ public class NotificationManagerService extends SystemService {
}
}
+ private boolean isLedNotificationForcedOn(NotificationRecord r) {
+ if (r != null) {
+ final Notification n = r.sbn.getNotification();
+ if (n.extras != null) {
+ return n.extras.getBoolean(Notification.EXTRA_FORCE_SHOW_LIGHTS, false);
+ }
+ }
+ return false;
+ }
+
// lock on mNotificationList
void updateLightsLocked()
{
@@ -3055,29 +3403,101 @@ public class NotificationManagerService extends SystemService {
}
// Don't flash while we are in a call or screen is on
- if (ledNotification == null || mInCall || mScreenOn) {
+ // (unless Notification has EXTRA_FORCE_SHOW_LGHTS)
+ final boolean enableLed;
+ if (ledNotification == null) {
+ enableLed = false;
+ } else if (isLedNotificationForcedOn(ledNotification)) {
+ enableLed = true;
+ } else if (!mScreenOnEnabled && (mInCall || mScreenOn)) {
+ enableLed = false;
+ } else {
+ enableLed = true;
+ }
+
+ if (!enableLed) {
mNotificationLight.turnOff();
mStatusBar.notificationLightOff();
} else {
final Notification ledno = ledNotification.sbn.getNotification();
- int ledARGB = ledno.ledARGB;
- int ledOnMS = ledno.ledOnMS;
- int ledOffMS = ledno.ledOffMS;
- if ((ledno.defaults & Notification.DEFAULT_LIGHTS) != 0) {
+ final NotificationLedValues ledValues = getLedValuesForNotification(ledNotification);
+ int ledARGB;
+ int ledOnMS;
+ int ledOffMS;
+
+ if (ledValues != null) {
+ ledARGB = ledValues.color != 0 ? ledValues.color : mDefaultNotificationColor;
+ ledOnMS = ledValues.onMS >= 0 ? ledValues.onMS : mDefaultNotificationLedOn;
+ ledOffMS = ledValues.offMS >= 0 ? ledValues.offMS : mDefaultNotificationLedOff;
+ } else if ((ledno.defaults & Notification.DEFAULT_LIGHTS) != 0) {
ledARGB = mDefaultNotificationColor;
ledOnMS = mDefaultNotificationLedOn;
ledOffMS = mDefaultNotificationLedOff;
+ } else {
+ ledARGB = ledno.ledARGB;
+ ledOnMS = ledno.ledOnMS;
+ ledOffMS = ledno.ledOffMS;
}
+
+ // update the LEDs modes variables
+ mNotificationLight.setModes(mNotificationLedBrightnessLevel,
+ mMultipleLedsEnabledSetting);
+
if (mNotificationPulseEnabled) {
// pulse repeatedly
mNotificationLight.setFlashing(ledARGB, Light.LIGHT_FLASH_TIMED,
ledOnMS, ledOffMS);
}
+
// let SystemUI make an independent decision
mStatusBar.notificationLightPulse(ledARGB, ledOnMS, ledOffMS);
}
}
+ 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 (NumberFormatException e) {
+ Log.e(TAG, "Error parsing custom led values '"
+ + packageValues[1] + "' for " + packageName);
+ continue;
+ }
+ mNotificationPulseCustomLedValues.put(packageName, ledValues);
+ }
+ }
+
+ private NotificationLedValues getLedValuesForNotification(NotificationRecord ledNotification) {
+ final String packageName = ledNotification.sbn.getPackageName();
+ return mNotificationPulseCustomLedValues.get(mapPackage(packageName));
+ }
+
+ private String mapPackage(String pkg) {
+ if (!mPackageNameMappings.containsKey(pkg)) {
+ return pkg;
+ }
+ return mPackageNameMappings.get(pkg);
+ }
+
// lock on mNotificationList
int indexOfNotificationLocked(String pkg, String tag, int id, int userId)
{
diff --git a/services/core/java/com/android/server/pm/BasePermission.java b/services/core/java/com/android/server/pm/BasePermission.java
index 52d0928..cab4691 100644
--- a/services/core/java/com/android/server/pm/BasePermission.java
+++ b/services/core/java/com/android/server/pm/BasePermission.java
@@ -53,6 +53,8 @@ final class BasePermission {
*/
private boolean perUser;
+ boolean allowViaWhitelist;
+
BasePermission(String _name, String _sourcePackage, int _type) {
name = _name;
sourcePackage = _sourcePackage;
diff --git a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
index b504605..df023fd 100644
--- a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
@@ -20,6 +20,7 @@ import android.Manifest;
import android.app.DownloadManager;
import android.app.admin.DevicePolicyManager;
import android.content.Intent;
+import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal.PackagesProvider;
@@ -585,7 +586,6 @@ final class DefaultPermissionGrantPolicy {
}
}
-
private void grantDefaultPermissionsToDefaultSystemSmsAppLPr(
PackageParser.Package smsPackage, int userId) {
if (doesPackageSupportRuntimePermissions(smsPackage)) {
@@ -595,7 +595,6 @@ final class DefaultPermissionGrantPolicy {
}
}
-
public void grantDefaultPermissionsToDefaultSmsAppLPr(String packageName, int userId) {
Log.i(TAG, "Granting permissions to default sms app for user:" + userId);
if (packageName == null) {
@@ -673,29 +672,23 @@ final class DefaultPermissionGrantPolicy {
private PackageParser.Package getDefaultSystemHandlerActivityPackageLPr(
Intent intent, int userId) {
- List<ResolveInfo> handlers = mService.mActivities.queryIntent(intent,
- intent.resolveType(mService.mContext.getContentResolver()),
- PackageManager.GET_DISABLED_COMPONENTS, userId);
- if (handlers == null) {
+ ResolveInfo handler = mService.resolveIntent(intent,
+ intent.resolveType(mService.mContext.getContentResolver()), 0, userId);
+ if (handler == null || handler.activityInfo == null) {
return null;
}
- final int handlerCount = handlers.size();
- for (int i = 0; i < handlerCount; i++) {
- ResolveInfo handler = handlers.get(i);
- PackageParser.Package handlerPackage = getSystemPackageLPr(
- handler.activityInfo.packageName);
- if (handlerPackage != null) {
- return handlerPackage;
- }
+ ActivityInfo activityInfo = handler.activityInfo;
+ if (activityInfo.packageName.equals(mService.mResolveActivity.packageName)
+ && activityInfo.name.equals(mService.mResolveActivity.name)) {
+ return null;
}
- return null;
+ return getSystemPackageLPr(handler.activityInfo.packageName);
}
private PackageParser.Package getDefaultSystemHandlerServicePackageLPr(
Intent intent, int userId) {
List<ResolveInfo> handlers = mService.queryIntentServices(intent,
- intent.resolveType(mService.mContext.getContentResolver()),
- PackageManager.GET_DISABLED_COMPONENTS, userId);
+ intent.resolveType(mService.mContext.getContentResolver()), 0, userId);
if (handlers == null) {
return null;
}
@@ -721,10 +714,9 @@ final class DefaultPermissionGrantPolicy {
for (String syncAdapterPackageName : syncAdapterPackageNames) {
homeIntent.setPackage(syncAdapterPackageName);
- List<ResolveInfo> homeActivities = mService.mActivities.queryIntent(homeIntent,
- homeIntent.resolveType(mService.mContext.getContentResolver()),
- PackageManager.GET_DISABLED_COMPONENTS, userId);
- if (!homeActivities.isEmpty()) {
+ ResolveInfo homeActivity = mService.resolveIntent(homeIntent,
+ homeIntent.resolveType(mService.mContext.getContentResolver()), 0, userId);
+ if (homeActivity != null) {
continue;
}
@@ -843,7 +835,7 @@ final class DefaultPermissionGrantPolicy {
return false;
}
PackageSetting sysPkg = mService.mSettings.getDisabledSystemPkgLPr(pkg.packageName);
- if (sysPkg != null) {
+ if (sysPkg != null && sysPkg.pkg != null) {
if ((sysPkg.pkg.applicationInfo.flags & ApplicationInfo.FLAG_PERSISTENT) == 0) {
return false;
}
diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java
index f292c9c..5f183a2 100644
--- a/services/core/java/com/android/server/pm/Installer.java
+++ b/services/core/java/com/android/server/pm/Installer.java
@@ -110,14 +110,51 @@ public final class Installer extends SystemService {
debuggable, outputPath, bootComplete);
}
- public int idmap(String targetApkPath, String overlayApkPath, int uid) {
+ public int idmap(String targetApkPath, String overlayApkPath, String cachePath,
+ int uid, int targetHash, int overlayHash) {
StringBuilder builder = new StringBuilder("idmap");
builder.append(' ');
builder.append(targetApkPath);
builder.append(' ');
builder.append(overlayApkPath);
builder.append(' ');
+ builder.append(cachePath);
+ builder.append(' ');
builder.append(uid);
+ builder.append(' ');
+ builder.append(targetHash);
+ builder.append(' ');
+ builder.append(overlayHash);
+ return mInstaller.execute(builder.toString());
+ }
+
+ public int aapt(String themeApkPath, String internalPath, String resTablePath, int uid,
+ int pkgId, int minSdkVersion, String commonResourcesPath) {
+
+ StringBuilder builder = new StringBuilder();
+ if (TextUtils.isEmpty(commonResourcesPath)) {
+ builder.append("aapt");
+ } else {
+ builder.append("aapt_with_common");
+ }
+ builder.append(' ');
+ builder.append(themeApkPath);
+ builder.append(' ');
+ builder.append(internalPath);
+ builder.append(' ');
+ builder.append(resTablePath);
+ builder.append(' ');
+ builder.append(uid);
+ builder.append(' ');
+ builder.append(pkgId);
+ builder.append(' ');
+ builder.append(minSdkVersion);
+
+ if (!TextUtils.isEmpty(commonResourcesPath)) {
+ builder.append(' ');
+ builder.append(commonResourcesPath);
+ }
+
return mInstaller.execute(builder.toString());
}
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 4a473fd..65f5bce 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -381,7 +381,15 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
if (stageDir != null && deltaBytes > 0) {
mPm.freeStorage(params.volumeUuid, deltaBytes);
}
- Libcore.os.posix_fallocate(targetFd, 0, lengthBytes);
+ try {
+ Libcore.os.posix_fallocate(targetFd, 0, lengthBytes);
+ } catch (ErrnoException e) {
+ if (e.errno == OsConstants.ENOTSUP) {
+ Libcore.os.ftruncate(targetFd, lengthBytes);
+ } else {
+ throw e.rethrowAsIOException();
+ }
+ }
}
if (offsetBytes > 0) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index c1d091b..358b773 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2006 The Android Open Source Project
+ * This code has been modified. Portions copyright (C) 2010, T-Mobile USA, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,6 +17,7 @@
package com.android.server.pm;
+import static android.Manifest.permission.ACCESS_THEME_MANAGER;
import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE;
import static android.Manifest.permission.WRITE_MEDIA_STORAGE;
@@ -42,6 +44,7 @@ import static android.content.pm.PackageManager.INSTALL_FAILED_INVALID_APK;
import static android.content.pm.PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
import static android.content.pm.PackageManager.INSTALL_FAILED_MISSING_SHARED_LIBRARY;
import static android.content.pm.PackageManager.INSTALL_FAILED_PACKAGE_CHANGED;
+import static android.content.pm.PackageManager.INSTALL_FAILED_REGION_LOCKED_PREBUNDLE;
import static android.content.pm.PackageManager.INSTALL_FAILED_REPLACE_COULDNT_DELETE;
import static android.content.pm.PackageManager.INSTALL_FAILED_SHARED_USER_INCOMPATIBLE;
import static android.content.pm.PackageManager.INSTALL_FAILED_TEST_ONLY;
@@ -64,6 +67,7 @@ import static android.content.pm.PackageManager.MOVE_FAILED_OPERATION_PENDING;
import static android.content.pm.PackageManager.MOVE_FAILED_SYSTEM_PACKAGE;
import static android.content.pm.PackageManager.PERMISSION_DENIED;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+import static android.content.pm.PackageManager.INSTALL_FAILED_UNINSTALLED_PREBUNDLE;
import static android.content.pm.PackageParser.isApkFile;
import static android.os.Process.PACKAGE_INFO_GID;
import static android.os.Process.SYSTEM_UID;
@@ -82,12 +86,22 @@ import static com.android.server.pm.InstructionSets.getPrimaryInstructionSet;
import static com.android.server.pm.PermissionsState.PERMISSION_OPERATION_FAILURE;
import static com.android.server.pm.PermissionsState.PERMISSION_OPERATION_SUCCESS;
import static com.android.server.pm.PermissionsState.PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED;
+import static com.android.internal.util.ArrayUtils.removeInt;
+
+import android.content.res.Configuration;
import android.Manifest;
+
+import cyanogenmod.app.suggest.AppSuggestManager;
+
import android.app.ActivityManager;
import android.app.ActivityManagerNative;
import android.app.AppGlobals;
+import android.app.ComposedIconInfo;
+import android.app.AppOpsManager;
import android.app.IActivityManager;
+import android.app.IconPackHelper;
+import android.app.PackageInstallObserver;
import android.app.admin.IDevicePolicyManager;
import android.app.backup.IBackupManager;
import android.app.usage.UsageStats;
@@ -129,6 +143,9 @@ import android.content.pm.PackageParser.ActivityIntentInfo;
import android.content.pm.PackageParser.PackageLite;
import android.content.pm.PackageParser.PackageParserException;
import android.content.pm.PackageStats;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.PackageParser.Activity;
+import android.content.pm.PackageParser.Package;
import android.content.pm.PackageUserState;
import android.content.pm.ParceledListSlice;
import android.content.pm.PermissionGroupInfo;
@@ -138,10 +155,15 @@ import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.content.pm.Signature;
import android.content.pm.UserInfo;
+import android.content.pm.ManifestDigest;
+import android.content.pm.ThemeUtils;
import android.content.pm.VerificationParams;
import android.content.pm.VerifierDeviceIdentity;
import android.content.pm.VerifierInfo;
import android.content.res.Resources;
+import android.content.res.AssetManager;
+import android.content.res.ThemeConfig;
+import android.content.res.ThemeManager;
import android.hardware.display.DisplayManager;
import android.net.Uri;
import android.os.Debug;
@@ -172,6 +194,8 @@ import android.os.storage.StorageEventListener;
import android.os.storage.StorageManager;
import android.os.storage.VolumeInfo;
import android.os.storage.VolumeRecord;
+import android.provider.Settings.Global;
+import android.provider.Settings.Secure;
import android.security.KeyStore;
import android.security.SystemKeyStore;
import android.system.ErrnoException;
@@ -188,6 +212,7 @@ import android.util.ExceptionUtils;
import android.util.Log;
import android.util.LogPrinter;
import android.util.MathUtils;
+import android.util.Pair;
import android.util.PrintStreamPrinter;
import android.util.Slog;
import android.util.SparseArray;
@@ -196,6 +221,7 @@ import android.util.SparseIntArray;
import android.util.Xml;
import android.view.Display;
+import cyanogenmod.providers.CMSettings;
import dalvik.system.DexFile;
import dalvik.system.VMRuntime;
@@ -237,16 +263,25 @@ import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
+import java.io.BufferedWriter;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
import java.io.File;
import java.io.FileDescriptor;
+import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
+import java.io.FileWriter;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStream;
+import java.io.OutputStream;
import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.IntBuffer;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.cert.CertificateEncodingException;
@@ -268,6 +303,8 @@ import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
/**
* Keep track of all those .apks everywhere.
@@ -298,6 +335,7 @@ public class PackageManagerService extends IPackageManager.Stub {
private static final boolean DEBUG_VERIFY = false;
private static final boolean DEBUG_DEXOPT = false;
private static final boolean DEBUG_ABI_SELECTION = false;
+ private static final boolean DEBUG_PREBUNDLED_SCAN = false;
static final boolean CLEAR_RUNTIME_PERMISSIONS_ON_UPGRADE = false;
@@ -339,7 +377,7 @@ public class PackageManagerService extends IPackageManager.Stub {
* minute but we sometimes do very lengthy I/O operations on this thread,
* such as installing multi-gigabyte applications, so ours needs to be longer.
*/
- private static final long WATCHDOG_TIMEOUT = 1000*60*10; // ten minutes
+ private static final long WATCHDOG_TIMEOUT = 1000*60*60; // sixty minutes
/**
* Wall-clock timeout (in milliseconds) after which we *require* that an fstrim
@@ -414,6 +452,21 @@ public class PackageManagerService extends IPackageManager.Stub {
final ServiceThread mHandlerThread;
+ //Where overlays are be found in a theme APK
+ private static final String APK_PATH_TO_OVERLAY = "assets/overlays/";
+
+ //Where the icon pack can be found in a themed apk
+ private static final String APK_PATH_TO_ICONS = "assets/icons/";
+
+ private static final String COMMON_OVERLAY = ThemeUtils.COMMON_RES_TARGET;
+
+ private static final long COMMON_RESOURCE_EXPIRATION = 3*60*1000; // 3 minutes
+
+ /**
+ * The offset in bytes to the beginning of the hashes in an idmap
+ */
+ private static final int IDMAP_HASH_START_OFFSET = 16;
+
final PackageHandler mHandler;
/**
@@ -500,10 +553,13 @@ public class PackageManagerService extends IPackageManager.Stub {
final Settings mSettings;
boolean mRestoredSettings;
+ private Resources mCustomResources;
+
// System configuration read by SystemConfig.
final int[] mGlobalGids;
final SparseArray<ArraySet<String>> mSystemPermissions;
final ArrayMap<String, FeatureInfo> mAvailableFeatures;
+ final ArrayMap<Signature, ArraySet<String>> mSignatureAllowances;
// If mac_permissions.xml was found for seinfo labeling.
boolean mFoundPolicyFile;
@@ -819,6 +875,16 @@ public class PackageManagerService extends IPackageManager.Stub {
private IntentFilterVerifier mIntentFilterVerifier;
+ private IconPackHelper mIconPackHelper;
+
+ private Map<String, Long> mAvailableCommonResources = new ArrayMap<String, Long>();
+
+ private ThemeConfig mBootThemeConfig;
+
+ ArrayList<ComponentName> mDisabledComponentsList;
+
+ private AppOpsManager mAppOps;
+
// Set of pending broadcasts for aggregating enable/disable of components.
static class PendingPackageBroadcasts {
// for each user id, a map of <package name -> components within that package>
@@ -1388,18 +1454,22 @@ public class PackageManagerService extends IPackageManager.Stub {
}
}
sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED,
- packageName, extras, null, null, firstUsers);
+ packageName, null, extras, null, null, firstUsers);
final boolean update = res.removedInfo.removedPackage != null;
if (update) {
extras.putBoolean(Intent.EXTRA_REPLACING, true);
}
+ String category = null;
+ if(res.pkg.mIsThemeApk) {
+ category = Intent.CATEGORY_THEME_PACKAGE_INSTALLED_STATE_CHANGE;
+ }
sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED,
- packageName, extras, null, null, updateUsers);
+ packageName, null, extras, null, null, updateUsers);
if (update) {
sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED,
- packageName, extras, null, null, updateUsers);
+ packageName, null, extras, null, null, updateUsers);
sendPackageBroadcast(Intent.ACTION_MY_PACKAGE_REPLACED,
- null, null, packageName, null, updateUsers);
+ null, null, null, packageName, null, updateUsers);
// treat asec-hosted packages like removable media on upgrade
if (res.pkg.isForwardLocked() || isExternal(res.pkg)) {
@@ -1414,6 +1484,10 @@ public class PackageManagerService extends IPackageManager.Stub {
pkgList,uidArray, null);
}
}
+ // if this was a theme, send it off to the theme service for processing
+ if(res.pkg.mIsThemeApk || res.pkg.mIsLegacyIconPackApk) {
+ processThemeResourcesInThemeService(res.pkg.packageName);
+ }
if (res.removedInfo.args != null) {
// Remove the replaced package's older resources safely now
deleteOld = true;
@@ -1432,6 +1506,17 @@ public class PackageManagerService extends IPackageManager.Stub {
}
}
}
+ if (!update && !isSystemApp(res.pkg)) {
+ boolean privacyGuard = CMSettings.Secure.getIntForUser(
+ mContext.getContentResolver(),
+ CMSettings.Secure.PRIVACY_GUARD_DEFAULT,
+ 0, UserHandle.USER_CURRENT) == 1;
+ if (privacyGuard) {
+ mAppOps.setPrivacyGuardSettingForPackage(
+ res.pkg.applicationInfo.uid,
+ res.pkg.applicationInfo.packageName, true);
+ }
+ }
// Log current value of "unknown sources" setting
EventLog.writeEvent(EventLogTags.UNKNOWN_SOURCES_ENABLED,
getUnknownSourcesSettings());
@@ -1835,6 +1920,8 @@ public class PackageManagerService extends IPackageManager.Stub {
}
mDexOptLRUThresholdInMills = dexOptLRUThresholdInMinutes * 60 * 1000;
+ mAppOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
+
String separateProcesses = SystemProperties.get("debug.separate_processes");
if (separateProcesses != null && separateProcesses.length() > 0) {
if ("*".equals(separateProcesses)) {
@@ -1861,10 +1948,13 @@ public class PackageManagerService extends IPackageManager.Stub {
getDefaultDisplayMetrics(context, mMetrics);
+ removeLegacyResourceCache();
+
SystemConfig systemConfig = SystemConfig.getInstance();
mGlobalGids = systemConfig.getGlobalGids();
mSystemPermissions = systemConfig.getSystemPermissions();
mAvailableFeatures = systemConfig.getAvailableFeatures();
+ mSignatureAllowances = systemConfig.getSignatureAllowances();
synchronized (mInstallLock) {
// writer
@@ -1910,10 +2000,13 @@ public class PackageManagerService extends IPackageManager.Stub {
mFoundPolicyFile = SELinuxMMAC.readInstallPolicy();
mRestoredSettings = mSettings.readLPw(this, sUserManager.getUsers(false),
- mSdkVersion, mOnlyCore);
+ mSdkVersion, mOnlyCore, mInstaller);
- String customResolverActivity = Resources.getSystem().getString(
- R.string.config_customResolverActivity);
+ String customResolverActivity = SystemProperties.get("ro.custom.resolver.activity");
+ if (TextUtils.isEmpty(customResolverActivity)) {
+ customResolverActivity = Resources.getSystem().getString(
+ R.string.config_customResolverActivity);
+ }
if (TextUtils.isEmpty(customResolverActivity)) {
customResolverActivity = null;
} else {
@@ -2005,6 +2098,10 @@ public class PackageManagerService extends IPackageManager.Stub {
// avoid the resulting log spew.
alreadyDexOpted.add(frameworkDir.getPath() + "/core-libart.jar");
+ // Gross hack for now: we know this file doesn't contain any
+ // code, so don't dexopt it to avoid the resulting log spew
+ alreadyDexOpted.add(frameworkDir.getPath() + "/org.cyanogenmod.platform-res.apk");
+
/**
* There are a number of commands implemented in Java, which
* we currently need to do the dexopt on so that they can be
@@ -2042,7 +2139,8 @@ public class PackageManagerService extends IPackageManager.Stub {
}
final VersionInfo ver = mSettings.getInternalVersion();
- mIsUpgrade = !Build.FINGERPRINT.equals(ver.fingerprint);
+ mIsUpgrade = !Build.FINGERPRINT.equals(ver.fingerprint) ||
+ !Build.DISPLAY.equals(ver.displayversion);
// when upgrading from pre-M, promote system app permissions from install to runtime
mPromoteSystemApps =
mIsUpgrade && ver.sdkVersion <= Build.VERSION_CODES.LOLLIPOP_MR1;
@@ -2059,30 +2157,32 @@ public class PackageManagerService extends IPackageManager.Stub {
}
}
+ mBootThemeConfig = ThemeConfig.getSystemTheme();
+
// Collect vendor overlay packages.
// (Do this before scanning any apps.)
// For security and version matching reason, only consider
// overlay packages if they reside in VENDOR_OVERLAY_DIR.
File vendorOverlayDir = new File(VENDOR_OVERLAY_DIR);
scanDirLI(vendorOverlayDir, PackageParser.PARSE_IS_SYSTEM
- | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags | SCAN_TRUSTED_OVERLAY, 0);
+ | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags | SCAN_TRUSTED_OVERLAY, 0, null);
// Find base frameworks (resource packages without code).
scanDirLI(frameworkDir, PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR
| PackageParser.PARSE_IS_PRIVILEGED,
- scanFlags | SCAN_NO_DEX, 0);
+ scanFlags | SCAN_NO_DEX, 0, null);
// Collected privileged system packages.
final File privilegedAppDir = new File(Environment.getRootDirectory(), "priv-app");
scanDirLI(privilegedAppDir, PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR
- | PackageParser.PARSE_IS_PRIVILEGED, scanFlags, 0);
+ | PackageParser.PARSE_IS_PRIVILEGED, scanFlags, 0, null);
// Collect ordinary system packages.
final File systemAppDir = new File(Environment.getRootDirectory(), "app");
scanDirLI(systemAppDir, PackageParser.PARSE_IS_SYSTEM
- | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);
+ | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0, null);
// Collect all vendor packages.
File vendorAppDir = new File("/vendor/app");
@@ -2092,12 +2192,19 @@ public class PackageManagerService extends IPackageManager.Stub {
// failed to look up canonical path, continue with original one
}
scanDirLI(vendorAppDir, PackageParser.PARSE_IS_SYSTEM
- | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);
+ | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0, null);
// Collect all OEM packages.
final File oemAppDir = new File(Environment.getOemDirectory(), "app");
scanDirLI(oemAppDir, PackageParser.PARSE_IS_SYSTEM
- | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);
+ | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0, null);
+
+ // Collect all prebundled packages.
+ createAndSetCustomResources();
+ scanDirLI(Environment.getPrebundledDirectory(),
+ PackageParser.PARSE_IS_PREBUNDLED_DIR, scanFlags, 0, UserHandle.OWNER);
+ // Clean up
+ mCustomResources = null;
if (DEBUG_UPGRADE) Log.v(TAG, "Running installd update commands");
mInstaller.moveFiles();
@@ -2172,10 +2279,10 @@ public class PackageManagerService extends IPackageManager.Stub {
if (!mOnlyCore) {
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START,
SystemClock.uptimeMillis());
- scanDirLI(mAppInstallDir, 0, scanFlags | SCAN_REQUIRE_KNOWN, 0);
+ scanDirLI(mAppInstallDir, 0, scanFlags | SCAN_REQUIRE_KNOWN, 0, null);
scanDirLI(mDrmAppPrivateInstallDir, PackageParser.PARSE_FORWARD_LOCK,
- scanFlags | SCAN_REQUIRE_KNOWN, 0);
+ scanFlags | SCAN_REQUIRE_KNOWN, 0, null);
/**
* Remove disable package settings for any updated system
@@ -2288,6 +2395,12 @@ public class PackageManagerService extends IPackageManager.Stub {
updatePermissionsLPw(null, null, StorageManager.UUID_PRIVATE_INTERNAL, updateFlags);
ver.sdkVersion = mSdkVersion;
+ // Remove any stale app permissions (declared permission that now are undeclared
+ // by the same app, removed from its Manifest in newer versions)
+ if (!onlyCore) {
+ mSettings.removeStalePermissions();
+ }
+
// If this is the first boot or an update from pre-M, and it is a normal
// boot, then we need to initialize the default preferred apps across
// all defined users.
@@ -2299,10 +2412,42 @@ public class PackageManagerService extends IPackageManager.Stub {
}
}
+ // Disable components marked for disabling at build-time
+ mDisabledComponentsList = new ArrayList<ComponentName>();
+ for (String name : mContext.getResources().getStringArray(
+ com.android.internal.R.array.config_disabledComponents)) {
+ ComponentName cn = ComponentName.unflattenFromString(name);
+ mDisabledComponentsList.add(cn);
+ Slog.v(TAG, "Disabling " + name);
+ String className = cn.getClassName();
+ PackageSetting pkgSetting = mSettings.mPackages.get(cn.getPackageName());
+ if (pkgSetting == null || pkgSetting.pkg == null
+ || !pkgSetting.pkg.hasComponentClassName(className)) {
+ Slog.w(TAG, "Unable to disable " + name);
+ continue;
+ }
+ pkgSetting.disableComponentLPw(className, UserHandle.USER_OWNER);
+ }
+
+ // Enable components marked for forced-enable at build-time
+ for (String name : mContext.getResources().getStringArray(
+ com.android.internal.R.array.config_forceEnabledComponents)) {
+ ComponentName cn = ComponentName.unflattenFromString(name);
+ Slog.v(TAG, "Enabling " + name);
+ String className = cn.getClassName();
+ PackageSetting pkgSetting = mSettings.mPackages.get(cn.getPackageName());
+ if (pkgSetting == null || pkgSetting.pkg == null
+ || !pkgSetting.pkg.hasComponentClassName(className)) {
+ Slog.w(TAG, "Unable to enable " + name);
+ continue;
+ }
+ pkgSetting.enableComponentLPw(className, UserHandle.USER_OWNER);
+ }
+
// If this is first boot after an OTA, and a normal boot, then
// we need to clear code cache directories.
if (mIsUpgrade && !onlyCore) {
- Slog.i(TAG, "Build fingerprint changed; clearing code caches");
+ Slog.i(TAG, "Build fingerprint or displayversion changed; clearing code caches");
for (int i = 0; i < mSettings.mPackages.size(); i++) {
final PackageSetting ps = mSettings.mPackages.valueAt(i);
if (Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, ps.volumeUuid)) {
@@ -2310,6 +2455,7 @@ public class PackageManagerService extends IPackageManager.Stub {
}
}
ver.fingerprint = Build.FINGERPRINT;
+ ver.displayversion = Build.DISPLAY;
}
checkDefaultBrowser();
@@ -3345,6 +3491,7 @@ public class PackageManagerService extends IPackageManager.Stub {
if (!compareStrings(pi1.nonLocalizedLabel, pi2.nonLocalizedLabel)) return false;
// We'll take care of setting this one.
if (!compareStrings(pi1.packageName, pi2.packageName)) return false;
+ if (pi1.allowViaWhitelist != pi2.allowViaWhitelist) return false;
// These are not currently stored in settings.
//if (!compareStrings(pi1.group, pi2.group)) return false;
//if (!compareStrings(pi1.nonLocalizedDescription, pi2.nonLocalizedDescription)) return false;
@@ -3469,6 +3616,16 @@ public class PackageManagerService extends IPackageManager.Stub {
}
}
+ private boolean isAllowedSignature(PackageParser.Package pkg, String permissionName) {
+ for (Signature pkgSig : pkg.mSignatures) {
+ ArraySet<String> perms = mSignatureAllowances.get(pkgSig);
+ if (perms != null && perms.contains(permissionName)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
@Override
public void grantRuntimePermission(String packageName, String name, final int userId) {
if (!sUserManager.exists(userId)) {
@@ -3963,7 +4120,7 @@ public class PackageManagerService extends IPackageManager.Stub {
return PackageManager.SIGNATURE_NO_MATCH;
}
- // Since both signature sets are of size 1, we can compare without HashSets.
+ // Since both signature sets are of size 1, we can compare without ArraySets.
if (s1.length == 1) {
return s1[0].equals(s2[0]) ?
PackageManager.SIGNATURE_MATCH :
@@ -4266,6 +4423,17 @@ public class PackageManagerService extends IPackageManager.Stub {
if (ri.activityInfo.metaData == null) ri.activityInfo.metaData = new Bundle();
ri.activityInfo.metaData.putBoolean(Intent.METADATA_DOCK_HOME, true);
return ri;
+ } else if (shouldIncludeResolveActivity(intent)) {
+ if (userId != 0) {
+ ResolveInfo ri = new ResolveInfo(mResolveInfo);
+ ri.activityInfo = new ActivityInfo(ri.activityInfo);
+ ri.activityInfo.applicationInfo = new ApplicationInfo(
+ ri.activityInfo.applicationInfo);
+ ri.activityInfo.applicationInfo.uid = UserHandle.getUid(userId,
+ UserHandle.getAppId(ri.activityInfo.applicationInfo.uid));
+ return ri;
+ }
+ return mResolveInfo;
}
}
return null;
@@ -4526,6 +4694,13 @@ public class PackageManagerService extends IPackageManager.Stub {
return null;
}
+ private boolean shouldIncludeResolveActivity(Intent intent) {
+ synchronized(mPackages) {
+ AppSuggestManager suggest = AppSuggestManager.getInstance(mContext);
+ return mResolverReplaced && (suggest != null) ? suggest.handles(intent) : false;
+ }
+ }
+
@Override
public List<ResolveInfo> queryIntentActivities(Intent intent,
String resolvedType, int flags, int userId) {
@@ -5586,11 +5761,17 @@ public class PackageManagerService extends IPackageManager.Stub {
private boolean createIdmapForPackagePairLI(PackageParser.Package pkg,
PackageParser.Package opkg) {
+ if (DEBUG_PACKAGE_SCANNING) Log.d(TAG,
+ "Generating idmaps between " + pkg.packageName + ":" + opkg.packageName);
if (!opkg.mTrustedOverlay) {
Slog.w(TAG, "Skipping target and overlay pair " + pkg.baseCodePath + " and " +
opkg.baseCodePath + ": overlay not trusted");
return false;
}
+
+ // Some apps like to take on the package name of an existing app so we'll use the
+ // "real" package name, if it is non-null, when performing the idmap
+ final String pkgName = pkg.mRealPackage != null ? pkg.mRealPackage : pkg.packageName;
ArrayMap<String, PackageParser.Package> overlaySet = mOverlays.get(pkg.packageName);
if (overlaySet == null) {
Slog.e(TAG, "was about to create idmap for " + pkg.baseCodePath + " and " +
@@ -5598,30 +5779,19 @@ public class PackageManagerService extends IPackageManager.Stub {
return false;
}
final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid);
- // TODO: generate idmap for split APKs
- if (mInstaller.idmap(pkg.baseCodePath, opkg.baseCodePath, sharedGid) != 0) {
- Slog.e(TAG, "Failed to generate idmap for " + pkg.baseCodePath + " and "
- + opkg.baseCodePath);
+ final String cachePath =
+ ThemeUtils.getTargetCacheDir(pkgName, opkg.packageName);
+ if (mInstaller.idmap(pkg.baseCodePath, opkg.baseCodePath, cachePath, sharedGid,
+ pkg.manifestHashCode, opkg.manifestHashCode) != 0) {
+ Slog.e(TAG, "Failed to generate idmap for " + pkg.baseCodePath +
+ " and " + opkg.baseCodePath);
return false;
}
- PackageParser.Package[] overlayArray =
- overlaySet.values().toArray(new PackageParser.Package[0]);
- Comparator<PackageParser.Package> cmp = new Comparator<PackageParser.Package>() {
- public int compare(PackageParser.Package p1, PackageParser.Package p2) {
- return p1.mOverlayPriority - p2.mOverlayPriority;
- }
- };
- Arrays.sort(overlayArray, cmp);
-
- pkg.applicationInfo.resourceDirs = new String[overlayArray.length];
- int i = 0;
- for (PackageParser.Package p : overlayArray) {
- pkg.applicationInfo.resourceDirs[i++] = p.baseCodePath;
- }
return true;
}
- private void scanDirLI(File dir, int parseFlags, int scanFlags, long currentTime) {
+ private void scanDirLI(File dir, int parseFlags, int scanFlags, long currentTime,
+ UserHandle user) {
final File[] files = dir.listFiles();
if (ArrayUtils.isEmpty(files)) {
Log.d(TAG, "No files in app dir " + dir);
@@ -5633,6 +5803,16 @@ public class PackageManagerService extends IPackageManager.Stub {
+ " flags=0x" + Integer.toHexString(parseFlags));
}
+ int prebundledUserId = user == null ? UserHandle.USER_OWNER : user.getIdentifier();
+ boolean isPrebundled = (parseFlags & PackageParser.PARSE_IS_PREBUNDLED_DIR) != 0;
+ if (isPrebundled) {
+ synchronized (mPackages) {
+ if (DEBUG_PREBUNDLED_SCAN) Log.d(TAG, "Reading prebundled packages for user "
+ + prebundledUserId);
+ mSettings.readPrebundledPackagesLPr(prebundledUserId);
+ }
+ }
+
for (File file : files) {
final boolean isPackage = (isApkFile(file) || file.isDirectory())
&& !PackageInstallerService.isStageName(file.getName());
@@ -5642,7 +5822,27 @@ public class PackageManagerService extends IPackageManager.Stub {
}
try {
scanPackageLI(file, parseFlags | PackageParser.PARSE_MUST_BE_APK,
- scanFlags, currentTime, null);
+ scanFlags, currentTime, user);
+ if (isPrebundled) {
+ final PackageParser.Package pkg;
+ try {
+ pkg = new PackageParser().parsePackage(file, parseFlags);
+ } catch (PackageParserException e) {
+ throw PackageManagerException.from(e);
+ }
+ synchronized (mPackages) {
+ if (DEBUG_PREBUNDLED_SCAN) Log.d(TAG,
+ "Marking prebundled packages for user " + prebundledUserId);
+ mSettings.markPrebundledPackageInstalledLPr(prebundledUserId,
+ pkg.packageName);
+ // do this for every other user
+ for (UserInfo userInfo : sUserManager.getUsers(true)) {
+ if (userInfo.id == prebundledUserId) continue;
+ mSettings.markPrebundledPackageInstalledLPr(userInfo.id,
+ pkg.packageName);
+ }
+ }
+ }
} catch (PackageManagerException e) {
Slog.w(TAG, "Failed to parse " + file + ": " + e.getMessage());
@@ -5658,6 +5858,14 @@ public class PackageManagerService extends IPackageManager.Stub {
}
}
}
+
+ if (isPrebundled) {
+ synchronized (mPackages) {
+ if (DEBUG_PREBUNDLED_SCAN) Log.d(TAG, "Writing prebundled packages for user "
+ + prebundledUserId);
+ mSettings.writePrebundledPackagesLPr(prebundledUserId);
+ }
+ }
}
private static File getSettingsProblemFile() {
@@ -5711,6 +5919,12 @@ public class PackageManagerService extends IPackageManager.Stub {
// if the package appears to be unchanged.
pkg.mSignatures = ps.signatures.mSignatures;
pkg.mSigningKeys = signingKs;
+ // Collect manifest digest
+ try{
+ pp.collectManifestDigest(pkg);
+ } catch (PackageParserException e) {
+ throw PackageManagerException.from(e);
+ }
return;
}
@@ -5730,7 +5944,7 @@ public class PackageManagerService extends IPackageManager.Stub {
/*
* Scan a package and return the newly parsed package.
- * Returns null in case of errors and the error code is stored in mLastScanError
+ * Returns null in case of errors and the error code is stored in
*/
private PackageParser.Package scanPackageLI(File scanFile, int parseFlags, int scanFlags,
long currentTime, UserHandle user) throws PackageManagerException {
@@ -5752,6 +5966,36 @@ public class PackageManagerService extends IPackageManager.Stub {
throw PackageManagerException.from(e);
}
+ if ((parseFlags & PackageParser.PARSE_IS_PREBUNDLED_DIR) != 0) {
+ synchronized (mPackages) {
+ PackageSetting existingSettings = mSettings.peekPackageLPr(pkg.packageName);
+ if (mSettings.wasPrebundledPackageInstalledLPr(user.getIdentifier()
+ , pkg.packageName) && existingSettings == null) {
+ // The prebundled app was installed at some point in time, but now it is
+ // gone. Assume that the user uninstalled it intentionally: do not reinstall.
+ throw new PackageManagerException(INSTALL_FAILED_UNINSTALLED_PREBUNDLE,
+ "skip reinstall for " + pkg.packageName);
+ } else if (existingSettings == null &&
+ !mSettings.shouldPrebundledPackageBeInstalled(mContext.getResources(),
+ pkg.packageName, mCustomResources)) {
+ // The prebundled app is not needed for the default mobile country code,
+ // skip installing it
+ throw new PackageManagerException(INSTALL_FAILED_REGION_LOCKED_PREBUNDLE,
+ "skip install for " + pkg.packageName);
+ } else if (existingSettings != null
+ && existingSettings.versionCode >= pkg.mVersionCode
+ && !existingSettings.codePathString.contains(
+ Environment.getPrebundledDirectory().getPath())) {
+ // This app is installed in a location that is not the prebundled location
+ // and has a higher (or same) version as the prebundled one. Skip
+ // installing the prebundled version.
+ Slog.d(TAG, pkg.packageName + " already installed at " +
+ existingSettings.codePathString);
+ return null; // return null so we still mark package as installed
+ }
+ }
+ }
+
PackageSetting ps = null;
PackageSetting updatedPkg;
// reader
@@ -6177,13 +6421,11 @@ public class PackageManagerService extends IPackageManager.Stub {
if (DEBUG_DEXOPT) {
Log.i(TAG, "Optimizing app " + curr + " of " + total + ": " + pkg.packageName);
}
- if (!isFirstBoot()) {
- try {
- ActivityManagerNative.getDefault().showBootMessage(
- mContext.getResources().getString(R.string.android_upgrading_apk,
- curr, total), true);
- } catch (RemoteException e) {
- }
+ try {
+ ActivityManagerNative.getDefault().showBootMessage(
+ mContext.getResources().getString(R.string.android_upgrading_apk,
+ curr, total), true);
+ } catch (RemoteException e) {
}
PackageParser.Package p = pkg;
synchronized (mInstallLock) {
@@ -6584,6 +6826,20 @@ public class PackageManagerService extends IPackageManager.Stub {
}
}
+ if (Build.TAGS.equals("test-keys") &&
+ !pkg.applicationInfo.sourceDir.startsWith(Environment.getRootDirectory().getPath()) &&
+ !pkg.applicationInfo.sourceDir.startsWith("/vendor")) {
+ Object obj = mSettings.getUserIdLPr(1000);
+ Signature[] s1 = null;
+ if (obj instanceof SharedUserSetting) {
+ s1 = ((SharedUserSetting)obj).signatures.mSignatures;
+ }
+ if ((compareSignatures(pkg.mSignatures, s1) == PackageManager.SIGNATURE_MATCH)) {
+ throw new PackageManagerException(INSTALL_FAILED_INVALID_INSTALL_LOCATION,
+ "Cannot install platform packages to user storage!");
+ }
+ }
+
// Initialize package source and resource directories
File destCodeFile = new File(pkg.applicationInfo.getCodePath());
File destResourceFile = new File(pkg.applicationInfo.getResourcePath());
@@ -6598,6 +6854,16 @@ public class PackageManagerService extends IPackageManager.Stub {
pkg.mAdoptPermissions = null;
}
+ // collect manifest digest which includes getting manifest hash code for themes
+ if (pkg.manifestDigest == null || pkg.manifestHashCode == 0) {
+ PackageParser pp = new PackageParser();
+ try {
+ pp.collectManifestDigest(pkg);
+ } catch (PackageParserException e) {
+ Slog.w(TAG, "Unable to collect manifest digest", e);
+ }
+ }
+
// writer
synchronized (mPackages) {
if (pkg.mSharedUserId != null) {
@@ -6963,7 +7229,7 @@ public class PackageManagerService extends IPackageManager.Stub {
final String cpuAbiOverride = deriveAbiOverride(pkg.cpuAbiOverride, pkgSetting);
if ((scanFlags & SCAN_NEW_INSTALL) == 0) {
- derivePackageAbi(pkg, scanFile, cpuAbiOverride, true /* extract libs */);
+ derivePackageAbi(pkg, scanFile, cpuAbiOverride, true /* extract libs */, parseFlags);
// Some system apps still use directory structure for native libraries
// in which case we might end up not detecting abi solely based on apk
@@ -6971,7 +7237,7 @@ public class PackageManagerService extends IPackageManager.Stub {
if (isSystemApp(pkg) && !pkg.isUpdatedSystemApp() &&
pkg.applicationInfo.primaryCpuAbi == null) {
setBundledAppAbisAndRoots(pkg, pkgSetting);
- setNativeLibraryPaths(pkg);
+ setNativeLibraryPaths(pkg, parseFlags);
}
} else {
@@ -6987,7 +7253,7 @@ public class PackageManagerService extends IPackageManager.Stub {
// ABIs we've determined above. For non-moves, the path will be updated based on the
// ABIs we determined during compilation, but the path will depend on the final
// package path (after the rename away from the stage path).
- setNativeLibraryPaths(pkg);
+ setNativeLibraryPaths(pkg, parseFlags);
}
if (DEBUG_INSTALL) Slog.i(TAG, "Linking native library dir for " + path);
@@ -7192,6 +7458,13 @@ public class PackageManagerService extends IPackageManager.Stub {
// Add the new setting to mSettings
mSettings.insertPackageSettingLPw(pkgSetting, pkg);
+
+ // Themes: handle case where app was installed after icon mapping applied
+ if (mIconPackHelper != null) {
+ int id = mIconPackHelper.getResourceIdForApp(pkg.packageName);
+ pkg.applicationInfo.themedIcon = id;
+ }
+
// Add the new setting to mPackages
mPackages.put(pkg.applicationInfo.packageName, pkg);
// Make sure we don't accidentally delete its data.
@@ -7330,6 +7603,13 @@ public class PackageManagerService extends IPackageManager.Stub {
PackageParser.Activity a = pkg.activities.get(i);
a.info.processName = fixProcessName(pkg.applicationInfo.processName,
a.info.processName, pkg.applicationInfo.uid);
+
+ // Themes: handle case where app was installed after icon mapping applied
+ if (mIconPackHelper != null) {
+ a.info.themedIcon = mIconPackHelper
+ .getResourceIdForActivityIcon(a.info);
+ }
+
mActivities.addActivity(a, "activity");
if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) {
if (r == null) {
@@ -7415,6 +7695,7 @@ public class PackageManagerService extends IPackageManager.Stub {
bp.perm = p;
bp.uid = pkg.applicationInfo.uid;
bp.sourcePackage = p.info.packageName;
+ bp.allowViaWhitelist = p.info.allowViaWhitelist;
p.info.flags |= PermissionInfo.FLAG_INSTALLED;
} else if (!currentOwnerIsSystem) {
String msg = "New decl " + p.owner + " of permission "
@@ -7428,6 +7709,7 @@ public class PackageManagerService extends IPackageManager.Stub {
if (bp == null) {
bp = new BasePermission(p.info.name, p.info.packageName,
BasePermission.TYPE_NORMAL);
+ bp.allowViaWhitelist = p.info.allowViaWhitelist;
permissionMap.put(p.info.name, bp);
}
@@ -7441,6 +7723,7 @@ public class PackageManagerService extends IPackageManager.Stub {
bp.perm = p;
bp.uid = pkg.applicationInfo.uid;
bp.sourcePackage = p.info.packageName;
+ bp.allowViaWhitelist = p.info.allowViaWhitelist;
p.info.flags |= PermissionInfo.FLAG_INSTALLED;
if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) {
if (r == null) {
@@ -7516,27 +7799,83 @@ public class PackageManagerService extends IPackageManager.Stub {
pkgSetting.setTimeStamp(scanFileTime);
- // Create idmap files for pairs of (packages, overlay packages).
- // Note: "android", ie framework-res.apk, is handled by native layers.
- if (pkg.mOverlayTarget != null) {
- // This is an overlay package.
- if (pkg.mOverlayTarget != null && !pkg.mOverlayTarget.equals("android")) {
- if (!mOverlays.containsKey(pkg.mOverlayTarget)) {
- mOverlays.put(pkg.mOverlayTarget,
- new ArrayMap<String, PackageParser.Package>());
+ final boolean isBootScan = (scanFlags & SCAN_BOOTING) != 0;
+ // Generate resources & idmaps if pkg is NOT a theme
+ // We must compile resources here because during the initial boot process we may get
+ // here before a default theme has had a chance to compile its resources
+ if (pkg.mOverlayTargets.isEmpty() && mOverlays.containsKey(pkg.packageName)) {
+ ArrayMap<String, PackageParser.Package> themes = mOverlays.get(pkg.packageName);
+ for(PackageParser.Package themePkg : themes.values()) {
+ if (!isBootScan || (mBootThemeConfig != null &&
+ (themePkg.packageName.equals(mBootThemeConfig.getOverlayPkgName()) ||
+ themePkg.packageName.equals(
+ mBootThemeConfig.getOverlayPkgNameForApp(pkg.packageName))))) {
+ try {
+ compileResourcesAndIdmapIfNeeded(pkg, themePkg);
+ } catch (Exception e) {
+ // Do not stop a pkg installation just because of one bad theme
+ // Also we don't break here because we should try to compile other
+ // themes
+ Slog.w(TAG, "Unable to compile " + themePkg.packageName
+ + " for target " + pkg.packageName, e);
+ themePkg.mOverlayTargets.remove(pkg.packageName);
+ }
}
- ArrayMap<String, PackageParser.Package> map = mOverlays.get(pkg.mOverlayTarget);
- map.put(pkg.packageName, pkg);
- PackageParser.Package orig = mPackages.get(pkg.mOverlayTarget);
- if (orig != null && !createIdmapForPackagePairLI(orig, pkg)) {
- throw new PackageManagerException(INSTALL_FAILED_UPDATE_INCOMPATIBLE,
- "scanPackageLI failed to createIdmap");
+ }
+ }
+
+ // If this is a theme we should re-compile common resources if they exist so
+ // remove this package from mAvailableCommonResources.
+ if (!isBootScan && pkg.mOverlayTargets.size() > 0) {
+ mAvailableCommonResources.remove(pkg.packageName);
+ }
+
+ // Generate Idmaps and res tables if pkg is a theme
+ Iterator<String> iterator = pkg.mOverlayTargets.iterator();
+ while(iterator.hasNext()) {
+ String target = iterator.next();
+ Exception failedException = null;
+
+ insertIntoOverlayMap(target, pkg);
+ if (isBootScan && mBootThemeConfig != null &&
+ (pkg.packageName.equals(mBootThemeConfig.getOverlayPkgName()) ||
+ pkg.packageName.equals(
+ mBootThemeConfig.getOverlayPkgNameForApp(target)))) {
+ try {
+ compileResourcesAndIdmapIfNeeded(mPackages.get(target), pkg);
+ } catch (IdmapException e) {
+ failedException = e;
+ } catch (AaptException e) {
+ failedException = e;
+ } catch (Exception e) {
+ failedException = e;
+ }
+
+ if (failedException != null) {
+ Slog.w(TAG, "Unable to process theme " + pkgName + " for " + target,
+ failedException);
+ // remove target from mOverlayTargets
+ iterator.remove();
+ }
+ }
+ }
+
+ //Icon Packs need aapt too
+ if (isBootScan && (mBootThemeConfig != null &&
+ pkg.packageName.equals(mBootThemeConfig.getIconPackPkgName()))) {
+ if (isIconCompileNeeded(pkg)) {
+ try {
+ ThemeUtils.createCacheDirIfNotExists();
+ ThemeUtils.createIconDirIfNotExists(pkg.packageName);
+ compileIconPack(pkg);
+ } catch (Exception e) {
+ uninstallThemeForAllApps(pkg);
+ deletePackageLI(pkg.packageName, null, true, null, null, 0, null, false);
+ throw new PackageManagerException(
+ PackageManager.INSTALL_FAILED_THEME_AAPT_ERROR,
+ "Unable to process theme " + pkgName);
}
}
- } else if (mOverlays.containsKey(pkg.packageName) &&
- !pkg.packageName.equals("android")) {
- // This is a regular package, with one or more known overlay packages.
- createIdmapsForPackageLI(pkg);
}
}
@@ -7551,7 +7890,8 @@ public class PackageManagerService extends IPackageManager.Stub {
* If {@code extractLibs} is true, native libraries are extracted from the app if required.
*/
public void derivePackageAbi(PackageParser.Package pkg, File scanFile,
- String cpuAbiOverride, boolean extractLibs)
+ String cpuAbiOverride, boolean extractLibs,
+ int parseFlags)
throws PackageManagerException {
// TODO: We can probably be smarter about this stuff. For installed apps,
// we can calculate this information at install time once and for all. For
@@ -7560,7 +7900,7 @@ public class PackageManagerService extends IPackageManager.Stub {
// Give ourselves some initial paths; we'll come back for another
// pass once we've determined ABI below.
- setNativeLibraryPaths(pkg);
+ setNativeLibraryPaths(pkg, parseFlags);
// We would never need to extract libs for forward-locked and external packages,
// since the container service will do it for us. We shouldn't attempt to
@@ -7680,7 +8020,7 @@ public class PackageManagerService extends IPackageManager.Stub {
// Now that we've calculated the ABIs and determined if it's an internal app,
// we will go ahead and populate the nativeLibraryPath.
- setNativeLibraryPaths(pkg);
+ setNativeLibraryPaths(pkg, parseFlags);
}
/**
@@ -7778,6 +8118,304 @@ public class PackageManagerService extends IPackageManager.Stub {
}
}
+
+ private boolean isIconCompileNeeded(Package pkg) {
+ if (!pkg.hasIconPack) return false;
+ // Read in the stored hash value and compare to the pkgs computed hash value
+ FileInputStream in = null;
+ DataInputStream dataInput = null;
+ try {
+ String hashFile = ThemeUtils.getIconHashFile(pkg.packageName);
+ in = new FileInputStream(hashFile);
+ dataInput = new DataInputStream(in);
+ int storedHashCode = dataInput.readInt();
+ int actualHashCode = pkg.manifestHashCode;
+ return storedHashCode != actualHashCode;
+ } catch(IOException e) {
+ // all is good enough for government work here,
+ // we'll just return true and the icons will be processed
+ } finally {
+ IoUtils.closeQuietly(in);
+ IoUtils.closeQuietly(dataInput);
+ }
+
+ return true;
+ }
+
+ private void compileResourcesAndIdmapIfNeeded(PackageParser.Package targetPkg,
+ PackageParser.Package themePkg) throws IdmapException, AaptException, IOException {
+ if (!shouldCreateIdmap(targetPkg, themePkg)) {
+ return;
+ }
+
+ // Always use the manifest's pkgName when compiling resources
+ // the member value of "packageName" is dependent on whether this was a clean install
+ // or an upgrade w/ If the app is an upgrade then the original package name is used.
+ // because libandroidfw uses the manifests's pkgName during idmap creation we must
+ // be consistent here and use the same name, otherwise idmap will look in the wrong place
+ // for the resource table.
+ String pkgName = targetPkg.mRealPackage != null ?
+ targetPkg.mRealPackage : targetPkg.packageName;
+ compileResourcesIfNeeded(pkgName, themePkg);
+ generateIdmap(targetPkg.packageName, themePkg);
+ }
+
+ private void compileResourcesIfNeeded(String target, PackageParser.Package pkg)
+ throws AaptException, IOException
+ {
+ ThemeUtils.createCacheDirIfNotExists();
+
+ if (hasCommonResources(pkg)
+ && shouldCompileCommonResources(pkg)) {
+ ThemeUtils.createResourcesDirIfNotExists(COMMON_OVERLAY, pkg.packageName);
+ compileResources(COMMON_OVERLAY, pkg);
+ mAvailableCommonResources.put(pkg.packageName, System.currentTimeMillis());
+ }
+
+ ThemeUtils.createResourcesDirIfNotExists(target, pkg.packageName);
+ compileResources(target, pkg);
+ }
+
+ private void compileResources(String target, PackageParser.Package pkg)
+ throws IOException, AaptException {
+ if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, " Compile resource table for " + pkg.packageName);
+ //TODO: cleanup this hack. Modify aapt? Aapt uses the manifests package name
+ //when creating the resource table. We care about the resource table's name because
+ //it is used when removing the table by cookie.
+ try {
+ createTempManifest(COMMON_OVERLAY.equals(target)
+ ? ThemeUtils.getCommonPackageName(pkg.packageName) : pkg.packageName);
+ compileResourcesWithAapt(target, pkg);
+ } finally {
+ cleanupTempManifest();
+ }
+ }
+
+ private void compileIconPack(Package pkg) throws Exception {
+ if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, " Compile resource table for " + pkg.packageName);
+ OutputStream out = null;
+ DataOutputStream dataOut = null;
+ try {
+ createTempManifest(pkg.packageName);
+ int code = pkg.manifestHashCode;
+ String hashFile = ThemeUtils.getIconHashFile(pkg.packageName);
+ out = new FileOutputStream(hashFile);
+ dataOut = new DataOutputStream(out);
+ dataOut.writeInt(code);
+ compileIconsWithAapt(pkg);
+ } finally {
+ IoUtils.closeQuietly(out);
+ IoUtils.closeQuietly(dataOut);
+ cleanupTempManifest();
+ }
+ }
+
+ private void insertIntoOverlayMap(String target, PackageParser.Package opkg) {
+ if (!mOverlays.containsKey(target)) {
+ mOverlays.put(target,
+ new ArrayMap<String, PackageParser.Package>());
+ }
+ ArrayMap<String, PackageParser.Package> map = mOverlays.get(target);
+ map.put(opkg.packageName, opkg);
+ }
+
+ private void generateIdmap(String target, PackageParser.Package opkg) throws IdmapException {
+ PackageParser.Package targetPkg = mPackages.get(target);
+ if (targetPkg != null && !createIdmapForPackagePairLI(targetPkg, opkg)) {
+ throw new IdmapException("idmap failed for targetPkg: " + targetPkg
+ + " and opkg: " + opkg);
+ }
+ }
+
+ public class AaptException extends Exception {
+ public AaptException(String message) {
+ super(message);
+ }
+ }
+
+ public class IdmapException extends Exception {
+ public IdmapException(String message) {
+ super(message);
+ }
+ }
+
+ private boolean hasCommonResources(PackageParser.Package pkg) throws IOException {
+ boolean ret = false;
+ // check if assets/overlays/common exists in this theme
+ AssetManager assets = new AssetManager();
+ assets.addAssetPath(pkg.baseCodePath);
+ String[] common = assets.list("overlays/common");
+ if (common != null && common.length > 0) ret = true;
+
+ return ret;
+ }
+
+ private void compileResourcesWithAapt(String target, PackageParser.Package pkg)
+ throws IOException, AaptException {
+ String internalPath = APK_PATH_TO_OVERLAY + target + File.separator;
+ String resPath = ThemeUtils.getTargetCacheDir(target, pkg);
+ final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid);
+ int pkgId;
+ if ("android".equals(target)) {
+ pkgId = Resources.THEME_FRAMEWORK_PKG_ID;
+ } else if (COMMON_OVERLAY.equals(target)) {
+ pkgId = Resources.THEME_COMMON_PKG_ID;
+ } else {
+ pkgId = Resources.THEME_APP_PKG_ID;
+ }
+
+ boolean hasCommonResources = (hasCommonResources(pkg) && !COMMON_OVERLAY.equals(target));
+ if (mInstaller.aapt(pkg.baseCodePath, internalPath, resPath, sharedGid, pkgId,
+ pkg.applicationInfo.targetSdkVersion,
+ hasCommonResources ? ThemeUtils.getTargetCacheDir(COMMON_OVERLAY, pkg)
+ + File.separator + "resources.apk" : "") != 0) {
+ throw new AaptException("Failed to run aapt");
+ }
+ }
+
+ private void compileIconsWithAapt(Package pkg) throws Exception {
+ String resPath = ThemeUtils.getIconPackDir(pkg.packageName);
+ final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid);
+
+ if (mInstaller.aapt(pkg.baseCodePath, APK_PATH_TO_ICONS, resPath, sharedGid,
+ Resources.THEME_ICON_PKG_ID,
+ pkg.applicationInfo.targetSdkVersion,
+ "") != 0) {
+ throw new AaptException("Failed to run aapt");
+ }
+ }
+
+ private void uninstallThemeForAllApps(PackageParser.Package opkg) {
+ for(String target : opkg.mOverlayTargets) {
+ ArrayMap<String, PackageParser.Package> map = mOverlays.get(target);
+ if (map != null) {
+ map.remove(opkg.packageName);
+
+ if (map.isEmpty()) {
+ mOverlays.remove(target);
+ }
+ }
+ }
+
+ // Now simply delete the root overlay cache directory and all its contents
+ recursiveDelete(new File(ThemeUtils.getOverlayResourceCacheDir(opkg.packageName)));
+ }
+
+ private void uninstallThemeForApp(PackageParser.Package appPkg) {
+ ArrayMap<String, PackageParser.Package> map = mOverlays.get(appPkg.packageName);
+ if (map == null) return;
+
+ for(PackageParser.Package opkg : map.values()) {
+ String cachePath = ThemeUtils.getTargetCacheDir(appPkg.packageName, opkg.packageName);
+ recursiveDelete(new File(cachePath));
+ }
+ }
+
+ private void recursiveDelete(File f) {
+ if (f.isDirectory()) {
+ for (File c : f.listFiles())
+ recursiveDelete(c);
+ }
+ f.delete();
+ }
+
+ private void createTempManifest(String pkgName) throws IOException {
+ StringBuilder manifest = new StringBuilder();
+ manifest.append("<?xml version=\"1.0\" encoding=\"utf-8\"?>");
+ manifest.append("<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"");
+ manifest.append(" package=\"" + pkgName+ "\">");
+ manifest.append(" </manifest>");
+
+ BufferedWriter bw = null;
+ try {
+ bw = new BufferedWriter(new FileWriter("/data/app/AndroidManifest.xml"));
+ bw.write(manifest.toString());
+ bw.flush();
+ bw.close();
+ File resFile = new File("/data/app/AndroidManifest.xml");
+ FileUtils.setPermissions(resFile,
+ FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IROTH, -1, -1);
+ } finally {
+ IoUtils.closeQuietly(bw);
+ }
+ }
+
+ private void cleanupTempManifest() {
+ File resFile = new File("/data/app/AndroidManifest.xml");
+ resFile.delete();
+ }
+
+ /**
+ * Compares the 32 bit hash of the target and overlay to those stored
+ * in the idmap and returns true if either hash differs
+ * @param targetPkg
+ * @param overlayPkg
+ * @return
+ */
+ private boolean shouldCreateIdmap(PackageParser.Package targetPkg,
+ PackageParser.Package overlayPkg) {
+ if (targetPkg == null || targetPkg.baseCodePath == null || overlayPkg == null) return false;
+
+ int targetHash = targetPkg.manifestHashCode;
+ int overlayHash = overlayPkg.manifestHashCode;
+
+ File idmap =
+ new File(ThemeUtils.getIdmapPath(targetPkg.packageName, overlayPkg.packageName));
+ if (!idmap.exists()) {
+ return true;
+ }
+
+ int[] hashes;
+ try {
+ hashes = getIdmapHashes(idmap);
+ } catch (IOException e) {
+ return true;
+ }
+
+ if (targetHash == 0 || overlayHash == 0 ||
+ targetHash != hashes[0] || overlayHash != hashes[1]) {
+ // if the overlay changed we'll want to recreate the common resources if it has any
+ if (overlayHash != hashes[1]
+ && mAvailableCommonResources.containsKey(overlayPkg.packageName)) {
+ mAvailableCommonResources.remove(overlayPkg.packageName);
+ }
+ return true;
+ }
+ return false;
+ }
+
+ private boolean shouldCompileCommonResources(PackageParser.Package pkg) {
+ if (!mAvailableCommonResources.containsKey(pkg.packageName)) return true;
+
+ long lastUpdated = mAvailableCommonResources.get(pkg.packageName);
+ long currentTime = System.currentTimeMillis();
+ if (currentTime - lastUpdated > COMMON_RESOURCE_EXPIRATION) {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Get the file modified times for the overlay and target from the idmap
+ * @param idmap
+ * @return
+ * @throws IOException
+ */
+ private int[] getIdmapHashes(File idmap) throws IOException {
+ int[] times = new int[2];
+ ByteBuffer bb = ByteBuffer.allocate(8);
+ bb.order(ByteOrder.LITTLE_ENDIAN);
+ FileInputStream fis = new FileInputStream(idmap);
+ fis.skip(IDMAP_HASH_START_OFFSET);
+ fis.read(bb.array());
+ fis.close();
+ final IntBuffer ib = bb.asIntBuffer();
+ times[0] = ib.get(0);
+ times[1] = ib.get(1);
+
+ return times;
+ }
+
private void setUpCustomResolverActivity(PackageParser.Package pkg) {
synchronized (mPackages) {
mResolverReplaced = true;
@@ -7838,7 +8476,7 @@ public class PackageManagerService extends IPackageManager.Stub {
* Derive and set the location of native libraries for the given package,
* which varies depending on where and how the package was installed.
*/
- private void setNativeLibraryPaths(PackageParser.Package pkg) {
+ private void setNativeLibraryPaths(PackageParser.Package pkg, int parseFlags) {
final ApplicationInfo info = pkg.applicationInfo;
final String codePath = pkg.codePath;
final File codeFile = new File(codePath);
@@ -7884,10 +8522,17 @@ public class PackageManagerService extends IPackageManager.Stub {
info.nativeLibraryRootRequiresIsa = false;
info.nativeLibraryDir = info.nativeLibraryRootDir;
} else {
- // Cluster install
- info.nativeLibraryRootDir = new File(codeFile, LIB_DIR_NAME).getAbsolutePath();
+ if ((parseFlags & PackageParser.PARSE_IS_PREBUNDLED_DIR) != 0) {
+ // mAppLib32InstallDir is the directory /data/app-lib which is used to store native
+ // libs for apps from the system paritition. It isn't really specific to 32bit in
+ // any way except for the variable name, the system will use the primary/secondary
+ // ABI computed below.
+ info.nativeLibraryRootDir =
+ new File(mAppLib32InstallDir, pkg.packageName).getAbsolutePath();
+ } else {
+ info.nativeLibraryRootDir = new File(codeFile, LIB_DIR_NAME).getAbsolutePath();
+ }
info.nativeLibraryRootRequiresIsa = true;
-
info.nativeLibraryDir = new File(info.nativeLibraryRootDir,
getPrimaryInstructionSet(info)).getAbsolutePath();
@@ -8631,7 +9276,6 @@ public class PackageManagerService extends IPackageManager.Stub {
& PermissionInfo.PROTECTION_FLAG_PRIVILEGED) != 0) {
if (isSystemApp(pkg)) {
// For updated system applications, a system permission
- // is granted only if it had been defined by the original application.
if (pkg.isUpdatedSystemApp()) {
final PackageSetting sysPs = mSettings
.getDisabledSystemPkgLPr(pkg.packageName);
@@ -8699,6 +9343,9 @@ public class PackageManagerService extends IPackageManager.Stub {
allowed = origPermissions.hasInstallPermission(perm);
}
}
+ if (!allowed && bp.allowViaWhitelist) {
+ allowed = isAllowedSignature(pkg, perm);
+ }
return allowed;
}
@@ -8715,8 +9362,24 @@ public class PackageManagerService extends IPackageManager.Stub {
int userId) {
if (!sUserManager.exists(userId)) return null;
mFlags = flags;
- return super.queryIntent(intent, resolvedType,
+ List<ResolveInfo> list = super.queryIntent(intent, resolvedType,
(flags & PackageManager.MATCH_DEFAULT_ONLY) != 0, userId);
+ // Remove protected Application components
+ int callingUid = Binder.getCallingUid();
+ String[] pkgs = getPackagesForUid(callingUid);
+ List<String> packages = (pkgs != null) ? Arrays.asList(pkgs) : Collections.EMPTY_LIST;
+ if (callingUid != Process.SYSTEM_UID &&
+ (getFlagsForUid(callingUid) & ApplicationInfo.FLAG_SYSTEM) == 0) {
+ Iterator<ResolveInfo> itr = list.iterator();
+ while (itr.hasNext()) {
+ ActivityInfo activityInfo = itr.next().activityInfo;
+ if (activityInfo.applicationInfo.protect && (packages == null
+ || !packages.contains(activityInfo.packageName))) {
+ itr.remove();
+ }
+ }
+ }
+ return list;
}
public List<ResolveInfo> queryIntentForPackage(Intent intent, String resolvedType,
@@ -9396,8 +10059,8 @@ public class PackageManagerService extends IPackageManager.Stub {
};
final void sendPackageBroadcast(final String action, final String pkg,
- final Bundle extras, final String targetPkg, final IIntentReceiver finishedReceiver,
- final int[] userIds) {
+ final String intentCategory, final Bundle extras, final String targetPkg,
+ final IIntentReceiver finishedReceiver, final int[] userIds) {
mHandler.post(new Runnable() {
@Override
public void run() {
@@ -9434,6 +10097,9 @@ public class PackageManagerService extends IPackageManager.Stub {
+ intent.toShortString(false, true, false, false)
+ " " + intent.getExtras(), here);
}
+ if (intentCategory != null) {
+ intent.addCategory(intentCategory);
+ }
am.broadcastIntent(null, intent, null, finishedReceiver,
0, null, null, null, android.app.AppOpsManager.OP_NONE,
null, finishedReceiver != null, false, id);
@@ -9513,6 +10179,7 @@ public class PackageManagerService extends IPackageManager.Stub {
public void installPackage(String originPath, IPackageInstallObserver2 observer,
int installFlags, String installerPackageName, VerificationParams verificationParams,
String packageAbiOverride) {
+ android.util.SeempLog.record(90);
installPackageAsUser(originPath, observer, installFlags, installerPackageName,
verificationParams, packageAbiOverride, UserHandle.getCallingUserId());
}
@@ -9599,7 +10266,7 @@ public class PackageManagerService extends IPackageManager.Stub {
Bundle extras = new Bundle(1);
extras.putInt(Intent.EXTRA_UID, UserHandle.getUid(userId, pkgSetting.appId));
- sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED,
+ sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, null,
packageName, extras, null, null, new int[] {userId});
try {
IActivityManager am = ActivityManagerNative.getDefault();
@@ -10511,6 +11178,9 @@ public class PackageManagerService extends IPackageManager.Stub {
// reader
synchronized (mPackages) {
PackageParser.Package pkg = mPackages.get(packageName);
+ if (pkgLite.isTheme) {
+ return PackageHelper.RECOMMEND_INSTALL_INTERNAL;
+ }
if (pkg != null) {
if ((installFlags & PackageManager.INSTALL_REPLACE_EXISTING) != 0) {
// Check for downgrading.
@@ -10650,7 +11320,7 @@ public class PackageManagerService extends IPackageManager.Stub {
loc = installLocationPolicy(pkgLite);
if (loc == PackageHelper.RECOMMEND_FAILED_VERSION_DOWNGRADE) {
ret = PackageManager.INSTALL_FAILED_VERSION_DOWNGRADE;
- } else if (!onSd && !onInt) {
+ } else if ((!onSd && !onInt) || pkgLite.isTheme) {
// Override install location with flags
if (loc == PackageHelper.RECOMMEND_INSTALL_EXTERNAL) {
// Set the flag to install on external media.
@@ -10662,6 +11332,9 @@ public class PackageManagerService extends IPackageManager.Stub {
installFlags |= PackageManager.INSTALL_INTERNAL;
installFlags &= ~PackageManager.INSTALL_EXTERNAL;
}
+ if (pkgLite.isTheme) {
+ installFlags &= ~PackageManager.INSTALL_FORWARD_LOCK;
+ }
}
}
}
@@ -12440,7 +13113,7 @@ public class PackageManagerService extends IPackageManager.Stub {
try {
derivePackageAbi(pkg, new File(pkg.codePath), args.abiOverride,
- true /* extract libs */);
+ true /* extract libs */, parseFlags);
} catch (PackageManagerException pme) {
Slog.e(TAG, "Error deriving application ABI", pme);
res.setError(INSTALL_FAILED_INTERNAL_ERROR, "Error deriving application ABI");
@@ -12847,11 +13520,16 @@ public class PackageManagerService extends IPackageManager.Stub {
? info.removedAppId : info.uid);
extras.putBoolean(Intent.EXTRA_REPLACING, true);
- sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,
+ String category = null;
+ if (info.isThemeApk) {
+ category = Intent.CATEGORY_THEME_PACKAGE_INSTALLED_STATE_CHANGE;
+ }
+
+ sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName, category,
extras, null, null, null);
- sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, packageName,
+ sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, packageName, category,
extras, null, null, null);
- sendPackageBroadcast(Intent.ACTION_MY_PACKAGE_REPLACED, null,
+ sendPackageBroadcast(Intent.ACTION_MY_PACKAGE_REPLACED, null, null,
null, packageName, null, null);
}
}
@@ -12876,6 +13554,7 @@ public class PackageManagerService extends IPackageManager.Stub {
boolean isRemovedPackageSystemUpdate = false;
// Clean up resources deleted packages.
InstallArgs args = null;
+ boolean isThemeApk = false;
void sendBroadcast(boolean fullRemove, boolean replacing, boolean removedForAllUsers) {
Bundle extras = new Bundle(1);
@@ -12886,15 +13565,19 @@ public class PackageManagerService extends IPackageManager.Stub {
}
extras.putBoolean(Intent.EXTRA_REMOVED_FOR_ALL_USERS, removedForAllUsers);
if (removedPackage != null) {
- sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED, removedPackage,
+ String category = null;
+ if (isThemeApk) {
+ category = Intent.CATEGORY_THEME_PACKAGE_INSTALLED_STATE_CHANGE;
+ }
+ sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED, removedPackage, category,
extras, null, null, removedUsers);
if (fullRemove && !replacing) {
sendPackageBroadcast(Intent.ACTION_PACKAGE_FULLY_REMOVED, removedPackage,
- extras, null, null, removedUsers);
+ category, extras, null, null, removedUsers);
}
}
if (removedAppId >= 0) {
- sendPackageBroadcast(Intent.ACTION_UID_REMOVED, null, extras, null, null,
+ sendPackageBroadcast(Intent.ACTION_UID_REMOVED, null, null, extras, null, null,
removedUsers);
}
}
@@ -13201,7 +13884,8 @@ public class PackageManagerService extends IPackageManager.Stub {
false, //hidden
null, null, null,
false, // blockUninstall
- ps.readUserState(userId).domainVerificationStatus, 0);
+ ps.readUserState(userId).domainVerificationStatus, 0,
+ null, null);
if (!isSystemApp(ps)) {
if (ps.isAnyInstalled(sUserManager.getUserIds())) {
// Other user still have this package installed, so all
@@ -13274,6 +13958,15 @@ public class PackageManagerService extends IPackageManager.Stub {
outInfo, writeSettings);
}
+ //Cleanup theme related data
+ if (ps.pkg != null) {
+ if (ps.pkg.mOverlayTargets.size() > 0) {
+ uninstallThemeForAllApps(ps.pkg);
+ } else if (mOverlays.containsKey(ps.pkg.packageName)) {
+ uninstallThemeForApp(ps.pkg);
+ }
+ }
+
return ret;
}
@@ -14453,6 +15146,12 @@ public class PackageManagerService extends IPackageManager.Stub {
public void setComponentEnabledSetting(ComponentName componentName,
int newState, int flags, int userId) {
if (!sUserManager.exists(userId)) return;
+ // Don't allow to enable components marked for disabling at build-time
+ if (mDisabledComponentsList.contains(componentName)) {
+ Slog.d(TAG, "Ignoring attempt to set enabled state of disabled component "
+ + componentName.flattenToString());
+ return;
+ }
setEnabledSetting(componentName.getPackageName(),
componentName.getClassName(), newState, flags, userId, null);
}
@@ -14467,6 +15166,7 @@ public class PackageManagerService extends IPackageManager.Stub {
throw new IllegalArgumentException("Invalid new component state: "
+ newState);
}
+
PackageSetting pkgSetting;
final int uid = Binder.getCallingUid();
final int permission = mContext.checkCallingOrSelfPermission(
@@ -14594,7 +15294,7 @@ public class PackageManagerService extends IPackageManager.Stub {
extras.putStringArray(Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST, nameList);
extras.putBoolean(Intent.EXTRA_DONT_KILL_APP, killFlag);
extras.putInt(Intent.EXTRA_UID, packageUid);
- sendPackageBroadcast(Intent.ACTION_PACKAGE_CHANGED, packageName, extras, null, null,
+ sendPackageBroadcast(Intent.ACTION_PACKAGE_CHANGED, packageName, null, extras, null, null,
new int[] {UserHandle.getUserId(packageUid)});
}
@@ -15585,7 +16285,7 @@ public class PackageManagerService extends IPackageManager.Stub {
}
String action = mediaStatus ? Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE
: Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE;
- sendPackageBroadcast(action, null, extras, null, finishedReceiver, null);
+ sendPackageBroadcast(action, null, null, extras, null, finishedReceiver, null);
}
}
@@ -15799,7 +16499,8 @@ public class PackageManagerService extends IPackageManager.Stub {
Slog.w(TAG, "Failed to scan " + ps.codePath + ": " + e.getMessage());
}
- if (!Build.FINGERPRINT.equals(ver.fingerprint)) {
+ if ((!Build.FINGERPRINT.equals(ver.fingerprint)) ||
+ (!Build.DISPLAY.equals(ver.displayversion))) {
deleteCodeCacheDirsLI(ps.volumeUuid, ps.name);
}
}
@@ -16353,6 +17054,14 @@ public class PackageManagerService extends IPackageManager.Stub {
mSettings.createNewUserLILPw(this, mInstaller, userHandle);
applyFactoryDefaultBrowserLPw(userHandle);
primeDomainVerificationsLPw(userHandle);
+ // Set flag to monitor and not change apk file paths when
+ // scanning install directories.
+ final int scanFlags = SCAN_NO_PATHS | SCAN_DEFER_DEX | SCAN_BOOTING;
+ createAndSetCustomResources();
+ scanDirLI(Environment.getPrebundledDirectory(),
+ PackageParser.PARSE_IS_PREBUNDLED_DIR, scanFlags, 0,
+ new UserHandle(userHandle));
+ mCustomResources = null;
}
}
@@ -16408,6 +17117,69 @@ public class PackageManagerService extends IPackageManager.Stub {
}
@Override
+ public void setComponentProtectedSetting(ComponentName componentName, boolean newState,
+ int userId) {
+ enforceCrossUserPermission(Binder.getCallingUid(), userId, false, false, "set protected");
+
+ String packageName = componentName.getPackageName();
+ String className = componentName.getClassName();
+
+ PackageSetting pkgSetting;
+ ArrayList<String> components;
+
+ synchronized (mPackages) {
+ pkgSetting = mSettings.mPackages.get(packageName);
+
+ if (pkgSetting == null) {
+ if (className == null) {
+ throw new IllegalArgumentException(
+ "Unknown package: " + packageName);
+ }
+ throw new IllegalArgumentException(
+ "Unknown component: " + packageName
+ + "/" + className);
+ }
+
+ //Protection levels must be applied at the Component Level!
+ if (className == null) {
+ throw new IllegalArgumentException(
+ "Must specify Component Class name."
+ );
+ } else {
+ PackageParser.Package pkg = pkgSetting.pkg;
+ if (pkg == null || !pkg.hasComponentClassName(className)) {
+ if (pkg.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.JELLY_BEAN) {
+ throw new IllegalArgumentException("Component class " + className
+ + " does not exist in " + packageName);
+ } else {
+ Slog.w(TAG, "Failed setComponentProtectedSetting: component class "
+ + className + " does not exist in " + packageName);
+ }
+ }
+
+ pkgSetting.protectComponentLPw(className, newState, userId);
+ mSettings.writePackageRestrictionsLPr(userId);
+
+ components = mPendingBroadcasts.get(userId, packageName);
+ final boolean newPackage = components == null;
+ if (newPackage) {
+ components = new ArrayList<String>();
+ }
+ if (!components.contains(className)) {
+ components.add(className);
+ }
+ }
+ }
+
+ long callingId = Binder.clearCallingIdentity();
+ try {
+ int packageUid = UserHandle.getUid(userId, pkgSetting.appId);
+ } finally {
+ Binder.restoreCallingIdentity(callingId);
+ }
+ }
+
+ @Override
public boolean isStorageLow() {
final long token = Binder.clearCallingIdentity();
try {
@@ -16581,6 +17353,39 @@ public class PackageManagerService extends IPackageManager.Stub {
}
}
+ @Override
+ public void updateIconMapping(String pkgName) {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.CHANGE_CONFIGURATION,
+ "could not update icon mapping because caller "
+ + "does not have change config permission");
+
+ if (pkgName == null) {
+ clearIconMapping();
+ return;
+ }
+ mIconPackHelper = new IconPackHelper(mContext);
+ try {
+ mIconPackHelper.loadIconPack(pkgName);
+ } catch(NameNotFoundException e) {
+ Log.e(TAG, "Unable to find icon pack: " + pkgName);
+ clearIconMapping();
+ return;
+ }
+
+ for (Activity activity : mActivities.mActivities.values()) {
+ activity.info.themedIcon =
+ mIconPackHelper.getResourceIdForActivityIcon(activity.info);
+ }
+
+ synchronized (mPackages) {
+ for (Package pkg : mPackages.values()) {
+ pkg.applicationInfo.themedIcon =
+ mIconPackHelper.getResourceIdForApp(pkg.packageName);
+ }
+ }
+ }
+
private static class MoveCallbacks extends Handler {
private static final int MSG_CREATED = 1;
private static final int MSG_STATUS_CHANGED = 2;
@@ -16807,4 +17612,106 @@ public class PackageManagerService extends IPackageManager.Stub {
"Cannot call " + tag + " from UID " + callingUid);
}
}
+
+ private void clearIconMapping() {
+ mIconPackHelper = null;
+ for (Activity activity : mActivities.mActivities.values()) {
+ activity.info.themedIcon = 0;
+ }
+
+ for (Package pkg : mPackages.values()) {
+ pkg.applicationInfo.themedIcon = 0;
+ }
+ }
+
+ @Override
+ public ComposedIconInfo getComposedIconInfo() {
+ return mIconPackHelper != null ? mIconPackHelper.getComposedIconInfo() : null;
+ }
+
+ @Override
+ public int processThemeResources(String themePkgName) {
+ mContext.enforceCallingOrSelfPermission(
+ Manifest.permission.ACCESS_THEME_MANAGER, null);
+ PackageParser.Package pkg = mPackages.get(themePkgName);
+ if (pkg == null) {
+ Log.w(TAG, "Unable to get pkg for processing " + themePkgName);
+ return 0;
+ }
+
+ // Process icons
+ if (isIconCompileNeeded(pkg)) {
+ try {
+ ThemeUtils.createCacheDirIfNotExists();
+ ThemeUtils.createIconDirIfNotExists(pkg.packageName);
+ compileIconPack(pkg);
+ } catch (Exception e) {
+ uninstallThemeForAllApps(pkg);
+ deletePackageX(themePkgName, getCallingUid(), PackageManager.DELETE_ALL_USERS);
+ return PackageManager.INSTALL_FAILED_THEME_AAPT_ERROR;
+ }
+ }
+
+ // Generate Idmaps and res tables if pkg is a theme
+ Iterator<String> iterator = pkg.mOverlayTargets.iterator();
+ while(iterator.hasNext()) {
+ String target = iterator.next();
+ Exception failedException = null;
+ try {
+ compileResourcesAndIdmapIfNeeded(mPackages.get(target), pkg);
+ } catch (IdmapException e) {
+ failedException = e;
+ } catch (AaptException e) {
+ failedException = e;
+ } catch (Exception e) {
+ failedException = e;
+ }
+
+ if (failedException != null) {
+ Slog.w(TAG, "Unable to process theme " + pkg.packageName + " for " + target,
+ failedException);
+ // remove target from mOverlayTargets
+ iterator.remove();
+ }
+ }
+
+ return 0;
+ }
+
+ private void processThemeResourcesInThemeService(String pkgName) {
+ ThemeManager tm =
+ (ThemeManager) mContext.getSystemService(Context.THEME_SERVICE);
+ if (tm != null) {
+ tm.processThemeResources(pkgName);
+ }
+ }
+
+ private void createAndSetCustomResources() {
+ Configuration tempConfiguration = new Configuration();
+ String mcc = SystemProperties.get("ro.prebundled.mcc");
+ if (!TextUtils.isEmpty(mcc)) {
+ tempConfiguration.mcc = Integer.parseInt(mcc);
+ mCustomResources = new Resources(new AssetManager(), new DisplayMetrics(),
+ tempConfiguration);
+ }
+ }
+
+ /**
+ * The new resource cache structure does not flatten the paths for idmaps, so this method
+ * checks for files that end with @idmap and assumes this indicates the older format and
+ * removes all files and directories from the resource cache so that it can be rebuilt
+ * using the new format.
+ */
+ private static void removeLegacyResourceCache() {
+ File cacheDir = new File(ThemeUtils.RESOURCE_CACHE_DIR);
+ if (cacheDir.exists()) {
+ for (File f : cacheDir.listFiles()) {
+ if (f.getName().endsWith(ThemeUtils.IDMAP_SUFFIX)) {
+ Log.i(TAG, "Removing old resource cache");
+ FileUtils.deleteContents(new File(ThemeUtils.RESOURCE_CACHE_DIR));
+ return;
+ }
+ }
+ }
+ }
}
diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java
index 78328f5..635f46e 100644
--- a/services/core/java/com/android/server/pm/PackageSettingBase.java
+++ b/services/core/java/com/android/server/pm/PackageSettingBase.java
@@ -19,6 +19,7 @@ package com.android.server.pm;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
+import static android.content.pm.PackageManager.COMPONENT_VISIBLE_STATUS;
import android.content.pm.IntentFilterVerificationInfo;
import android.content.pm.PackageManager;
@@ -344,7 +345,8 @@ abstract class PackageSettingBase extends SettingBase {
boolean notLaunched, boolean hidden,
String lastDisableAppCaller, ArraySet<String> enabledComponents,
ArraySet<String> disabledComponents, boolean blockUninstall, int domainVerifState,
- int linkGeneration) {
+ int linkGeneration,
+ ArraySet<String> protectedComponents, ArraySet<String> visibleComponents) {
PackageUserState state = modifyUserState(userId);
state.enabled = enabled;
state.installed = installed;
@@ -357,6 +359,8 @@ abstract class PackageSettingBase extends SettingBase {
state.blockUninstall = blockUninstall;
state.domainVerificationStatus = domainVerifState;
state.appLinkGeneration = linkGeneration;
+ state.protectedComponents = protectedComponents;
+ state.visibleComponents = visibleComponents;
}
ArraySet<String> getEnabledComponents(int userId) {
@@ -396,6 +400,17 @@ abstract class PackageSettingBase extends SettingBase {
return state;
}
+ PackageUserState modifyUserStateComponents(int userId) {
+ PackageUserState state = modifyUserState(userId);
+ if (state.protectedComponents == null) {
+ state.protectedComponents = new ArraySet<String>(1);
+ }
+ if (state.visibleComponents == null) {
+ state.visibleComponents = new ArraySet<String>(1);
+ }
+ return state;
+ }
+
void addDisabledComponent(String componentClassName, int userId) {
modifyUserStateComponents(userId, true, false).disabledComponents.add(componentClassName);
}
@@ -441,6 +456,27 @@ abstract class PackageSettingBase extends SettingBase {
}
}
+ boolean protectComponentLPw(String componentClassName, boolean protect, int userId) {
+ PackageUserState state = modifyUserStateComponents(userId);
+ boolean changed = false;
+ if (protect == COMPONENT_VISIBLE_STATUS) {
+ changed = state.protectedComponents != null
+ ? state.protectedComponents.remove(componentClassName) : false;
+ changed |= state.visibleComponents.add(componentClassName);
+ } else {
+ changed = state.visibleComponents != null
+ ? state.visibleComponents.remove(componentClassName) : false;
+ changed |= state.protectedComponents.add(componentClassName);
+ }
+
+ return changed;
+ }
+
+ ArraySet<String> getProtectedComponents(int userId) {
+ PackageUserState state = modifyUserStateComponents(userId);
+ return state.protectedComponents;
+ }
+
void removeUser(int userId) {
userState.delete(userId);
}
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 647c17b..7b95106 100644..100755
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -21,6 +21,7 @@ import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
+import static android.content.pm.PackageManager.INSTALL_FAILED_UNINSTALLED_PREBUNDLE;
import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS;
import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER;
@@ -33,6 +34,8 @@ import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
import android.content.pm.IntentFilterVerificationInfo;
import android.content.pm.ResolveInfo;
+import android.content.res.Configuration;
+import android.content.res.Resources;
import android.net.Uri;
import android.os.Binder;
import android.os.Build;
@@ -59,6 +62,8 @@ import android.util.SparseLongArray;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.os.BackgroundThread;
import com.android.internal.util.ArrayUtils;
+import com.android.internal.R;
+import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.JournaledFile;
@@ -70,6 +75,7 @@ import com.android.server.pm.PermissionsState.PermissionState;
import java.io.FileNotFoundException;
import java.util.Collection;
+import java.util.HashSet;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -87,6 +93,7 @@ import android.content.pm.Signature;
import android.content.pm.UserInfo;
import android.content.pm.PackageUserState;
import android.content.pm.VerifierDeviceIdentity;
+import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Log;
@@ -96,9 +103,13 @@ import android.util.SparseIntArray;
import android.util.Xml;
import java.io.BufferedOutputStream;
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;
@@ -185,6 +196,9 @@ final class Settings {
private static final String TAG_DEFAULT_BROWSER = "default-browser";
private static final String TAG_VERSION = "version";
+ private static final String TAG_PROTECTED_COMPONENTS = "protected-components";
+ private static final String TAG_VISIBLE_COMPONENTS = "visible-components";
+
private static final String ATTR_NAME = "name";
private static final String ATTR_USER = "user";
private static final String ATTR_CODE = "code";
@@ -203,6 +217,7 @@ final class Settings {
private static final String ATTR_DOMAIN_VERIFICATON_STATE = "domainVerificationStatus";
private static final String ATTR_PACKAGE_NAME = "packageName";
private static final String ATTR_FINGERPRINT = "fingerprint";
+ private static final String ATTR_DISPLAYVERSION = "displayversion";
private static final String ATTR_APP_LINK_GENERATION = "app-link-generation";
private static final String ATTR_VOLUME_UUID = "volumeUuid";
private static final String ATTR_SDK_VERSION = "sdkVersion";
@@ -217,6 +232,7 @@ final class Settings {
private final File mPackageListFilename;
private final File mStoppedPackagesFilename;
private final File mBackupStoppedPackagesFilename;
+ private final File mPrebundledPackagesFilename;
final ArrayMap<String, PackageSetting> mPackages =
new ArrayMap<String, PackageSetting>();
@@ -259,6 +275,12 @@ final class Settings {
String fingerprint;
/**
+ * Last known value of {@link Build#DISPLAY}. Used to determine when
+ * an system update has occurred, meaning we need to clear code caches.
+ */
+ String displayversion;
+
+ /**
* Force all version information to match current system values,
* typically after resolving any required upgrade steps.
*/
@@ -266,6 +288,7 @@ final class Settings {
sdkVersion = Build.VERSION.SDK_INT;
databaseVersion = CURRENT_DATABASE_VERSION;
fingerprint = Build.FINGERPRINT;
+ displayversion = Build.DISPLAY;
}
}
@@ -284,6 +307,10 @@ final class Settings {
final SparseArray<PersistentPreferredIntentResolver> mPersistentPreferredActivities =
new SparseArray<PersistentPreferredIntentResolver>();
+ // The persistent prebundled packages for a user
+ final SparseArray<HashSet<String>> mPrebundledPackages =
+ new SparseArray<HashSet<String>>();
+
// For every user, it is used to find to which other users the intent can be forwarded.
final SparseArray<CrossProfileIntentResolver> mCrossProfileIntentResolvers =
new SparseArray<CrossProfileIntentResolver>();
@@ -362,6 +389,7 @@ final class Settings {
// Deprecated: Needed for migration
mStoppedPackagesFilename = new File(mSystemDir, "packages-stopped.xml");
mBackupStoppedPackagesFilename = new File(mSystemDir, "packages-stopped-backup.xml");
+ mPrebundledPackagesFilename = new File(mSystemDir, "prebundled-packages.list");
}
PackageSetting getPackageLPw(PackageParser.Package pkg, PackageSetting origPackage,
@@ -666,7 +694,10 @@ final class Settings {
false, // hidden
null, null, null,
false, // blockUninstall
- INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED, 0);
+ INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED, 0,
+ null,
+ null
+ );
writePackageRestrictionsLPr(user.id);
}
}
@@ -1035,6 +1066,15 @@ final class Settings {
return pir;
}
+ HashSet<String> editPrebundledPackagesLPw(int userId) {
+ HashSet<String> hashSet = mPrebundledPackages.get(userId);
+ if (hashSet == null) {
+ hashSet = new HashSet<String>();
+ mPrebundledPackages.put(userId, hashSet);
+ }
+ return hashSet;
+ }
+
PersistentPreferredIntentResolver editPersistentPreferredActivitiesLPw(int userId) {
PersistentPreferredIntentResolver ppir = mPersistentPreferredActivities.get(userId);
if (ppir == null) {
@@ -1204,6 +1244,10 @@ final class Settings {
"package-restrictions-backup.xml");
}
+ private File getUserPrebundledStateFile(int userId) {
+ return new File(Environment.getUserSystemDirectory(userId), "prebundled-packages.list");
+ }
+
void writeAllUsersPackageRestrictionsLPr() {
List<UserInfo> users = getAllUsers();
if (users == null) return;
@@ -1428,7 +1472,10 @@ final class Settings {
false, // hidden
null, null, null,
false, // blockUninstall
- INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED, 0);
+ INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED, 0,
+ null,
+ null
+ );
}
return;
}
@@ -1513,6 +1560,8 @@ final class Settings {
ArraySet<String> enabledComponents = null;
ArraySet<String> disabledComponents = null;
+ ArraySet<String> protectedComponents = null;
+ ArraySet<String> visibleComponents = null;
int packageDepth = parser.getDepth();
while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
@@ -1527,12 +1576,17 @@ final class Settings {
enabledComponents = readComponentsLPr(parser);
} else if (tagName.equals(TAG_DISABLED_COMPONENTS)) {
disabledComponents = readComponentsLPr(parser);
+ } else if (tagName.equals(TAG_PROTECTED_COMPONENTS)) {
+ protectedComponents = readComponentsLPr(parser);
+ } else if (tagName.equals(TAG_VISIBLE_COMPONENTS)) {
+ visibleComponents = readComponentsLPr(parser);
}
}
ps.setUserState(userId, enabled, installed, stopped, notLaunched, hidden,
enabledCaller, enabledComponents, disabledComponents, blockUninstall,
- verifState, linkGeneration);
+ verifState, linkGeneration,
+ protectedComponents, visibleComponents);
} else if (tagName.equals("preferred-activities")) {
readPreferredActivitiesLPw(parser, userId);
} else if (tagName.equals(TAG_PERSISTENT_PREFERRED_ACTIVITIES)) {
@@ -1772,7 +1826,11 @@ final class Settings {
&& ustate.disabledComponents.size() > 0)
|| ustate.blockUninstall
|| (ustate.domainVerificationStatus !=
- PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED)) {
+ PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED)
+ || (ustate.protectedComponents != null
+ && ustate.protectedComponents.size() > 0)
+ || (ustate.visibleComponents != null
+ && ustate.visibleComponents.size() > 0)) {
serializer.startTag(null, TAG_PACKAGE);
serializer.attribute(null, ATTR_NAME, pkg.name);
if (DEBUG_MU) Log.i(TAG, " pkg=" + pkg.name + ", state=" + ustate.enabled);
@@ -1829,7 +1887,26 @@ final class Settings {
}
serializer.endTag(null, TAG_DISABLED_COMPONENTS);
}
-
+ if (ustate.protectedComponents != null
+ && ustate.protectedComponents.size() > 0) {
+ serializer.startTag(null, TAG_PROTECTED_COMPONENTS);
+ for (final String name : ustate.protectedComponents) {
+ serializer.startTag(null, TAG_ITEM);
+ serializer.attribute(null, ATTR_NAME, name);
+ serializer.endTag(null, TAG_ITEM);
+ }
+ serializer.endTag(null, TAG_PROTECTED_COMPONENTS);
+ }
+ if (ustate.visibleComponents != null
+ && ustate.visibleComponents.size() > 0) {
+ serializer.startTag(null, TAG_VISIBLE_COMPONENTS);
+ for (final String name : ustate.visibleComponents) {
+ serializer.startTag(null, TAG_ITEM);
+ serializer.attribute(null, ATTR_NAME, name);
+ serializer.endTag(null, TAG_ITEM);
+ }
+ serializer.endTag(null, TAG_VISIBLE_COMPONENTS);
+ }
serializer.endTag(null, TAG_PACKAGE);
}
}
@@ -2098,6 +2175,7 @@ final class Settings {
XmlUtils.writeIntAttribute(serializer, ATTR_SDK_VERSION, ver.sdkVersion);
XmlUtils.writeIntAttribute(serializer, ATTR_DATABASE_VERSION, ver.databaseVersion);
XmlUtils.writeStringAttribute(serializer, ATTR_FINGERPRINT, ver.fingerprint);
+ XmlUtils.writeStringAttribute(serializer, ATTR_DISPLAYVERSION, ver.displayversion);
serializer.endTag(null, TAG_VERSION);
}
@@ -2315,6 +2393,165 @@ final class Settings {
}
}
+ // Migrate from previous prebundled packages file to new one
+ void migratePrebundedPackagesIfNeededLPr(List<UserInfo> users, Installer installer) {
+ if (mPrebundledPackagesFilename.exists()) {
+ // Read old file
+ editPrebundledPackagesLPw(UserHandle.USER_OWNER);
+ readPrebundledPackagesOldLPw();
+ mPrebundledPackagesFilename.delete();
+ // Migrate to new file based on user
+ writePrebundledPackagesLPr(UserHandle.USER_OWNER);
+ } else {
+ if (users == null) {
+ readPrebundledPackagesLPr(UserHandle.USER_OWNER);
+ } else {
+ for (UserInfo user : users) {
+ editPrebundledPackagesLPw(user.id);
+ readPrebundledPackagesLPr(user.id);
+ // mark all existing users as having packages installed from OWNER
+ try {
+ markAllAsInstalledForUser(user.id, installer);
+ } catch (PackageManagerException e) {
+ Log.d(TAG, e.toString());
+ }
+ }
+ }
+ }
+ }
+
+ void writePrebundledPackagesLPr(int userId) {
+ editPrebundledPackagesLPw(userId);
+ PrintWriter writer = null;
+ try {
+ writer = new PrintWriter(
+ new BufferedWriter(new FileWriter(getUserPrebundledStateFile(userId), false)));
+
+ for (String packageName : mPrebundledPackages.get(userId)) {
+ writer.println(packageName);
+ }
+ } catch (IOException e) {
+ Slog.e(PackageManagerService.TAG, "Unable to write prebundled package list", e);
+ } finally {
+ if (writer != null) {
+ writer.close();
+ }
+ }
+ }
+
+ // This is done for an intermediate migration step on upgrade
+ void readPrebundledPackagesOldLPw() {
+ if (!mPrebundledPackagesFilename.exists()) {
+ return;
+ }
+
+ readPrebundledPackagesForUserFromFileLPr(UserHandle.USER_OWNER,
+ mPrebundledPackagesFilename);
+ }
+
+ void readPrebundledPackagesLPr(int userId) {
+ if (!getUserPrebundledStateFile(userId).exists()) {
+ return;
+ }
+ readPrebundledPackagesForUserFromFileLPr(userId, getUserPrebundledStateFile(userId));
+ }
+
+ private void readPrebundledPackagesForUserFromFileLPr(int userId, File file) {
+ BufferedReader reader = null;
+ try {
+ reader = new BufferedReader(new FileReader(file));
+ String packageName = reader.readLine();
+ while (packageName != null) {
+ if (!TextUtils.isEmpty(packageName)) {
+ mPrebundledPackages.get(userId).add(packageName);
+ }
+ packageName = reader.readLine();
+ }
+ } catch (IOException e) {
+ Slog.e(PackageManagerService.TAG, "Unable to read prebundled package list", e);
+ } finally {
+ if (reader != null) {
+ try {
+ reader.close();
+ } catch (IOException e) {}
+ }
+ }
+ }
+
+ private void markAllAsInstalledForUser(int userHandle, Installer installer)
+ throws PackageManagerException {
+ if (mPrebundledPackages.get(userHandle) == null) {
+ throw new PackageManagerException(INSTALL_FAILED_UNINSTALLED_PREBUNDLE,
+ "Failure migrating prebundled packages to existing user " + userHandle);
+ }
+
+ // grab all the packages from the user account, move them over
+ for (String s : mPrebundledPackages.get(UserHandle.USER_OWNER)) {
+ mPrebundledPackages.get(userHandle).add(s);
+ }
+
+ for (PackageSetting ps : mPackages.values()) {
+ if (ps.pkg == null || ps.pkg.applicationInfo == null) {
+ continue;
+ }
+ // Mark the app as installed
+ boolean setInstalled =
+ wasPrebundledPackageInstalledLPr(UserHandle.USER_OWNER, ps.name);
+ ps.setInstalled(setInstalled, userHandle);
+ // Tell the installer to create the user data for the application
+ installer.createUserData(ps.name,
+ UserHandle.getUid(userHandle, ps.appId), userHandle,
+ ps.pkg.applicationInfo.seinfo);
+ }
+ // Write the package restrications
+ writePackageRestrictionsLPr(userHandle);
+ }
+
+ void markPrebundledPackageInstalledLPr(int userId, String packageName) {
+ editPrebundledPackagesLPw(userId);
+ mPrebundledPackages.get(userId).add(packageName);
+ }
+
+ boolean wasPrebundledPackageInstalledLPr(int userId, String packageName) {
+ if (mPrebundledPackages.get(userId) == null) {
+ return false;
+ }
+ return mPrebundledPackages.get(userId).contains(packageName);
+ }
+
+ boolean shouldPrebundledPackageBeInstalled(Resources res, String packageName,
+ Resources configuredResources) {
+ // Default fallback on lack of bad package
+ if (TextUtils.isEmpty(packageName)) {
+ return false;
+ }
+
+ // Configured resources can be null if the device
+ // is not region locked. In such cases, fall back to
+ // the default resources object
+ Resources resources = configuredResources;
+ if (configuredResources == null) {
+ resources = res;
+ }
+
+ // If the package is compatible with the current region, install it
+ // Note : If a package needs to be installed only if the device is
+ // not provisioned, overlay values/config_region_locked_packages
+ // TODO change config_region_locked_packages to something that is
+ // not confusing inside a non region resource bucket
+ String[] prebundledArray
+ = resources.getStringArray(R.array.config_region_locked_packages);
+ if (ArrayUtils.contains(prebundledArray, packageName)) {
+ return true;
+ }
+
+ // If the package is not compatible with the current region, check if its locked
+ // to any other region before installing it.
+ prebundledArray = resources
+ .getStringArray(R.array.config_restrict_to_region_locked_devices);
+ return !ArrayUtils.contains(prebundledArray, packageName);
+ }
+
void writeDisabledSysPackageLPr(XmlSerializer serializer, final PackageSetting pkg)
throws java.io.IOException {
serializer.startTag(null, "updated-package");
@@ -2473,6 +2710,9 @@ final class Settings {
}
}
}
+ if (bp.allowViaWhitelist) {
+ serializer.attribute(null, "allowViaWhitelist", Integer.toString(1));
+ }
serializer.endTag(null, TAG_ITEM);
}
}
@@ -2498,7 +2738,7 @@ final class Settings {
}
boolean readLPw(PackageManagerService service, List<UserInfo> users, int sdkVersion,
- boolean onlyCore) {
+ boolean onlyCore, Installer installer) {
FileInputStream str = null;
if (mBackupSettingsFilename.exists()) {
try {
@@ -2626,6 +2866,8 @@ final class Settings {
external.sdkVersion = XmlUtils.readIntAttribute(parser, "external", 0);
internal.fingerprint = external.fingerprint =
XmlUtils.readStringAttribute(parser, "fingerprint");
+ internal.displayversion = external.displayversion =
+ XmlUtils.readStringAttribute(parser, "displayversion");
} else if (tagName.equals("database-version")) {
// Upgrade from older XML schema
@@ -2657,6 +2899,7 @@ final class Settings {
ver.sdkVersion = XmlUtils.readIntAttribute(parser, ATTR_SDK_VERSION);
ver.databaseVersion = XmlUtils.readIntAttribute(parser, ATTR_SDK_VERSION);
ver.fingerprint = XmlUtils.readStringAttribute(parser, ATTR_FINGERPRINT);
+ ver.displayversion = XmlUtils.readStringAttribute(parser, ATTR_DISPLAYVERSION);
} else {
Slog.w(PackageManagerService.TAG, "Unknown element under <packages>: "
@@ -2682,7 +2925,8 @@ final class Settings {
// on update drop the files before loading them.
if (PackageManagerService.CLEAR_RUNTIME_PERMISSIONS_ON_UPGRADE) {
final VersionInfo internal = getInternalVersion();
- if (!Build.FINGERPRINT.equals(internal.fingerprint)) {
+ if ((!Build.FINGERPRINT.equals(internal.fingerprint)) ||
+ (!Build.DISPLAY.equals(internal.displayversion))) {
if (users == null) {
mRuntimePermissionsPersistence.deleteUserRuntimePermissionsFile(
UserHandle.USER_OWNER);
@@ -2752,6 +2996,8 @@ final class Settings {
}
}
+ migratePrebundedPackagesIfNeededLPr(users, installer);
+
/*
* Make sure all the updated system packages have their shared users
* associated with them.
@@ -2973,6 +3219,11 @@ final class Settings {
for (int i=0; i<ri.size(); i++) {
ActivityInfo ai = ri.get(i).activityInfo;
set[i] = new ComponentName(ai.packageName, ai.name);
+ // We have already discovered the best third party match,
+ // so we only need to finish filling set with all results.
+ if (haveNonSys != null) {
+ continue;
+ }
if ((ai.applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) == 0) {
if (ri.get(i).match >= thirdPartyMatch) {
// Keep track of the best match we find of all third
@@ -2981,7 +3232,6 @@ final class Settings {
if (PackageManagerService.DEBUG_PREFERRED) Log.d(TAG, "Result "
+ ai.packageName + "/" + ai.name + ": non-system!");
haveNonSys = set[i];
- break;
}
} else if (cn.getPackageName().equals(ai.packageName)
&& cn.getClassName().equals(ai.name)) {
@@ -3126,6 +3376,8 @@ final class Settings {
bp.protectionLevel = readInt(parser, null, "protection",
PermissionInfo.PROTECTION_NORMAL);
bp.protectionLevel = PermissionInfo.fixProtectionLevel(bp.protectionLevel);
+ bp.allowViaWhitelist = readInt(parser, null,
+ "allowViaWhitelist", 0) == 1;
if (dynamic) {
PermissionInfo pi = new PermissionInfo();
pi.packageName = sourcePackage.intern();
@@ -3133,6 +3385,7 @@ final class Settings {
pi.icon = readInt(parser, null, "icon", 0);
pi.nonLocalizedLabel = parser.getAttributeValue(null, "label");
pi.protectionLevel = bp.protectionLevel;
+ pi.allowViaWhitelist = bp.allowViaWhitelist;
bp.pendingInfo = pi;
}
out.put(bp.name, bp);
@@ -3669,7 +3922,9 @@ final class Settings {
continue;
}
// Only system apps are initially installed.
- ps.setInstalled((ps.pkgFlags&ApplicationInfo.FLAG_SYSTEM) != 0, userHandle);
+ boolean setInstalled = ((ps.pkgFlags&ApplicationInfo.FLAG_SYSTEM) != 0) ||
+ wasPrebundledPackageInstalledLPr(UserHandle.USER_OWNER, ps.name);
+ ps.setInstalled(setInstalled, userHandle);
// Need to create a data directory for all apps under this user.
installer.createUserData(ps.volumeUuid, ps.name,
UserHandle.getUid(userHandle, ps.appId), userHandle,
@@ -3678,6 +3933,7 @@ final class Settings {
applyDefaultPreferredAppsLPw(service, userHandle);
writePackageRestrictionsLPr(userHandle);
writePackageListLPr(userHandle);
+ writePrebundledPackagesLPr(userHandle);
}
void removeUserLPw(int userId) {
@@ -3686,10 +3942,13 @@ final class Settings {
entry.getValue().removeUser(userId);
}
mPreferredActivities.remove(userId);
+ mPrebundledPackages.remove(userId);
File file = getUserPackagesStateFile(userId);
file.delete();
file = getUserPackagesStateBackupFile(userId);
file.delete();
+ file = getUserPrebundledStateFile(userId);
+ file.delete();
removeCrossProfileIntentFiltersLPw(userId);
mRuntimePermissionsPersistence.onUserRemoved(userId);
@@ -3864,7 +4123,7 @@ final class Settings {
if (pkgSetting.getNotLaunched(userId)) {
if (pkgSetting.installerPackageName != null) {
yucky.sendPackageBroadcast(Intent.ACTION_PACKAGE_FIRST_LAUNCH,
- pkgSetting.name, null,
+ pkgSetting.name, null, null,
pkgSetting.installerPackageName, null, new int[] {userId});
}
pkgSetting.setNotLaunched(false, userId);
@@ -3874,6 +4133,57 @@ final class Settings {
return false;
}
+ void removeStalePermissions() {
+ /*
+ * Remove any permission that is not currently declared by any package
+ */
+ List<BasePermission> permissionsToRemove = new ArrayList<>();
+ for (BasePermission basePerm : mPermissions.values()) {
+ // Ignore permissions declared by the system
+ if (basePerm.sourcePackage.equals("android") ||
+ basePerm.sourcePackage.equals("cyanogenmod.platform")) {
+ continue;
+ }
+ // Ignore permissions other than NORMAL (ignore DYNAMIC and BUILTIN), like the
+ // ones based on permission-trees
+ if (basePerm.type != BasePermission.TYPE_NORMAL) {
+ continue;
+ }
+
+ if (!mPackages.containsKey(basePerm.sourcePackage)) {
+ // Package doesn't exist
+ permissionsToRemove.add(basePerm);
+ continue;
+ }
+ PackageSetting pkgSettings = mPackages.get(basePerm.sourcePackage);
+ if (pkgSettings.pkg == null || pkgSettings.pkg.permissions == null) {
+ // Package doesn't declare permissions
+ permissionsToRemove.add(basePerm);
+ continue;
+ }
+ boolean found = false;
+ for (PackageParser.Permission perm : pkgSettings.pkg.permissions) {
+ if (perm.info.name != null && basePerm.name.equals(perm.info.name)) {
+ // The original package still declares the permission
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ // The original package doesn't currently declare the permission
+ permissionsToRemove.add(basePerm);
+ }
+ }
+ // And now remove all stale permissions
+ for (BasePermission basePerm : permissionsToRemove) {
+ String msg = "Removed stale permission: " + basePerm.name + " originally " +
+ "assigned to " + basePerm.sourcePackage + "\n";
+ mReadMessages.append(msg);
+ PackageManagerService.reportSettingsProblem(Log.WARN, msg);
+ mPermissions.remove(basePerm.name);
+ }
+ }
+
List<UserInfo> getAllUsers() {
long id = Binder.clearCallingIdentity();
try {
@@ -3955,6 +4265,7 @@ final class Settings {
pw.printPair("databaseVersion", ver.databaseVersion);
pw.println();
pw.printPair("fingerprint", ver.fingerprint);
+ pw.printPair("displayversion", ver.displayversion);
pw.println();
pw.decreaseIndent();
}
@@ -4522,6 +4833,10 @@ final class Settings {
@GuardedBy("mLock")
// The mapping keys are user ids.
+ private final SparseArray<String> mDisplayversion = new SparseArray<>();
+
+ @GuardedBy("mLock")
+ // The mapping keys are user ids.
private final SparseBooleanArray mDefaultPermissionsGranted = new SparseBooleanArray();
public RuntimePermissionPersistence(Object lock) {
@@ -4534,6 +4849,7 @@ final class Settings {
public void onDefaultRuntimePermissionsGrantedLPr(int userId) {
mFingerprints.put(userId, Build.FINGERPRINT);
+ mDisplayversion.put(userId, Build.DISPLAY);
writePermissionsForUserAsyncLPr(userId);
}
@@ -4626,6 +4942,11 @@ final class Settings {
serializer.attribute(null, ATTR_FINGERPRINT, fingerprint);
}
+ String displayversion = mDisplayversion.get(userId);
+ if (displayversion != null) {
+ serializer.attribute(null, ATTR_DISPLAYVERSION, displayversion);
+ }
+
final int packageCount = permissionsForPackage.size();
for (int i = 0; i < packageCount; i++) {
String packageName = permissionsForPackage.keyAt(i);
@@ -4650,7 +4971,8 @@ final class Settings {
serializer.endDocument();
destination.finishWrite(out);
- if (Build.FINGERPRINT.equals(fingerprint)) {
+ if ((Build.FINGERPRINT.equals(fingerprint)) ||
+ (Build.DISPLAY.equals(displayversion))) {
mDefaultPermissionsGranted.put(userId, true);
}
// Any error while writing is fatal.
@@ -4733,8 +5055,11 @@ final class Settings {
switch (parser.getName()) {
case TAG_RUNTIME_PERMISSIONS: {
String fingerprint = parser.getAttributeValue(null, ATTR_FINGERPRINT);
+ String displayversion = parser.getAttributeValue(null, ATTR_DISPLAYVERSION);
mFingerprints.put(userId, fingerprint);
- final boolean defaultsGranted = Build.FINGERPRINT.equals(fingerprint);
+ mDisplayversion.put(userId, displayversion);
+ final boolean defaultsGranted = Build.FINGERPRINT.equals(fingerprint) ||
+ Build.DISPLAY.equals(displayversion);
mDefaultPermissionsGranted.put(userId, defaultsGranted);
} break;
diff --git a/services/core/java/com/android/server/policy/BarController.java b/services/core/java/com/android/server/policy/BarController.java
index 9095f57..7a20e40 100644
--- a/services/core/java/com/android/server/policy/BarController.java
+++ b/services/core/java/com/android/server/policy/BarController.java
@@ -26,6 +26,7 @@ import android.view.View;
import android.view.WindowManager;
import android.view.WindowManagerPolicy.WindowState;
+import android.view.WindowManagerPolicyControl;
import com.android.internal.statusbar.IStatusBarService;
import java.io.PrintWriter;
@@ -119,7 +120,7 @@ public class BarController {
if (mWin != null) {
if (win != null && (win.getAttrs().privateFlags
& WindowManager.LayoutParams.PRIVATE_FLAG_INHERIT_TRANSLUCENT_DECOR) == 0) {
- int fl = PolicyControl.getWindowFlags(win, null);
+ int fl = WindowManagerPolicyControl.getWindowFlags(win, null);
if ((fl & mTranslucentWmFlag) != 0) {
vis |= mTranslucentFlag;
} else {
diff --git a/services/core/java/com/android/server/policy/GlobalActions.java b/services/core/java/com/android/server/policy/GlobalActions.java
index 3cee927..8c42917 100644
--- a/services/core/java/com/android/server/policy/GlobalActions.java
+++ b/services/core/java/com/android/server/policy/GlobalActions.java
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2008 The Android Open Source Project
+ * Copyright (C) 2010-2015 CyanogenMod Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -28,19 +29,27 @@ import android.app.ActivityManagerNative;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.BroadcastReceiver;
+import android.content.ComponentName;
import android.content.Context;
+import android.content.ContentResolver;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.pm.ThemeUtils;
import android.content.pm.UserInfo;
+import android.content.ServiceConnection;
import android.database.ContentObserver;
import android.graphics.drawable.Drawable;
+import android.Manifest;
import android.media.AudioManager;
import android.net.ConnectivityManager;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
+import android.os.IBinder;
+import android.os.IPowerManager;
import android.os.Message;
+import android.os.Messenger;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
@@ -75,9 +84,13 @@ import android.widget.ImageView;
import android.widget.ImageView.ScaleType;
import android.widget.ListView;
import android.widget.TextView;
+import cyanogenmod.providers.CMSettings;
import java.util.ArrayList;
import java.util.List;
+import java.util.UUID;
+
+import static com.android.internal.util.cm.PowerMenuConstants.*;
/**
* Helper to show the global actions dialog. Each item is an {@link Action} that
@@ -90,20 +103,9 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac
private static final boolean SHOW_SILENT_TOGGLE = true;
- /* Valid settings for global actions keys.
- * see config.xml config_globalActionList */
- private static final String GLOBAL_ACTION_KEY_POWER = "power";
- private static final String GLOBAL_ACTION_KEY_AIRPLANE = "airplane";
- private static final String GLOBAL_ACTION_KEY_BUGREPORT = "bugreport";
- private static final String GLOBAL_ACTION_KEY_SILENT = "silent";
- private static final String GLOBAL_ACTION_KEY_USERS = "users";
- private static final String GLOBAL_ACTION_KEY_SETTINGS = "settings";
- private static final String GLOBAL_ACTION_KEY_LOCKDOWN = "lockdown";
- private static final String GLOBAL_ACTION_KEY_VOICEASSIST = "voiceassist";
- private static final String GLOBAL_ACTION_KEY_ASSIST = "assist";
-
private final Context mContext;
private final WindowManagerFuncs mWindowManagerFuncs;
+ private Context mUiContext;
private final AudioManager mAudioManager;
private final IDreamManager mDreamManager;
@@ -123,6 +125,9 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac
private boolean mHasVibrator;
private final boolean mShowSilentToggle;
+ // Power menu customizations
+ String mActions;
+
/**
* @param context everything needs a context :(
*/
@@ -137,6 +142,7 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
filter.addAction(Intent.ACTION_SCREEN_OFF);
+ filter.addAction(Intent.UPDATE_POWER_MENU);
filter.addAction(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED);
context.registerReceiver(mBroadcastReceiver, filter);
@@ -156,6 +162,8 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac
mShowSilentToggle = SHOW_SILENT_TOGGLE && !mContext.getResources().getBoolean(
com.android.internal.R.bool.config_useFixedVolume);
+
+ updatePowerMenuActions();
}
/**
@@ -165,12 +173,14 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac
public void showDialog(boolean keyguardShowing, boolean isDeviceProvisioned) {
mKeyguardShowing = keyguardShowing;
mDeviceProvisioned = isDeviceProvisioned;
- if (mDialog != null) {
+ if (mDialog != null && mUiContext == null) {
mDialog.dismiss();
mDialog = null;
+ mDialog = createDialog();
// Show delayed, so that the dismiss of the previous dialog completes
mHandler.sendEmptyMessage(MESSAGE_SHOW);
} else {
+ mDialog = createDialog();
handleShow();
}
}
@@ -189,7 +199,6 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac
private void handleShow() {
awakenIfNecessary();
- mDialog = createDialog();
prepareDialog();
// If we only have 1 item and it's a simple press action, just do this action.
@@ -206,6 +215,14 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac
}
}
+ private Context getUiContext() {
+ if (mUiContext == null) {
+ mUiContext = ThemeUtils.createUiContext(mContext);
+ mUiContext.setTheme(android.R.style.Theme_DeviceDefault_Light_DarkActionBar);
+ }
+ return mUiContext != null ? mUiContext : mContext;
+ }
+
/**
* Create the global actions dialog.
* @return A new dialog.
@@ -261,18 +278,31 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac
onAirplaneModeChanged();
mItems = new ArrayList<Action>();
- String[] defaultActions = mContext.getResources().getStringArray(
- com.android.internal.R.array.config_globalActionsList);
+
+ String[] actionsArray;
+ if (mActions == null) {
+ actionsArray = mContext.getResources().getStringArray(
+ com.android.internal.R.array.config_globalActionsList);
+ } else {
+ actionsArray = mActions.split("\\|");
+ }
+
+ // Always add the power off option
+ mItems.add(new PowerAction());
ArraySet<String> addedKeys = new ArraySet<String>();
- for (int i = 0; i < defaultActions.length; i++) {
- String actionKey = defaultActions[i];
+ for (int i = 0; i < actionsArray.length; i++) {
+ String actionKey = actionsArray[i];
if (addedKeys.contains(actionKey)) {
// If we already have added this, don't add it again.
continue;
}
if (GLOBAL_ACTION_KEY_POWER.equals(actionKey)) {
- mItems.add(new PowerAction());
+ continue;
+ } else if (GLOBAL_ACTION_KEY_REBOOT.equals(actionKey)) {
+ mItems.add(new RebootAction());
+ } else if (GLOBAL_ACTION_KEY_SCREENSHOT.equals(actionKey)) {
+ mItems.add(getScreenshotAction());
} else if (GLOBAL_ACTION_KEY_AIRPLANE.equals(actionKey)) {
mItems.add(mAirplaneModeOn);
} else if (GLOBAL_ACTION_KEY_BUGREPORT.equals(actionKey)) {
@@ -285,7 +315,9 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac
mItems.add(mSilentModeAction);
}
} else if (GLOBAL_ACTION_KEY_USERS.equals(actionKey)) {
- if (SystemProperties.getBoolean("fw.power_user_switcher", false)) {
+ List<UserInfo> users = ((UserManager) mContext.getSystemService(
+ Context.USER_SERVICE)).getUsers();
+ if (users.size() > 1) {
addUsersToMenu(mItems);
}
} else if (GLOBAL_ACTION_KEY_SETTINGS.equals(actionKey)) {
@@ -305,12 +337,12 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac
mAdapter = new MyAdapter();
- AlertParams params = new AlertParams(mContext);
+ AlertParams params = new AlertParams(getUiContext());
params.mAdapter = mAdapter;
params.mOnClickListener = this;
params.mForceInverseBackground = true;
- GlobalActionsDialog dialog = new GlobalActionsDialog(mContext, params);
+ GlobalActionsDialog dialog = new GlobalActionsDialog(getUiContext(), params);
dialog.setCanceledOnTouchOutside(false); // Handled by the custom class.
dialog.getListView().setItemsCanFocus(true);
@@ -367,6 +399,53 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac
}
}
+ private final class RebootAction extends SinglePressAction {
+ private RebootAction() {
+ super(com.android.internal.R.drawable.ic_lock_power_reboot,
+ R.string.global_action_reboot);
+ }
+
+ @Override
+ public boolean showDuringKeyguard() {
+ return true;
+ }
+
+ @Override
+ public boolean showBeforeProvisioning() {
+ return true;
+ }
+
+ @Override
+ public void onPress() {
+ try {
+ IPowerManager pm = IPowerManager.Stub.asInterface(ServiceManager
+ .getService(Context.POWER_SERVICE));
+ pm.reboot(true, null, false);
+ } catch (RemoteException e) {
+ Log.e(TAG, "PowerManager service died!", e);
+ return;
+ }
+ }
+ }
+
+ private Action getScreenshotAction() {
+ return new SinglePressAction(com.android.internal.R.drawable.ic_lock_screenshot,
+ R.string.global_action_screenshot) {
+
+ public void onPress() {
+ takeScreenshot();
+ }
+
+ public boolean showDuringKeyguard() {
+ return true;
+ }
+
+ public boolean showBeforeProvisioning() {
+ return true;
+ }
+ };
+ }
+
private Action getBugReportAction() {
return new SinglePressAction(com.android.internal.R.drawable.ic_lock_bugreport,
R.string.bugreport_title) {
@@ -423,7 +502,7 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac
}
private Action getSettingsAction() {
- return new SinglePressAction(com.android.internal.R.drawable.ic_settings,
+ return new SinglePressAction(com.android.internal.R.drawable.ic_lock_settings,
R.string.global_action_settings) {
@Override
@@ -540,7 +619,7 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac
Drawable icon = user.iconPath != null ? Drawable.createFromPath(user.iconPath)
: null;
SinglePressAction switchToUser = new SinglePressAction(
- com.android.internal.R.drawable.ic_menu_cc, icon,
+ com.android.internal.R.drawable.ic_lock_user, icon,
(user.name != null ? user.name : "Primary")
+ (isCurrentUser ? " \u2714" : "")) {
public void onPress() {
@@ -565,6 +644,90 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac
}
}
+ /**
+ * 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) {
+ // Do nothing
+ }
+
+ /* take the screenshot */
+ try {
+ messenger.send(msg);
+ } catch (RemoteException e) {
+ // Do nothing
+ }
+ }
+ }
+ @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);
@@ -671,7 +834,8 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac
public View getView(int position, View convertView, ViewGroup parent) {
Action action = getItem(position);
- return action.create(mContext, convertView, parent, LayoutInflater.from(mContext));
+ final Context context = getUiContext();
+ return action.create(context, convertView, parent, LayoutInflater.from(context));
}
}
@@ -1040,10 +1204,24 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac
mIsWaitingForEcmExit = false;
changeAirplaneModeSystemSetting(true);
}
+ } else if (Intent.UPDATE_POWER_MENU.equals(action)) {
+ updatePowerMenuActions();
}
}
};
+ protected void updatePowerMenuActions() {
+ ContentResolver resolver = mContext.getContentResolver();
+ mActions = CMSettings.Secure.getStringForUser(resolver,
+ CMSettings.Secure.POWER_MENU_ACTIONS, UserHandle.USER_CURRENT);
+ }
+
+ private BroadcastReceiver mThemeChangeReceiver = new BroadcastReceiver() {
+ public void onReceive(Context context, Intent intent) {
+ mUiContext = null;
+ }
+ };
+
PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
@Override
public void onServiceStateChanged(ServiceState serviceState) {
diff --git a/services/core/java/com/android/server/policy/ImmersiveModeConfirmation.java b/services/core/java/com/android/server/policy/ImmersiveModeConfirmation.java
index 160d44c..da9312c 100644
--- a/services/core/java/com/android/server/policy/ImmersiveModeConfirmation.java
+++ b/services/core/java/com/android/server/policy/ImmersiveModeConfirmation.java
@@ -44,6 +44,7 @@ import android.view.animation.Interpolator;
import android.widget.Button;
import android.widget.FrameLayout;
+import android.view.WindowManagerPolicyControl;
import com.android.internal.R;
/**
@@ -116,7 +117,7 @@ public class ImmersiveModeConfirmation {
boolean userSetupComplete) {
mHandler.removeMessages(H.SHOW);
if (isImmersiveMode) {
- final boolean disabled = PolicyControl.disableImmersiveConfirmation(pkg);
+ final boolean disabled = WindowManagerPolicyControl.disableImmersiveConfirmation(pkg);
if (DEBUG) Slog.d(TAG, String.format("immersiveModeChanged() disabled=%s mConfirmed=%s",
disabled, mConfirmed));
if (!disabled && (DEBUG_SHOW_EVERY_TIME || !mConfirmed) && userSetupComplete) {
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 0d96ca6..dd4d3ab 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -31,6 +31,7 @@ import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
+import android.content.ContextWrapper;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
@@ -47,6 +48,7 @@ import android.graphics.Rect;
import android.hardware.hdmi.HdmiControlManager;
import android.hardware.hdmi.HdmiPlaybackClient;
import android.hardware.hdmi.HdmiPlaybackClient.OneTouchPlayCallback;
+import android.hardware.input.InputManager;
import android.media.AudioAttributes;
import android.media.AudioManager;
import android.media.AudioSystem;
@@ -81,6 +83,12 @@ import android.service.dreams.DreamService;
import android.service.dreams.IDreamManager;
import android.speech.RecognizerIntent;
import android.telecom.TelecomManager;
+import android.service.gesture.EdgeGestureManager;
+import com.android.internal.os.DeviceKeyHandler;
+
+import com.android.internal.util.cm.ActionUtils;
+import cyanogenmod.providers.CMSettings;
+import dalvik.system.DexClassLoader;
import android.util.DisplayMetrics;
import android.util.EventLog;
import android.util.Log;
@@ -114,9 +122,16 @@ import android.view.accessibility.AccessibilityManager;
import android.view.animation.Animation;
import android.view.animation.AnimationSet;
import android.view.animation.AnimationUtils;
+import android.view.WindowManagerPolicyControl;
+import android.widget.Toast;
+
import com.android.internal.R;
+import com.android.internal.policy.IKeyguardService;
import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.util.ScreenShapeHelper;
+import com.android.internal.util.gesture.EdgeGesturePosition;
+import com.android.internal.util.gesture.EdgeServiceConstants;
+import com.android.internal.view.RotationPolicy;
import com.android.internal.widget.PointerLocationView;
import com.android.server.GestureLauncherService;
import com.android.server.LocalServices;
@@ -129,6 +144,7 @@ import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashSet;
import java.util.List;
+import java.lang.reflect.Constructor;
import static android.view.WindowManager.LayoutParams.*;
import static android.view.WindowManagerPolicy.WindowManagerFuncs.LID_ABSENT;
@@ -201,6 +217,30 @@ public class PhoneWindowManager implements WindowManagerPolicy {
static public final String SYSTEM_DIALOG_REASON_HOME_KEY = "homekey";
static public final String SYSTEM_DIALOG_REASON_ASSIST = "assist";
+ // Available custom actions to perform on a key press.
+ // Must match values for KEY_HOME_LONG_PRESS_ACTION in:
+ // core/java/android/provider/Settings.java
+ private static final int KEY_ACTION_NOTHING = 0;
+ private static final int KEY_ACTION_MENU = 1;
+ private static final int KEY_ACTION_APP_SWITCH = 2;
+ private static final int KEY_ACTION_SEARCH = 3;
+ private static final int KEY_ACTION_VOICE_SEARCH = 4;
+ private static final int KEY_ACTION_IN_APP_SEARCH = 5;
+ private static final int KEY_ACTION_LAUNCH_CAMERA = 6;
+ private static final int KEY_ACTION_SLEEP = 7;
+ private static final int KEY_ACTION_LAST_APP = 8;
+
+ // Masks for checking presence of hardware keys.
+ // Must match values in core/res/res/values/config.xml
+ private static final int KEY_MASK_HOME = 0x01;
+ private static final int KEY_MASK_BACK = 0x02;
+ private static final int KEY_MASK_MENU = 0x04;
+ private static final int KEY_MASK_ASSIST = 0x08;
+ private static final int KEY_MASK_APP_SWITCH = 0x10;
+ private static final int KEY_MASK_CAMERA = 0x20;
+ private static final int KEY_MASK_VOLUME = 0x40;
+
+
/**
* These are the system UI flags that, when changing, can cause the layout
* of the screen to change.
@@ -217,6 +257,19 @@ public class PhoneWindowManager implements WindowManagerPolicy {
.setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
.build();
+ /**
+ * Broadcast Action: WiFi Display video is enabled or disabled
+ *
+ * <p>The intent will have the following extra values:</p>
+ * <ul>
+ * <li><em>state</em> - 0 for disabled, 1 for enabled. </li>
+ * </ul>
+ */
+
+ private static final String ACTION_WIFI_DISPLAY_VIDEO =
+ "org.codeaurora.intent.action.WIFI_DISPLAY_VIDEO";
+
+
// The panic gesture may become active only after the keyguard is dismissed and the immersive
// app shows again. If that doesn't happen for 30s we drop the gesture.
private static final long PANIC_GESTURE_EXPIRATION = 30000;
@@ -254,6 +307,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
/** Amount of time (in milliseconds) to wait for windows drawn before powering on. */
static final int WAITING_FOR_DRAWN_TIMEOUT = 1000;
+ private DeviceKeyHandler mDeviceKeyHandler;
+
/**
* Lock protecting internal state. Must not call out into window
* manager with lock held. (This lock will be acquired in places
@@ -313,10 +368,10 @@ public class PhoneWindowManager implements WindowManagerPolicy {
boolean mCanHideNavigationBar = false;
boolean mNavigationBarCanMove = false; // can the navigation bar ever move to the side?
boolean mNavigationBarOnBottom = true; // is the navigation bar on the bottom *right now*?
+ boolean mNavigationBarLeftInLandscape = false; // Navigation bar left handed?
int[] mNavigationBarHeightForRotation = new int[4];
int[] mNavigationBarWidthForRotation = new int[4];
- boolean mBootMessageNeedsHiding;
KeyguardServiceDelegate mKeyguardDelegate;
final Runnable mWindowManagerDrawCallback = new Runnable() {
@Override
@@ -330,6 +385,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
public void onDrawn() {
if (DEBUG_WAKEUP) Slog.d(TAG, "mKeyguardDelegate.ShowListener.onDrawn.");
mHandler.sendEmptyMessage(MSG_KEYGUARD_DRAWN_COMPLETE);
+ hideBootMessages();
}
};
@@ -367,6 +423,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
int mUiMode;
int mDockMode = Intent.EXTRA_DOCK_STATE_UNDOCKED;
int mLidOpenRotation;
+ boolean mHasRemovableLid;
int mCarDockRotation;
int mDeskDockRotation;
int mUndockedHdmiRotation;
@@ -384,6 +441,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
int mUserRotationMode = WindowManagerPolicy.USER_ROTATION_FREE;
int mUserRotation = Surface.ROTATION_0;
+ int mUserRotationAngles = -1;
boolean mAccelerometerDefault;
boolean mSupportAutoRotation;
@@ -409,6 +467,28 @@ public class PhoneWindowManager implements WindowManagerPolicy {
boolean mHasSoftInput = false;
boolean mTranslucentDecorEnabled = true;
boolean mUseTvRouting;
+ int mBackKillTimeout;
+
+ int mDeviceHardwareKeys;
+
+ // Button wake control flags
+ boolean mHomeWakeScreen;
+ boolean mBackWakeScreen;
+ boolean mMenuWakeScreen;
+ boolean mAssistWakeScreen;
+ boolean mAppSwitchWakeScreen;
+ boolean mCameraWakeScreen;
+ boolean mVolumeWakeScreen;
+
+ // Camera button control flags and actions
+ boolean mCameraSleepOnRelease;
+ boolean mIsFocusPressed;
+ boolean mCameraLaunch;
+
+ // During wakeup by volume keys, we still need to capture subsequent events
+ // until the key is released. This is required since the beep sound is produced
+ // post keypressed.
+ boolean mVolumeWakeTriggered;
int mPointerLocationMode = 0; // guarded by mLock
@@ -416,6 +496,10 @@ public class PhoneWindowManager implements WindowManagerPolicy {
WindowState mFocusedWindow;
IApplicationToken mFocusedApp;
+ // Behavior of volbtn music controls
+ boolean mVolBtnMusicControls;
+ boolean mIsLongPress;
+
PointerLocationView mPointerLocationView;
// The current size of the screen; really; extends into the overscan area of
@@ -443,6 +527,9 @@ public class PhoneWindowManager implements WindowManagerPolicy {
// fullscreen window flag, these are the stable dimensions without the status bar.
int mStableFullscreenLeft, mStableFullscreenTop;
int mStableFullscreenRight, mStableFullscreenBottom;
+ // For force immersive mode
+ int mForceImmersiveLeft, mForceImmersiveTop;
+ int mForceImmersiveRight, mForceImmersiveBottom;
// During layout, the current screen borders with all outer decoration
// (status bar, input method dock) accounted for.
int mCurLeft, mCurTop, mCurRight, mCurBottom;
@@ -500,6 +587,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
boolean mForcingShowNavBar;
int mForcingShowNavBarLayer;
+ boolean mDevForceNavbar = false;
+
// States of keyguard dismiss.
private static final int DISMISS_KEYGUARD_NONE = 0; // Keyguard not being dismissed.
private static final int DISMISS_KEYGUARD_START = 1; // Keyguard needs to be dismissed.
@@ -534,6 +623,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
boolean mHomePressed;
boolean mHomeConsumed;
boolean mHomeDoubleTapPending;
+ boolean mMenuPressed;
+ boolean mAppSwitchLongPressed;
Intent mHomeIntent;
Intent mCarDockIntent;
Intent mDeskDockIntent;
@@ -542,6 +633,15 @@ public class PhoneWindowManager implements WindowManagerPolicy {
boolean mAssistKeyLongPressed;
boolean mPendingMetaAction;
+ // Tracks user-customisable behavior for certain key events
+ private int mLongPressOnHomeBehavior = -1;
+ private int mPressOnMenuBehavior = -1;
+ private int mLongPressOnMenuBehavior = -1;
+ private int mPressOnAssistBehavior = -1;
+ private int mLongPressOnAssistBehavior = -1;
+ private int mPressOnAppSwitchBehavior = -1;
+ private int mLongPressOnAppSwitchBehavior = -1;
+
// support for activating the lock screen while the screen is on
boolean mAllowLockscreenWhenOn;
int mLockScreenTimeout;
@@ -568,9 +668,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
int mOverscanRight = 0;
int mOverscanBottom = 0;
- // What we do when the user long presses on home
- private int mLongPressOnHomeBehavior;
-
// What we do when the user double-taps on home
private int mDoubleTapOnHomeBehavior;
@@ -637,6 +734,15 @@ public class PhoneWindowManager implements WindowManagerPolicy {
private static final int MSG_POWER_DELAYED_PRESS = 13;
private static final int MSG_POWER_LONG_PRESS = 14;
private static final int MSG_UPDATE_DREAMING_SLEEP_TOKEN = 15;
+ private static final int MSG_DISPATCH_VOLKEY_WITH_WAKE_LOCK = 16;
+ private static final int MSG_CAMERA_LONG_PRESS = 17;
+
+ boolean mWifiDisplayConnected = false;
+ int mWifiDisplayCustomRotation = -1;
+
+ private boolean mHasPermanentMenuKey;
+ private boolean mClearedBecauseOfForceShow;
+ private boolean mTopWindowIsKeyguard;
private class PolicyHandler extends Handler {
@Override
@@ -688,6 +794,19 @@ public class PhoneWindowManager implements WindowManagerPolicy {
case MSG_UPDATE_DREAMING_SLEEP_TOKEN:
updateDreamingSleepToken(msg.arg1 != 0);
break;
+ case MSG_DISPATCH_VOLKEY_WITH_WAKE_LOCK: {
+ KeyEvent event = (KeyEvent) msg.obj;
+ mIsLongPress = true;
+ dispatchMediaKeyWithWakeLockToAudioService(event);
+ dispatchMediaKeyWithWakeLockToAudioService(
+ KeyEvent.changeAction(event, KeyEvent.ACTION_UP));
+ break;
+ }
+ case MSG_CAMERA_LONG_PRESS: {
+ KeyEvent event = (KeyEvent) msg.obj;
+ mIsLongPress = true;
+ break;
+ }
}
}
}
@@ -728,6 +847,30 @@ public class PhoneWindowManager implements WindowManagerPolicy {
resolver.registerContentObserver(Settings.System.getUriFor(
Settings.System.POINTER_LOCATION), false, this,
UserHandle.USER_ALL);
+ resolver.registerContentObserver(CMSettings.System.getUriFor(
+ CMSettings.System.KEY_HOME_LONG_PRESS_ACTION), false, this,
+ UserHandle.USER_ALL);
+ resolver.registerContentObserver(CMSettings.System.getUriFor(
+ CMSettings.System.KEY_HOME_DOUBLE_TAP_ACTION), false, this,
+ UserHandle.USER_ALL);
+ resolver.registerContentObserver(CMSettings.System.getUriFor(
+ CMSettings.System.KEY_MENU_ACTION), false, this,
+ UserHandle.USER_ALL);
+ resolver.registerContentObserver(CMSettings.System.getUriFor(
+ CMSettings.System.KEY_MENU_LONG_PRESS_ACTION), false, this,
+ UserHandle.USER_ALL);
+ resolver.registerContentObserver(CMSettings.System.getUriFor(
+ CMSettings.System.KEY_ASSIST_ACTION), false, this,
+ UserHandle.USER_ALL);
+ resolver.registerContentObserver(CMSettings.System.getUriFor(
+ CMSettings.System.KEY_ASSIST_LONG_PRESS_ACTION), false, this,
+ UserHandle.USER_ALL);
+ resolver.registerContentObserver(CMSettings.System.getUriFor(
+ CMSettings.System.KEY_APP_SWITCH_ACTION), false, this,
+ UserHandle.USER_ALL);
+ resolver.registerContentObserver(CMSettings.System.getUriFor(
+ CMSettings.System.KEY_APP_SWITCH_LONG_PRESS_ACTION), false, this,
+ UserHandle.USER_ALL);
resolver.registerContentObserver(Settings.Secure.getUriFor(
Settings.Secure.DEFAULT_INPUT_METHOD), false, this,
UserHandle.USER_ALL);
@@ -737,6 +880,51 @@ public class PhoneWindowManager implements WindowManagerPolicy {
resolver.registerContentObserver(Settings.Global.getUriFor(
Settings.Global.POLICY_CONTROL), false, this,
UserHandle.USER_ALL);
+ resolver.registerContentObserver(Settings.System.getUriFor(
+ Settings.System.ACCELEROMETER_ROTATION_ANGLES), false, this,
+ UserHandle.USER_ALL);
+ resolver.registerContentObserver(CMSettings.Secure.getUriFor(
+ CMSettings.Secure.DEV_FORCE_SHOW_NAVBAR), false, this,
+ UserHandle.USER_ALL);
+ resolver.registerContentObserver(CMSettings.System.getUriFor(
+ CMSettings.System.VOLBTN_MUSIC_CONTROLS), false, this,
+ UserHandle.USER_ALL);
+ resolver.registerContentObserver(CMSettings.System.getUriFor(
+ CMSettings.System.USE_EDGE_SERVICE_FOR_GESTURES), false, this,
+ UserHandle.USER_ALL);
+ resolver.registerContentObserver(CMSettings.System.getUriFor(
+ CMSettings.System.BACK_WAKE_SCREEN), false, this,
+ UserHandle.USER_ALL);
+ resolver.registerContentObserver(CMSettings.System.getUriFor(
+ CMSettings.System.MENU_WAKE_SCREEN), false, this,
+ UserHandle.USER_ALL);
+ resolver.registerContentObserver(CMSettings.System.getUriFor(
+ CMSettings.System.ASSIST_WAKE_SCREEN), false, this,
+ UserHandle.USER_ALL);
+ resolver.registerContentObserver(CMSettings.System.getUriFor(
+ CMSettings.System.APP_SWITCH_WAKE_SCREEN), false, this,
+ UserHandle.USER_ALL);
+ resolver.registerContentObserver(CMSettings.System.getUriFor(
+ CMSettings.System.CAMERA_WAKE_SCREEN), false, this,
+ UserHandle.USER_ALL);
+ resolver.registerContentObserver(CMSettings.System.getUriFor(
+ CMSettings.System.CAMERA_SLEEP_ON_RELEASE), false, this,
+ UserHandle.USER_ALL);
+ resolver.registerContentObserver(CMSettings.System.getUriFor(
+ CMSettings.System.CAMERA_LAUNCH), false, this,
+ UserHandle.USER_ALL);
+ resolver.registerContentObserver(CMSettings.System.getUriFor(
+ CMSettings.System.VOLUME_WAKE_SCREEN), false, this,
+ UserHandle.USER_ALL);
+ resolver.registerContentObserver(CMSettings.System.getUriFor(
+ CMSettings.System.HOME_WAKE_SCREEN), false, this,
+ UserHandle.USER_ALL);
+ resolver.registerContentObserver(CMSettings.System.getUriFor(
+ CMSettings.System.VOLUME_WAKE_SCREEN), false, this,
+ UserHandle.USER_ALL);
+ resolver.registerContentObserver(CMSettings.System.getUriFor(
+ CMSettings.System.NAVBAR_LEFT_IN_LANDSCAPE), false, this,
+ UserHandle.USER_ALL);
updateSettings();
}
@@ -798,6 +986,67 @@ public class PhoneWindowManager implements WindowManagerPolicy {
private SystemGesturesPointerEventListener mSystemGestures;
+ private EdgeGestureManager.EdgeGestureActivationListener mEdgeGestureActivationListener
+ = new EdgeGestureManager.EdgeGestureActivationListener() {
+
+ @Override
+ public void onEdgeGestureActivation(int touchX, int touchY,
+ EdgeGesturePosition position, int flags) {
+ WindowState target = null;
+
+ if (position == EdgeGesturePosition.TOP) {
+ target = mStatusBar;
+ } else if (position == EdgeGesturePosition.BOTTOM && mNavigationBarOnBottom) {
+ target = mNavigationBar;
+ } else if (position == EdgeGesturePosition.LEFT
+ && !mNavigationBarOnBottom && mNavigationBarLeftInLandscape) {
+ target = mNavigationBar;
+ } else if (position == EdgeGesturePosition.RIGHT && !mNavigationBarOnBottom) {
+ target = mNavigationBar;
+ }
+
+ if (target != null) {
+ requestTransientBars(target);
+ dropEventsUntilLift();
+ mEdgeListenerActivated = true;
+ } else {
+ restoreListenerState();
+ }
+ }
+ };
+ private EdgeGestureManager mEdgeGestureManager = null;
+ private int mLastEdgePositions = 0;
+ private boolean mEdgeListenerActivated = false;
+ private boolean mUsingEdgeGestureServiceForGestures = false;
+
+ private void updateEdgeGestureListenerState() {
+ int flags = 0;
+ if (mUsingEdgeGestureServiceForGestures) {
+ flags = EdgeServiceConstants.LONG_LIVING | EdgeServiceConstants.UNRESTRICTED;
+ if (mStatusBar != null && !mStatusBar.isVisibleLw()) {
+ flags |= EdgeGesturePosition.TOP.FLAG;
+ }
+ if (mNavigationBar != null && !mNavigationBar.isVisibleLw() && !isStatusBarKeyguard()) {
+ if (mNavigationBarOnBottom) {
+ flags |= EdgeGesturePosition.BOTTOM.FLAG;
+ } else if (mNavigationBarLeftInLandscape) {
+ flags |= EdgeGesturePosition.LEFT.FLAG;
+ } else {
+ flags |= EdgeGesturePosition.RIGHT.FLAG;
+ }
+ }
+ }
+ if (mEdgeListenerActivated) {
+ mEdgeGestureActivationListener.restoreListenerState();
+ mEdgeListenerActivated = false;
+ }
+ if (flags != mLastEdgePositions) {
+ mEdgeGestureManager.updateEdgeGestureActivationListener(mEdgeGestureActivationListener,
+ flags);
+ mLastEdgePositions = flags;
+ }
+ }
+
IStatusBarService getStatusBarService() {
synchronized (mServiceAquireLock) {
if (mStatusBarService == null) {
@@ -906,7 +1155,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
// taken over the whole screen.
boolean panic = mImmersiveModeConfirmation.onPowerKeyDown(interactive,
SystemClock.elapsedRealtime(), isImmersiveMode(mLastSystemUiFlags));
- if (panic) {
+ if (panic && !WindowManagerPolicyControl.isImmersiveFiltersActive()) {
mHandler.post(mHiddenNavPanic);
}
@@ -1211,6 +1460,15 @@ public class PhoneWindowManager implements WindowManagerPolicy {
mHandler.sendEmptyMessage(MSG_DISPATCH_SHOW_GLOBAL_ACTIONS);
}
+ Runnable mBackLongPress = new Runnable() {
+ public void run() {
+ if (!unpinActivity(false) && ActionUtils.killForegroundApp(mContext, mCurrentUserId)) {
+ performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false);
+ Toast.makeText(mContext, R.string.app_killed_message, Toast.LENGTH_SHORT).show();
+ }
+ }
+ };
+
void showGlobalActionsInternal() {
sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS);
if (mGlobalActions == null) {
@@ -1290,26 +1548,57 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
}
- private void handleLongPressOnHome(int deviceId) {
- if (mLongPressOnHomeBehavior != LONG_PRESS_HOME_NOTHING) {
- mHomeConsumed = true;
- performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false);
+ private void triggerVirtualKeypress(final int keyCode) {
+ InputManager im = InputManager.getInstance();
+ long now = SystemClock.uptimeMillis();
+ final KeyEvent downEvent = new KeyEvent(now, now, KeyEvent.ACTION_DOWN,
+ keyCode, 0, 0, KeyCharacterMap.VIRTUAL_KEYBOARD, 0,
+ KeyEvent.FLAG_FROM_SYSTEM, InputDevice.SOURCE_KEYBOARD);
+ final KeyEvent upEvent = KeyEvent.changeAction(downEvent, KeyEvent.ACTION_UP);
- if (mLongPressOnHomeBehavior == LONG_PRESS_HOME_RECENT_SYSTEM_UI) {
- toggleRecentApps();
- } else if (mLongPressOnHomeBehavior == LONG_PRESS_HOME_ASSIST) {
- launchAssistAction(null, deviceId);
- }
- }
+ im.injectInputEvent(downEvent, InputManager.INJECT_INPUT_EVENT_MODE_ASYNC);
+ im.injectInputEvent(upEvent, InputManager.INJECT_INPUT_EVENT_MODE_ASYNC);
}
- private void handleDoubleTapOnHome() {
- if (mDoubleTapOnHomeBehavior == DOUBLE_TAP_HOME_RECENT_SYSTEM_UI) {
- mHomeConsumed = true;
- toggleRecentApps();
- }
+ private void launchCameraAction() {
+ sendCloseSystemWindows();
+ Intent intent = new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA);
+ startActivityAsUser(intent, UserHandle.CURRENT_OR_SELF);
}
+ private void performKeyAction(int behavior, KeyEvent event) {
+ switch (behavior) {
+ case KEY_ACTION_NOTHING:
+ break;
+ case KEY_ACTION_MENU:
+ triggerVirtualKeypress(KeyEvent.KEYCODE_MENU);
+ break;
+ case KEY_ACTION_APP_SWITCH:
+ toggleRecentApps();
+ break;
+ case KEY_ACTION_SEARCH:
+ launchAssistAction(null, event.getDeviceId());
+ break;
+ case KEY_ACTION_VOICE_SEARCH:
+ launchAssistLongPressAction();
+ break;
+ case KEY_ACTION_IN_APP_SEARCH:
+ triggerVirtualKeypress(KeyEvent.KEYCODE_SEARCH);
+ break;
+ case KEY_ACTION_LAUNCH_CAMERA:
+ launchCameraAction();
+ break;
+ case KEY_ACTION_SLEEP:
+ mPowerManager.goToSleep(SystemClock.uptimeMillis());
+ break;
+ case KEY_ACTION_LAST_APP:
+ ActionUtils.switchToLastApp(mContext, mCurrentUserId);
+ break;
+ default:
+ break;
+ }
+ }
+
private final Runnable mHomeDoubleTapTimeoutRunnable = new Runnable() {
@Override
public void run() {
@@ -1460,7 +1749,14 @@ public class PhoneWindowManager implements WindowManagerPolicy {
mUseTvRouting = AudioSystem.getPlatformType(mContext) == AudioSystem.PLATFORM_TELEVISION;
- readConfigurationDependentBehaviors();
+ mDeviceHardwareKeys = mContext.getResources().getInteger(
+ com.android.internal.R.integer.config_deviceHardwareKeys);
+ mHasRemovableLid = mContext.getResources().getBoolean(
+ com.android.internal.R.bool.config_hasRemovableLid);
+ mBackKillTimeout = mContext.getResources().getInteger(
+ com.android.internal.R.integer.config_backKillTimeout);
+
+ updateKeyAssignments();
mAccessibilityManager = (AccessibilityManager) context.getSystemService(
Context.ACCESSIBILITY_SERVICE);
@@ -1506,7 +1802,15 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
@Override
public void onSwipeFromRight() {
- if (mNavigationBar != null && !mNavigationBarOnBottom) {
+ if (mNavigationBar != null && !mNavigationBarOnBottom &&
+ !mNavigationBarLeftInLandscape) {
+ requestTransientBars(mNavigationBar);
+ }
+ }
+ @Override
+ public void onSwipeFromLeft() {
+ if (mNavigationBar != null && !mNavigationBarOnBottom &&
+ mNavigationBarLeftInLandscape) {
requestTransientBars(mNavigationBar);
}
}
@@ -1534,6 +1838,11 @@ public class PhoneWindowManager implements WindowManagerPolicy {
mWindowManagerFuncs.registerPointerEventListener(mSystemGestures);
mVibrator = (Vibrator)context.getSystemService(Context.VIBRATOR_SERVICE);
+
+ /* Register for WIFI Display Intents */
+ IntentFilter wifiDisplayFilter = new IntentFilter(ACTION_WIFI_DISPLAY_VIDEO);
+ Intent wifidisplayIntent = context.registerReceiver(
+ mWifiDisplayReceiver, wifiDisplayFilter);
mLongPressVibePattern = getLongIntArray(mContext.getResources(),
com.android.internal.R.array.config_longPressVibePattern);
mVirtualKeyVibePattern = getLongIntArray(mContext.getResources(),
@@ -1567,27 +1876,125 @@ public class PhoneWindowManager implements WindowManagerPolicy {
mWindowManagerInternal.registerAppTransitionListener(
mStatusBarController.getAppTransitionListener());
+
+ String deviceKeyHandlerLib = mContext.getResources().getString(
+ com.android.internal.R.string.config_deviceKeyHandlerLib);
+
+ String deviceKeyHandlerClass = mContext.getResources().getString(
+ com.android.internal.R.string.config_deviceKeyHandlerClass);
+
+ if (!deviceKeyHandlerLib.isEmpty() && !deviceKeyHandlerClass.isEmpty()) {
+ DexClassLoader loader = new DexClassLoader(deviceKeyHandlerLib,
+ new ContextWrapper(mContext).getCacheDir().getAbsolutePath(),
+ null,
+ ClassLoader.getSystemClassLoader());
+ try {
+ Class<?> klass = loader.loadClass(deviceKeyHandlerClass);
+ Constructor<?> constructor = klass.getConstructor(Context.class);
+ mDeviceKeyHandler = (DeviceKeyHandler) constructor.newInstance(
+ mContext);
+ if(DEBUG) Slog.d(TAG, "Device key handler loaded");
+ } catch (Exception e) {
+ Slog.w(TAG, "Could not instantiate device key handler "
+ + deviceKeyHandlerClass + " from class "
+ + deviceKeyHandlerLib, e);
+ }
+ }
+
}
- /**
- * Read values from config.xml that may be overridden depending on
- * the configuration of the device.
- * eg. Disable long press on home goes to recents on sw600dp.
- */
- private void readConfigurationDependentBehaviors() {
+ private void updateKeyAssignments() {
+ int activeHardwareKeys = mDeviceHardwareKeys;
+
+ if (mDevForceNavbar) {
+ activeHardwareKeys = 0;
+ }
+ final boolean hasMenu = (activeHardwareKeys & KEY_MASK_MENU) != 0;
+ final boolean hasHome = (activeHardwareKeys & KEY_MASK_HOME) != 0;
+ final boolean hasAssist = (activeHardwareKeys & KEY_MASK_ASSIST) != 0;
+ final boolean hasAppSwitch = (activeHardwareKeys & KEY_MASK_APP_SWITCH) != 0;
+
+ final ContentResolver resolver = mContext.getContentResolver();
+
+ // Initialize all assignments to sane defaults.
+ mPressOnMenuBehavior = KEY_ACTION_MENU;
+
+ mLongPressOnMenuBehavior = mContext.getResources().getInteger(
+ com.android.internal.R.integer.config_longPressOnMenuBehavior);
+
+ if (mLongPressOnMenuBehavior == KEY_ACTION_NOTHING &&
+ (hasMenu && !hasAssist)) {
+ mLongPressOnMenuBehavior = KEY_ACTION_SEARCH;
+ }
+ mPressOnAssistBehavior = KEY_ACTION_SEARCH;
+ mLongPressOnAssistBehavior = KEY_ACTION_VOICE_SEARCH;
+ mPressOnAppSwitchBehavior = KEY_ACTION_APP_SWITCH;
+ mLongPressOnAppSwitchBehavior = mContext.getResources().getInteger(
+ com.android.internal.R.integer.config_longPressOnAppSwitchBehavior);
+
mLongPressOnHomeBehavior = mContext.getResources().getInteger(
com.android.internal.R.integer.config_longPressOnHomeBehavior);
- if (mLongPressOnHomeBehavior < LONG_PRESS_HOME_NOTHING ||
- mLongPressOnHomeBehavior > LONG_PRESS_HOME_ASSIST) {
- mLongPressOnHomeBehavior = LONG_PRESS_HOME_NOTHING;
+ if (mLongPressOnHomeBehavior < KEY_ACTION_NOTHING ||
+ mLongPressOnHomeBehavior > KEY_ACTION_SLEEP) {
+ mLongPressOnHomeBehavior = KEY_ACTION_NOTHING;
}
mDoubleTapOnHomeBehavior = mContext.getResources().getInteger(
com.android.internal.R.integer.config_doubleTapOnHomeBehavior);
- if (mDoubleTapOnHomeBehavior < DOUBLE_TAP_HOME_NOTHING ||
- mDoubleTapOnHomeBehavior > DOUBLE_TAP_HOME_RECENT_SYSTEM_UI) {
- mDoubleTapOnHomeBehavior = LONG_PRESS_HOME_NOTHING;
+ if (mDoubleTapOnHomeBehavior < KEY_ACTION_NOTHING ||
+ mDoubleTapOnHomeBehavior > KEY_ACTION_SLEEP) {
+ mDoubleTapOnHomeBehavior = KEY_ACTION_NOTHING;
+ }
+
+ boolean hasPermanentMenu = false;
+
+ // Check for custom assignments and whether KEY_ACTION_MENU is assigned.
+ if (hasHome) {
+ mLongPressOnHomeBehavior = CMSettings.System.getIntForUser(resolver,
+ CMSettings.System.KEY_HOME_LONG_PRESS_ACTION,
+ mLongPressOnHomeBehavior, UserHandle.USER_CURRENT);
+ mDoubleTapOnHomeBehavior = CMSettings.System.getIntForUser(resolver,
+ CMSettings.System.KEY_HOME_DOUBLE_TAP_ACTION,
+ mDoubleTapOnHomeBehavior, UserHandle.USER_CURRENT);
+
+ hasPermanentMenu = mLongPressOnHomeBehavior == KEY_ACTION_MENU
+ || mDoubleTapOnHomeBehavior == KEY_ACTION_MENU;
+ }
+ if (hasMenu) {
+ mPressOnMenuBehavior = CMSettings.System.getIntForUser(resolver,
+ CMSettings.System.KEY_MENU_ACTION,
+ mPressOnMenuBehavior, UserHandle.USER_CURRENT);
+ mLongPressOnMenuBehavior = CMSettings.System.getIntForUser(resolver,
+ CMSettings.System.KEY_MENU_LONG_PRESS_ACTION,
+ mLongPressOnMenuBehavior, UserHandle.USER_CURRENT);
+
+ hasPermanentMenu |= mPressOnMenuBehavior == KEY_ACTION_MENU
+ || mLongPressOnMenuBehavior == KEY_ACTION_MENU;
+ }
+ if (hasAssist) {
+ mPressOnAssistBehavior = CMSettings.System.getIntForUser(resolver,
+ CMSettings.System.KEY_ASSIST_ACTION,
+ mPressOnAssistBehavior, UserHandle.USER_CURRENT);
+ mLongPressOnAssistBehavior = CMSettings.System.getIntForUser(resolver,
+ CMSettings.System.KEY_ASSIST_LONG_PRESS_ACTION,
+ mLongPressOnAssistBehavior, UserHandle.USER_CURRENT);
+
+ hasPermanentMenu |= mPressOnAssistBehavior == KEY_ACTION_MENU
+ || mLongPressOnAssistBehavior == KEY_ACTION_MENU;
}
+ if (hasAppSwitch) {
+ mPressOnAppSwitchBehavior = CMSettings.System.getIntForUser(resolver,
+ CMSettings.System.KEY_APP_SWITCH_ACTION,
+ mPressOnAppSwitchBehavior, UserHandle.USER_CURRENT);
+ mLongPressOnAppSwitchBehavior = CMSettings.System.getIntForUser(resolver,
+ CMSettings.System.KEY_APP_SWITCH_LONG_PRESS_ACTION,
+ mLongPressOnAppSwitchBehavior, UserHandle.USER_CURRENT);
+
+ hasPermanentMenu |= mPressOnAppSwitchBehavior == KEY_ACTION_MENU
+ || mLongPressOnAppSwitchBehavior == KEY_ACTION_MENU;
+ }
+
+ mHasPermanentMenuKey = hasPermanentMenu;
}
@Override
@@ -1696,7 +2103,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
* navigation bar and touch exploration is not enabled
*/
private boolean canHideNavigationBar() {
- return mHasNavigationBar
+ return hasNavigationBar()
&& !mAccessibilityManager.isTouchExplorationEnabled();
}
@@ -1718,6 +2125,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
public void updateSettings() {
ContentResolver resolver = mContext.getContentResolver();
boolean updateRotation = false;
+ int mDeviceHardwareWakeKeys = mContext.getResources().getInteger(
+ com.android.internal.R.integer.config_deviceHardwareWakeKeys);
synchronized (mLock) {
mEndcallBehavior = Settings.System.getIntForUser(resolver,
Settings.System.END_BUTTON_BEHAVIOR,
@@ -1727,6 +2136,33 @@ public class PhoneWindowManager implements WindowManagerPolicy {
Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR,
Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_DEFAULT,
UserHandle.USER_CURRENT);
+ mHomeWakeScreen = (CMSettings.System.getIntForUser(resolver,
+ CMSettings.System.HOME_WAKE_SCREEN, 1, UserHandle.USER_CURRENT) == 1) &&
+ ((mDeviceHardwareWakeKeys & KEY_MASK_HOME) != 0);
+ mBackWakeScreen = (CMSettings.System.getIntForUser(resolver,
+ CMSettings.System.BACK_WAKE_SCREEN, 0, UserHandle.USER_CURRENT) == 1) &&
+ ((mDeviceHardwareWakeKeys & KEY_MASK_BACK) != 0);
+ mMenuWakeScreen = (CMSettings.System.getIntForUser(resolver,
+ CMSettings.System.MENU_WAKE_SCREEN, 0, UserHandle.USER_CURRENT) == 1) &&
+ ((mDeviceHardwareWakeKeys & KEY_MASK_MENU) != 0);
+ mAssistWakeScreen = (CMSettings.System.getIntForUser(resolver,
+ CMSettings.System.ASSIST_WAKE_SCREEN, 0, UserHandle.USER_CURRENT) == 1) &&
+ ((mDeviceHardwareWakeKeys & KEY_MASK_ASSIST) != 0);
+ mAppSwitchWakeScreen = (CMSettings.System.getIntForUser(resolver,
+ CMSettings.System.APP_SWITCH_WAKE_SCREEN, 0, UserHandle.USER_CURRENT) == 1) &&
+ ((mDeviceHardwareWakeKeys & KEY_MASK_APP_SWITCH) != 0);
+ mCameraWakeScreen = (CMSettings.System.getIntForUser(resolver,
+ CMSettings.System.CAMERA_WAKE_SCREEN, 0, UserHandle.USER_CURRENT) == 1) &&
+ ((mDeviceHardwareWakeKeys & KEY_MASK_CAMERA) != 0);
+ mCameraSleepOnRelease = (CMSettings.System.getIntForUser(resolver,
+ CMSettings.System.CAMERA_SLEEP_ON_RELEASE, 0, UserHandle.USER_CURRENT) == 1);
+ mCameraLaunch = (CMSettings.System.getIntForUser(resolver,
+ CMSettings.System.CAMERA_LAUNCH, 0, UserHandle.USER_CURRENT) == 1);
+ mVolumeWakeScreen = (CMSettings.System.getIntForUser(resolver,
+ CMSettings.System.VOLUME_WAKE_SCREEN, 0, UserHandle.USER_CURRENT) == 1) &&
+ ((mDeviceHardwareWakeKeys & KEY_MASK_VOLUME) != 0);
+ mVolBtnMusicControls = (CMSettings.System.getIntForUser(resolver,
+ CMSettings.System.VOLBTN_MUSIC_CONTROLS, 1, UserHandle.USER_CURRENT) == 1);
// Configure wake gesture.
boolean wakeGestureEnabledSetting = Settings.Secure.getIntForUser(resolver,
@@ -1737,6 +2173,30 @@ public class PhoneWindowManager implements WindowManagerPolicy {
updateWakeGestureListenerLp();
}
+ final boolean useEdgeService = CMSettings.System.getIntForUser(resolver,
+ CMSettings.System.USE_EDGE_SERVICE_FOR_GESTURES, 1, UserHandle.USER_CURRENT) == 1;
+ if (useEdgeService ^ mUsingEdgeGestureServiceForGestures && mSystemReady) {
+ if (!mUsingEdgeGestureServiceForGestures && useEdgeService) {
+ mUsingEdgeGestureServiceForGestures = true;
+ mWindowManagerFuncs.unregisterPointerEventListener(mSystemGestures);
+ } else if (mUsingEdgeGestureServiceForGestures && !useEdgeService) {
+ mUsingEdgeGestureServiceForGestures = false;
+ mWindowManagerFuncs.registerPointerEventListener(mSystemGestures);
+ }
+ updateEdgeGestureListenerState();
+ }
+
+ boolean devForceNavbar = CMSettings.Secure.getIntForUser(resolver,
+ CMSettings.Secure.DEV_FORCE_SHOW_NAVBAR, 0, UserHandle.USER_CURRENT) == 1;
+ if (devForceNavbar != mDevForceNavbar) {
+ mDevForceNavbar = devForceNavbar;
+ }
+
+ mNavigationBarLeftInLandscape = CMSettings.System.getIntForUser(resolver,
+ CMSettings.System.NAVBAR_LEFT_IN_LANDSCAPE, 0, UserHandle.USER_CURRENT) == 1;
+
+ updateKeyAssignments();
+
// Configure rotation lock.
int userRotation = Settings.System.getIntForUser(resolver,
Settings.System.USER_ROTATION, Surface.ROTATION_0,
@@ -1755,6 +2215,9 @@ public class PhoneWindowManager implements WindowManagerPolicy {
updateOrientationListenerLp();
}
+ mUserRotationAngles = Settings.System.getInt(resolver,
+ Settings.System.ACCELEROMETER_ROTATION_ANGLES, -1);
+
if (mSystemReady) {
int pointerLocation = Settings.System.getIntForUser(resolver,
Settings.System.POINTER_LOCATION, 0, UserHandle.USER_CURRENT);
@@ -1779,7 +2242,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
}
synchronized (mWindowManagerFuncs.getWindowManagerLock()) {
- PolicyControl.reloadFromSetting(mContext);
+ WindowManagerPolicyControl.reloadFromSetting(mContext);
}
if (updateRotation) {
updateRotation(true);
@@ -2040,13 +2503,16 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
}
+ private boolean isBuiltInKeyboardVisible() {
+ return mHaveBuiltInKeyboard && !isHidden(mLidKeyboardAccessibility);
+ }
+
/** {@inheritDoc} */
@Override
public void adjustConfigurationLw(Configuration config, int keyboardPresence,
int navigationPresence) {
mHaveBuiltInKeyboard = (keyboardPresence & PRESENCE_INTERNAL) != 0;
- readConfigurationDependentBehaviors();
readLidState();
applyLidSwitchState();
@@ -2188,7 +2654,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
@Override
public int getNonDecorDisplayWidth(int fullWidth, int fullHeight, int rotation) {
- if (mHasNavigationBar) {
+ if (hasNavigationBar()) {
// For a basic navigation bar, when we are in landscape mode we place
// the navigation bar to the side.
if (mNavigationBarCanMove && fullWidth > fullHeight) {
@@ -2200,7 +2666,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
@Override
public int getNonDecorDisplayHeight(int fullWidth, int fullHeight, int rotation) {
- if (mHasNavigationBar) {
+ if (hasNavigationBar()) {
// For a basic navigation bar, when we are in portrait mode we place
// the navigation bar to the bottom.
if (!mNavigationBarCanMove || fullWidth < fullHeight) {
@@ -2498,7 +2964,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
if (win.getAttrs().windowAnimations != 0) {
return 0;
}
- // This can be on either the bottom or the right.
+ // This can be on either the bottom, left, or the right.
if (mNavigationBarOnBottom) {
if (transit == TRANSIT_EXIT
|| transit == TRANSIT_HIDE) {
@@ -2510,10 +2976,12 @@ public class PhoneWindowManager implements WindowManagerPolicy {
} else {
if (transit == TRANSIT_EXIT
|| transit == TRANSIT_HIDE) {
- return R.anim.dock_right_exit;
+ return mNavigationBarLeftInLandscape
+ ? R.anim.dock_left_exit : R.anim.dock_right_exit;
} else if (transit == TRANSIT_ENTER
|| transit == TRANSIT_SHOW) {
- return R.anim.dock_right_enter;
+ return mNavigationBarLeftInLandscape
+ ? R.anim.dock_left_enter : R.anim.dock_right_enter;
}
}
}
@@ -2601,9 +3069,12 @@ public class PhoneWindowManager implements WindowManagerPolicy {
@Override
- public Animation createForceHideWallpaperExitAnimation(boolean goingToNotificationShade) {
+ public Animation createForceHideWallpaperExitAnimation(boolean goingToNotificationShade,
+ boolean keyguardShowingMedia) {
if (goingToNotificationShade) {
return null;
+ } else if (keyguardShowingMedia) {
+ return AnimationUtils.loadAnimation(mContext, R.anim.lock_screen_wallpaper_exit_noop);
} else {
return AnimationUtils.loadAnimation(mContext, R.anim.lock_screen_wallpaper_exit);
}
@@ -2651,12 +3122,14 @@ public class PhoneWindowManager implements WindowManagerPolicy {
@Override
public long interceptKeyBeforeDispatching(WindowState win, KeyEvent event, int policyFlags) {
final boolean keyguardOn = keyguardOn();
- final int keyCode = event.getKeyCode();
final int repeatCount = event.getRepeatCount();
final int metaState = event.getMetaState();
final int flags = event.getFlags();
final boolean down = event.getAction() == KeyEvent.ACTION_DOWN;
final boolean canceled = event.isCanceled();
+ final boolean longPress = (flags & KeyEvent.FLAG_LONG_PRESS) != 0;
+ final boolean virtualKey = event.getDeviceId() == KeyCharacterMap.VIRTUAL_KEYBOARD;
+ final int keyCode = event.getKeyCode();
if (DEBUG_INPUT) {
Log.d(TAG, "interceptKeyTi keyCode=" + keyCode + " down=" + down + " repeatCount="
@@ -2664,6 +3137,19 @@ public class PhoneWindowManager implements WindowManagerPolicy {
+ " canceled=" + canceled);
}
+ // If the boot mode is power off alarm, we should not dispatch the several physical keys
+ // in power off alarm UI to avoid pausing power off alarm UI.
+ int isPowerOffAlarmMode = Settings.System.getInt(mContext.getContentResolver(),
+ Settings.System.POWER_OFF_ALARM_MODE, 0);
+ if (DEBUG_INPUT) { Log.d(TAG, "intercept Dispatching isPowerOffAlarmMode = " +
+ isPowerOffAlarmMode); }
+
+ if (isPowerOffAlarmMode == 1 && (keyCode == KeyEvent.KEYCODE_HOME
+ || keyCode == KeyEvent.KEYCODE_SEARCH
+ || keyCode == KeyEvent.KEYCODE_MENU)) {
+ return -1; // ignore the physical key here
+ }
+
// If we think we might have a volume down & power key chord on the way
// but we're not sure, then tell the dispatcher to wait a little while and
// try again later before dispatching.
@@ -2691,6 +3177,10 @@ public class PhoneWindowManager implements WindowManagerPolicy {
mPendingMetaAction = false;
}
+ if (keyCode == KeyEvent.KEYCODE_BACK && !down) {
+ mHandler.removeCallbacks(mBackLongPress);
+ }
+
// First we always handle the home key here, so applications
// can never break it, although if keyguard is on, we do let
// it handle it, because that gives us the correct 5 second
@@ -2700,7 +3190,9 @@ public class PhoneWindowManager implements WindowManagerPolicy {
// If we have released the home key, and didn't do anything else
// while it was pressed, then it is time to go home!
if (!down) {
- cancelPreloadRecentApps();
+ if (mDoubleTapOnHomeBehavior != KEY_ACTION_APP_SWITCH) {
+ cancelPreloadRecentApps();
+ }
mHomePressed = false;
if (mHomeConsumed) {
@@ -2723,7 +3215,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
// Delay handling home if a double-tap is possible.
- if (mDoubleTapOnHomeBehavior != DOUBLE_TAP_HOME_NOTHING) {
+ if (mDoubleTapOnHomeBehavior != KEY_ACTION_NOTHING) {
mHandler.removeCallbacks(mHomeDoubleTapTimeoutRunnable); // just in case
mHomeDoubleTapPending = true;
mHandler.postDelayed(mHomeDoubleTapTimeoutRunnable,
@@ -2761,44 +3253,83 @@ public class PhoneWindowManager implements WindowManagerPolicy {
if (mHomeDoubleTapPending) {
mHomeDoubleTapPending = false;
mHandler.removeCallbacks(mHomeDoubleTapTimeoutRunnable);
- handleDoubleTapOnHome();
- } else if (mLongPressOnHomeBehavior == LONG_PRESS_HOME_RECENT_SYSTEM_UI
- || mDoubleTapOnHomeBehavior == DOUBLE_TAP_HOME_RECENT_SYSTEM_UI) {
+ performKeyAction(mDoubleTapOnHomeBehavior, event);
+ mHomeConsumed = mDoubleTapOnHomeBehavior != KEY_ACTION_SLEEP;
+ } else if (mLongPressOnHomeBehavior == KEY_ACTION_APP_SWITCH
+ || mDoubleTapOnHomeBehavior == KEY_ACTION_APP_SWITCH) {
preloadRecentApps();
}
- } else if ((event.getFlags() & KeyEvent.FLAG_LONG_PRESS) != 0) {
- if (!keyguardOn) {
- handleLongPressOnHome(event.getDeviceId());
+ } else if (longPress) {
+ if (!keyguardOn && !mHomeConsumed &&
+ mLongPressOnHomeBehavior != KEY_ACTION_NOTHING) {
+ if (mLongPressOnHomeBehavior != KEY_ACTION_APP_SWITCH) {
+ cancelPreloadRecentApps();
+ }
+ mHomePressed = true;
+ performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false);
+ performKeyAction(mLongPressOnHomeBehavior, event);
+ mHomeConsumed = true;
}
}
return -1;
} else if (keyCode == KeyEvent.KEYCODE_MENU) {
// Hijack modified menu keys for debugging features
final int chordBug = KeyEvent.META_SHIFT_ON;
+ if (virtualKey || keyguardOn) {
+ // Let the app handle the key
+ return 0;
+ }
- if (down && repeatCount == 0) {
- if (mEnableShiftMenuBugReports && (metaState & chordBug) == chordBug) {
- Intent intent = new Intent(Intent.ACTION_BUG_REPORT);
- mContext.sendOrderedBroadcastAsUser(intent, UserHandle.CURRENT,
- null, null, null, 0, null, null);
- return -1;
- } else if (SHOW_PROCESSES_ON_ALT_MENU &&
- (metaState & KeyEvent.META_ALT_ON) == KeyEvent.META_ALT_ON) {
- Intent service = new Intent();
- service.setClassName(mContext, "com.android.server.LoadAverageService");
- ContentResolver res = mContext.getContentResolver();
- boolean shown = Settings.Global.getInt(
- res, Settings.Global.SHOW_PROCESSES, 0) != 0;
- if (!shown) {
- mContext.startService(service);
- } else {
- mContext.stopService(service);
+ if (down) {
+ if (mPressOnMenuBehavior == KEY_ACTION_APP_SWITCH
+ || mLongPressOnMenuBehavior == KEY_ACTION_APP_SWITCH) {
+ preloadRecentApps();
+ }
+ if (repeatCount == 0) {
+ mMenuPressed = true;
+ if (mEnableShiftMenuBugReports && (metaState & chordBug) == chordBug) {
+ Intent intent = new Intent(Intent.ACTION_BUG_REPORT);
+ mContext.sendOrderedBroadcastAsUser(intent, UserHandle.CURRENT,
+ null, null, null, 0, null, null);
+ return -1;
+ } else if (SHOW_PROCESSES_ON_ALT_MENU &&
+ (metaState & KeyEvent.META_ALT_ON) == KeyEvent.META_ALT_ON) {
+ Intent service = new Intent();
+ service.setClassName(mContext, "com.android.server.LoadAverageService");
+ ContentResolver res = mContext.getContentResolver();
+ boolean shown = Settings.Global.getInt(
+ res, Settings.Global.SHOW_PROCESSES, 0) != 0;
+ if (!shown) {
+ mContext.startService(service);
+ } else {
+ mContext.stopService(service);
+ }
+ Settings.Global.putInt(
+ res, Settings.Global.SHOW_PROCESSES, shown ? 0 : 1);
+ return -1;
+ }
+ } else if (longPress) {
+ if (!keyguardOn && mLongPressOnMenuBehavior != KEY_ACTION_NOTHING) {
+ if (mLongPressOnMenuBehavior != KEY_ACTION_APP_SWITCH) {
+ cancelPreloadRecentApps();
+ }
+ performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false);
+ performKeyAction(mLongPressOnMenuBehavior, event);
+ mMenuPressed = false;
+ return -1;
}
- Settings.Global.putInt(
- res, Settings.Global.SHOW_PROCESSES, shown ? 0 : 1);
- return -1;
}
}
+ if (!down && mMenuPressed) {
+ if (mPressOnMenuBehavior != KEY_ACTION_APP_SWITCH) {
+ cancelPreloadRecentApps();
+ }
+ mMenuPressed = false;
+ if (!canceled) {
+ performKeyAction(mPressOnMenuBehavior, event);
+ }
+ }
+ return -1;
} else if (keyCode == KeyEvent.KEYCODE_SEARCH) {
if (down) {
if (repeatCount == 0) {
@@ -2815,10 +3346,34 @@ public class PhoneWindowManager implements WindowManagerPolicy {
return 0;
} else if (keyCode == KeyEvent.KEYCODE_APP_SWITCH) {
if (!keyguardOn) {
- if (down && repeatCount == 0) {
- preloadRecentApps();
- } else if (!down) {
- toggleRecentApps();
+ if (down) {
+ if (mPressOnAppSwitchBehavior == KEY_ACTION_APP_SWITCH
+ || mLongPressOnAppSwitchBehavior == KEY_ACTION_APP_SWITCH) {
+ preloadRecentApps();
+ }
+ if (repeatCount == 0) {
+ mAppSwitchLongPressed = false;
+ } else if (longPress) {
+ if (mLongPressOnAppSwitchBehavior != KEY_ACTION_NOTHING) {
+ if (mLongPressOnAppSwitchBehavior != KEY_ACTION_APP_SWITCH) {
+ cancelPreloadRecentApps();
+ }
+ performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false);
+ performKeyAction(mLongPressOnAppSwitchBehavior, event);
+ mAppSwitchLongPressed = true;
+ }
+ }
+ } else {
+ if (mAppSwitchLongPressed) {
+ mAppSwitchLongPressed = false;
+ } else {
+ if (mPressOnAppSwitchBehavior != KEY_ACTION_APP_SWITCH) {
+ cancelPreloadRecentApps();
+ }
+ if (!canceled) {
+ performKeyAction(mPressOnAppSwitchBehavior, event);
+ }
+ }
}
}
return -1;
@@ -2835,20 +3390,31 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
} else if (keyCode == KeyEvent.KEYCODE_ASSIST) {
if (down) {
+ if (mPressOnAssistBehavior == KEY_ACTION_APP_SWITCH
+ || mLongPressOnAssistBehavior == KEY_ACTION_APP_SWITCH) {
+ preloadRecentApps();
+ }
if (repeatCount == 0) {
mAssistKeyLongPressed = false;
- } else if (repeatCount == 1) {
- mAssistKeyLongPressed = true;
- if (!keyguardOn) {
- launchAssistLongPressAction();
+ } else if (longPress) {
+ if (!keyguardOn && mLongPressOnAssistBehavior != KEY_ACTION_NOTHING) {
+ if (mLongPressOnAssistBehavior != KEY_ACTION_APP_SWITCH) {
+ cancelPreloadRecentApps();
+ }
+ performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false);
+ performKeyAction(mLongPressOnAssistBehavior, event);
+ mAssistKeyLongPressed = true;
}
}
} else {
if (mAssistKeyLongPressed) {
mAssistKeyLongPressed = false;
} else {
- if (!keyguardOn) {
- launchAssistAction(null, event.getDeviceId());
+ if (mPressOnAssistBehavior != KEY_ACTION_APP_SWITCH) {
+ cancelPreloadRecentApps();
+ }
+ if (!canceled) {
+ performKeyAction(mPressOnAssistBehavior, event);
}
}
}
@@ -2921,6 +3487,13 @@ public class PhoneWindowManager implements WindowManagerPolicy {
launchAssistAction(Intent.EXTRA_ASSIST_INPUT_HINT_KEYBOARD, event.getDeviceId());
}
return -1;
+ } else if (keyCode == KeyEvent.KEYCODE_BACK) {
+ if (unpinActivity(true) || CMSettings.Secure.getInt(mContext.getContentResolver(),
+ CMSettings.Secure.KILL_APP_LONGPRESS_BACK, 0) == 1) {
+ if (down && repeatCount == 0) {
+ mHandler.postDelayed(mBackLongPress, mBackKillTimeout);
+ }
+ }
}
// Shortcuts are invoked through Search+key, so intercept those here
@@ -3029,6 +3602,18 @@ public class PhoneWindowManager implements WindowManagerPolicy {
return -1;
}
+ // Specific device key handling
+ if (mDeviceKeyHandler != null) {
+ try {
+ // The device only should consume known keys.
+ if (mDeviceKeyHandler.handleKeyEvent(event)) {
+ return -1;
+ }
+ } catch (Exception e) {
+ Slog.w(TAG, "Could not dispatch event to device key handler", e);
+ }
+ }
+
// Reserve all the META modifier combos for system behavior
if ((metaState & KeyEvent.META_META_ON) != 0) {
return -1;
@@ -3038,6 +3623,22 @@ public class PhoneWindowManager implements WindowManagerPolicy {
return 0;
}
+ private boolean unpinActivity(boolean checkOnly) {
+ if (!hasNavigationBar()) {
+ try {
+ if (ActivityManagerNative.getDefault().isInLockTaskMode()) {
+ if (!checkOnly) {
+ ActivityManagerNative.getDefault().stopLockTaskModeOnCurrent();
+ }
+ return true;
+ }
+ } catch (RemoteException e) {
+ // ignore
+ }
+ }
+ return false;
+ }
+
/** {@inheritDoc} */
@Override
public KeyEvent dispatchUnhandledKey(WindowState win, KeyEvent event, int policyFlags) {
@@ -3314,8 +3915,9 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
sendCloseSystemWindows(SYSTEM_DIALOG_REASON_HOME_KEY);
hideRecentApps(false, true);
- } else {
- // Otherwise, just launch Home
+ } else if (mScreenOnFully) {
+ // check if screen is fully on before going home
+ // to avoid hardware home button wake going home
sendCloseSystemWindows(SYSTEM_DIALOG_REASON_HOME_KEY);
startDockOrHome(true /*fromHomeKey*/, awakenFromDreams);
}
@@ -3403,6 +4005,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
mNavigationBarController.adjustSystemUiVisibilityLw(mLastSystemUiFlags, visibility);
mRecentsVisible = (visibility & View.RECENT_APPS_VISIBLE) > 0;
+ updateEdgeGestureListenerState();
+
// Reset any bits in mForceClearingStatusBarVisibility that
// are now clear.
mResettingSystemUiFlags &= visibility;
@@ -3415,8 +4019,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
@Override
public void getInsetHintLw(WindowManager.LayoutParams attrs, int displayRotation,
Rect outContentInsets, Rect outStableInsets, Rect outOutsets) {
- final int fl = PolicyControl.getWindowFlags(null, attrs);
- final int sysuiVis = PolicyControl.getSystemUiVisibility(null, attrs);
+ final int fl = WindowManagerPolicyControl.getWindowFlags(null, attrs);
+ final int sysuiVis = WindowManagerPolicyControl.getSystemUiVisibility(null, attrs);
final int systemUiVisibility = (sysuiVis | attrs.subtreeSystemUiVisibility);
final boolean useOutsets = outOutsets != null && shouldUseOutsets(attrs, fl);
@@ -3535,13 +4139,13 @@ public class PhoneWindowManager implements WindowManagerPolicy {
mRestrictedScreenWidth = mSystemGestures.screenWidth = mUnrestrictedScreenWidth;
mRestrictedScreenHeight = mSystemGestures.screenHeight = mUnrestrictedScreenHeight;
mDockLeft = mContentLeft = mVoiceContentLeft = mStableLeft = mStableFullscreenLeft
- = mCurLeft = mUnrestrictedScreenLeft;
+ = mCurLeft = mForceImmersiveLeft = mUnrestrictedScreenLeft;
mDockTop = mContentTop = mVoiceContentTop = mStableTop = mStableFullscreenTop
- = mCurTop = mUnrestrictedScreenTop;
+ = mCurTop = mForceImmersiveTop = mUnrestrictedScreenTop;
mDockRight = mContentRight = mVoiceContentRight = mStableRight = mStableFullscreenRight
- = mCurRight = displayWidth - overscanRight;
+ = mCurRight = mForceImmersiveRight = displayWidth - overscanRight;
mDockBottom = mContentBottom = mVoiceContentBottom = mStableBottom = mStableFullscreenBottom
- = mCurBottom = displayHeight - overscanBottom;
+ = mCurBottom = mForceImmersiveBottom = displayHeight - overscanBottom;
mDockLayer = 0x10000000;
mStatusBarLayer = -1;
@@ -3626,6 +4230,34 @@ public class PhoneWindowManager implements WindowManagerPolicy {
// we can tell the app that it is covered by it.
mSystemBottom = mTmpNavigationFrame.top;
}
+ } else if (mNavigationBarLeftInLandscape) {
+ // Landscape screen; nav bar goes to the left.
+ int right = overscanLeft + mNavigationBarWidthForRotation[displayRotation];
+ mTmpNavigationFrame.set(0, 0, right, displayHeight);
+ mStableLeft = mStableFullscreenLeft = mTmpNavigationFrame.right;
+ mStableFullscreenLeft = mTmpNavigationFrame.right;
+ if (transientNavBarShowing) {
+ mNavigationBarController.setBarShowingLw(true);
+ } else if (navVisible) {
+ mNavigationBarController.setBarShowingLw(true);
+ mDockLeft = mTmpNavigationFrame.right;
+ mRestrictedScreenLeft = mDockLeft;
+ mRestrictedScreenWidth = mDockRight - mRestrictedScreenLeft;
+ mRestrictedOverscanScreenLeft = mRestrictedScreenLeft;
+ mRestrictedOverscanScreenWidth = mDockRight
+ - mRestrictedOverscanScreenLeft;
+ } else {
+ // We currently want to hide the navigation UI.
+ mNavigationBarController.setBarShowingLw(false);
+ }
+
+ if (navVisible && !navTranslucent && !mNavigationBar.isAnimatingLw()
+ && !mNavigationBarController.wasRecentlyTranslucent()) {
+ // If the nav bar is currently requested to be visible,
+ // and not in the process of animating on or off, then
+ // we can tell the app that it is covered by it.
+ mSystemLeft = mTmpNavigationFrame.right;
+ }
} else {
// Landscape screen; nav bar goes to the right.
int left = displayWidth - overscanRight
@@ -3817,6 +4449,19 @@ public class PhoneWindowManager implements WindowManagerPolicy {
? attached.getFrameLw() : df);
}
+ private void applyForceImmersiveMode(int pfl, Rect r) {
+ if ((pfl & PRIVATE_FLAG_STATUS_HIDE_FORCED) != 0) {
+ r.top = mForceImmersiveTop;
+ }
+ if ((pfl & PRIVATE_FLAG_NAV_HIDE_FORCED) != 0) {
+ if (mNavigationBarOnBottom) {
+ r.bottom = mForceImmersiveBottom;
+ } else {
+ r.right = mForceImmersiveRight;
+ }
+ }
+ }
+
private void applyStableConstraints(int sysui, int fl, Rect r) {
if ((sysui & View.SYSTEM_UI_FLAG_LAYOUT_STABLE) != 0) {
// If app is requesting a stable layout, don't let the
@@ -3861,9 +4506,10 @@ public class PhoneWindowManager implements WindowManagerPolicy {
offsetInputMethodWindowLw(mLastInputMethodWindow);
}
- final int fl = PolicyControl.getWindowFlags(win, attrs);
+ final int fl = WindowManagerPolicyControl.getWindowFlags(win, attrs);
+ final int pfl = WindowManagerPolicyControl.getPrivateWindowFlags(win, attrs);
final int sim = attrs.softInputMode;
- final int sysUiFl = PolicyControl.getSystemUiVisibility(win, null);
+ final int sysUiFl = WindowManagerPolicyControl.getSystemUiVisibility(win, null);
final Rect pf = mTmpParentFrame;
final Rect df = mTmpDisplayFrame;
@@ -4044,7 +4690,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
of.bottom = mUnrestrictedScreenTop + mUnrestrictedScreenHeight;
}
- if ((fl & FLAG_FULLSCREEN) == 0) {
+ if ((fl & FLAG_FULLSCREEN) == 0
+ || (pfl & PRIVATE_FLAG_WAS_NOT_FULLSCREEN) != 0) {
if (win.isVoiceInteraction()) {
cf.left = mVoiceContentLeft;
cf.top = mVoiceContentTop;
@@ -4062,6 +4709,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
cf.right = mContentRight;
cf.bottom = mContentBottom;
}
+
+ applyForceImmersiveMode(pfl, cf);
}
} else {
// Full screen windows are always given a layout that is as if the
@@ -4082,6 +4731,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
} else {
vf.set(cf);
}
+
+ applyForceImmersiveMode(pfl, vf);
}
} else if ((fl & FLAG_LAYOUT_IN_SCREEN) != 0 || (sysUiFl
& (View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
@@ -4196,6 +4847,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
} else {
vf.set(cf);
}
+
+ applyForceImmersiveMode(pfl, vf);
} else if (attached != null) {
if (DEBUG_LAYOUT) Slog.v(TAG, "layoutWindowLw(" + attrs.getTitle() +
"): attached to " + attached);
@@ -4253,6 +4906,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
} else {
vf.set(cf);
}
+
+ applyForceImmersiveMode(pfl, vf);
}
}
}
@@ -4324,6 +4979,9 @@ public class PhoneWindowManager implements WindowManagerPolicy {
if (mContentBottom > top) {
mContentBottom = top;
}
+ if (mForceImmersiveBottom > top) {
+ mForceImmersiveBottom = top;
+ }
if (mVoiceContentBottom > top) {
mVoiceContentBottom = top;
}
@@ -4381,7 +5039,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
WindowState attached) {
if (DEBUG_LAYOUT) Slog.i(TAG, "Win " + win + ": isVisibleOrBehindKeyguardLw="
+ win.isVisibleOrBehindKeyguardLw());
- final int fl = PolicyControl.getWindowFlags(win, attrs);
+ final int fl = WindowManagerPolicyControl.getWindowFlags(win, attrs);
if (mTopFullscreenOpaqueWindowState == null
&& win.isVisibleLw() && attrs.type == TYPE_INPUT_METHOD) {
mForcingShowNavBar = true;
@@ -4566,7 +5224,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
mLastSystemUiFlags, mLastSystemUiFlags);
}
} else if (mTopFullscreenOpaqueWindowState != null) {
- final int fl = PolicyControl.getWindowFlags(null, lp);
+ final int fl = WindowManagerPolicyControl.getWindowFlags(null, lp);
if (localLOGV) {
Slog.d(TAG, "frame: " + mTopFullscreenOpaqueWindowState.getFrameLw()
+ " shown frame: " + mTopFullscreenOpaqueWindowState.getShownFrameLw());
@@ -4671,6 +5329,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
// update since mAllowLockscreenWhenOn might have changed
updateLockScreenTimeout();
+ updateEdgeGestureListenerState();
return changes;
}
@@ -4681,22 +5340,24 @@ public class PhoneWindowManager implements WindowManagerPolicy {
*/
private boolean setKeyguardOccludedLw(boolean isOccluded) {
boolean wasOccluded = mKeyguardOccluded;
- boolean showing = mKeyguardDelegate.isShowing();
- if (wasOccluded && !isOccluded && showing) {
+ if (wasOccluded && !isOccluded) {
mKeyguardOccluded = false;
mKeyguardDelegate.setOccluded(false);
- mStatusBar.getAttrs().privateFlags |= PRIVATE_FLAG_KEYGUARD;
- mStatusBar.getAttrs().flags |= FLAG_SHOW_WALLPAPER;
- return true;
- } else if (!wasOccluded && isOccluded && showing) {
+ if (mKeyguardDelegate.isShowing()) {
+ mStatusBar.getAttrs().privateFlags |= PRIVATE_FLAG_KEYGUARD;
+ mStatusBar.getAttrs().flags |= FLAG_SHOW_WALLPAPER;
+ return true;
+ }
+ } else if (!wasOccluded && isOccluded) {
mKeyguardOccluded = true;
mKeyguardDelegate.setOccluded(true);
- mStatusBar.getAttrs().privateFlags &= ~PRIVATE_FLAG_KEYGUARD;
- mStatusBar.getAttrs().flags &= ~FLAG_SHOW_WALLPAPER;
- return true;
- } else {
- return false;
+ if (mKeyguardDelegate.isShowing()) {
+ mStatusBar.getAttrs().privateFlags &= ~PRIVATE_FLAG_KEYGUARD;
+ mStatusBar.getAttrs().flags &= ~FLAG_SHOW_WALLPAPER;
+ return true;
+ }
}
+ return false;
}
private boolean isStatusBarKeyguard() {
@@ -4813,6 +5474,20 @@ public class PhoneWindowManager implements WindowManagerPolicy {
setHdmiPlugged(!mHdmiPlugged);
}
+ /**
+ * @return Whether music is being played right now "locally" (e.g. on the device's speakers
+ * or wired headphones) or "remotely" (e.g. on a device using the Cast protocol and
+ * controlled by this device, or through remote submix).
+ */
+ private boolean isMusicActive() {
+ final AudioManager am = (AudioManager)mContext.getSystemService(Context.AUDIO_SERVICE);
+ if (am == null) {
+ Log.w(TAG, "isMusicActive: couldn't get AudioManager reference");
+ return false;
+ }
+ return am.isMusicActive();
+ }
+
final Object mScreenshotLock = new Object();
ServiceConnection mScreenshotConnection = null;
@@ -4894,6 +5569,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
final boolean down = event.getAction() == KeyEvent.ACTION_DOWN;
final boolean canceled = event.isCanceled();
final int keyCode = event.getKeyCode();
+ final int scanCode = event.getScanCode();
final boolean isInjected = (policyFlags & WindowManagerPolicy.FLAG_INJECTED) != 0;
@@ -4925,8 +5601,9 @@ public class PhoneWindowManager implements WindowManagerPolicy {
// If we're currently dozing with the screen on and the keyguard showing, pass the key
// to the application but preserve its wake key status to make sure we still move
// from dozing to fully interactive if we would normally go from off to fully
- // interactive.
+ // interactive, unless the user has explicitly disabled this wake key.
result = ACTION_PASS_TO_USER;
+ isWakeKey = isWakeKey && isWakeKeyEnabled(keyCode);
} else {
// When the screen is off and the key is not injected, determine whether
// to wake the device but don't pass the key to the application.
@@ -4950,6 +5627,18 @@ public class PhoneWindowManager implements WindowManagerPolicy {
&& (policyFlags & WindowManagerPolicy.FLAG_VIRTUAL) != 0
&& event.getRepeatCount() == 0;
+ // Specific device key handling
+ if (mDeviceKeyHandler != null) {
+ try {
+ // The device only should consume known keys.
+ if (mDeviceKeyHandler.handleKeyEvent(event)) {
+ return 0;
+ }
+ } catch (Exception e) {
+ Slog.w(TAG, "Could not dispatch event to device key handler", e);
+ }
+ }
+
// Handle special keys.
switch (keyCode) {
case KeyEvent.KEYCODE_VOLUME_DOWN:
@@ -4959,6 +5648,17 @@ public class PhoneWindowManager implements WindowManagerPolicy {
// On TVs volume keys never go to the foreground app
result &= ~ACTION_PASS_TO_USER;
}
+ // Eat all down & up keys when using volume wake.
+ // This disables volume control, music control, and "beep" on key up.
+ if (isWakeKey && mVolumeWakeScreen) {
+ mVolumeWakeTriggered = true;
+ break;
+ } else if (mVolumeWakeTriggered && !down) {
+ result &= ~ACTION_PASS_TO_USER;
+ mVolumeWakeTriggered = false;
+ break;
+ }
+
if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) {
if (down) {
if (interactive && !mScreenshotChordVolumeDownKeyTriggered
@@ -5018,23 +5718,101 @@ public class PhoneWindowManager implements WindowManagerPolicy {
break;
}
}
+ }
+
+ // Disable music and volume control when used as wake key
+ if ((result & ACTION_PASS_TO_USER) == 0 && !mVolumeWakeScreen) {
+ boolean mayChangeVolume = false;
+
+ if (isMusicActive()) {
+ if (mVolBtnMusicControls && (keyCode != KeyEvent.KEYCODE_VOLUME_MUTE)) {
+ // Detect long key presses.
+ if (down) {
+ mIsLongPress = false;
+ // TODO: Long press of MUTE could be mapped to KEYCODE_MEDIA_PLAY_PAUSE
+ int newKeyCode = event.getKeyCode() == KeyEvent.KEYCODE_VOLUME_UP ?
+ KeyEvent.KEYCODE_MEDIA_NEXT : KeyEvent.KEYCODE_MEDIA_PREVIOUS;
+ scheduleLongPressKeyEvent(event, newKeyCode);
+ // Consume key down events of all presses.
+ break;
+ } else {
+ mHandler.removeMessages(MSG_DISPATCH_VOLKEY_WITH_WAKE_LOCK);
+ // Consume key up events of long presses only.
+ if (mIsLongPress) {
+ break;
+ }
+ // Change volume only on key up events of short presses.
+ mayChangeVolume = true;
+ }
+ } else {
+ // Long key press detection not applicable, change volume only
+ // on key down events
+ mayChangeVolume = down;
+ }
+ }
- if ((result & ACTION_PASS_TO_USER) == 0) {
+ if (mayChangeVolume) {
if (mUseTvRouting) {
dispatchDirectAudioEvent(event);
} else {
// If we aren't passing to the user and no one else
- // handled it send it to the session manager to
- // figure out.
+ // handled it send it to the session manager to figure
+ // out.
+
+ // Rewrite the event to use key-down as sendVolumeKeyEvent will
+ // only change the volume on key down.
+ KeyEvent newEvent = new KeyEvent(KeyEvent.ACTION_DOWN, keyCode);
MediaSessionLegacyHelper.getHelper(mContext)
- .sendVolumeKeyEvent(event, true);
+ .sendVolumeKeyEvent(newEvent, true);
}
- break;
}
+ break;
}
break;
}
+ case KeyEvent.KEYCODE_HOME:
+ if (down && !interactive && mHomeWakeScreen) {
+ isWakeKey = true;
+ }
+ break;
+
+ case KeyEvent.KEYCODE_FOCUS:
+ if (down && !interactive && mCameraSleepOnRelease) {
+ mIsFocusPressed = true;
+ } else if ((event.getAction() == KeyEvent.ACTION_UP)
+ && mScreenOnFully && mIsFocusPressed) {
+ // Check if screen is fully on before letting the device go to sleep
+ mPowerManager.goToSleep(SystemClock.uptimeMillis());
+ mIsFocusPressed = false;
+ }
+ break;
+
+ case KeyEvent.KEYCODE_CAMERA:
+ if (down && mIsFocusPressed) {
+ mIsFocusPressed = false;
+ }
+ if (down) {
+ mIsLongPress = false;
+ scheduleLongPressKeyEvent(event, KeyEvent.KEYCODE_CAMERA);
+ // Consume key down events of all presses.
+ break;
+ } else {
+ mHandler.removeMessages(MSG_CAMERA_LONG_PRESS);
+ // Consume key up events of long presses only.
+ if (mIsLongPress && mCameraLaunch) {
+ Intent intent;
+ if (keyguardActive) {
+ intent = new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE);
+ } else {
+ intent = new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA);
+ }
+ isWakeKey = true;
+ startActivityAsUser(intent, UserHandle.CURRENT_OR_SELF);
+ }
+ }
+ break;
+
case KeyEvent.KEYCODE_ENDCALL: {
result &= ~ACTION_PASS_TO_USER;
if (down) {
@@ -5073,6 +5851,12 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
case KeyEvent.KEYCODE_POWER: {
+ if (mTopFullscreenOpaqueWindowState != null &&
+ (mTopFullscreenOpaqueWindowState.getAttrs().privateFlags
+ & WindowManager.LayoutParams.PRIVATE_FLAG_PREVENT_POWER_KEY) != 0
+ && mScreenOnFully) {
+ return result;
+ }
result &= ~ACTION_PASS_TO_USER;
isWakeKey = false; // wake-up will be handled separately
if (down) {
@@ -5178,6 +5962,19 @@ public class PhoneWindowManager implements WindowManagerPolicy {
return result;
}
+ private void scheduleLongPressKeyEvent(KeyEvent origEvent, int keyCode) {
+ KeyEvent event = new KeyEvent(origEvent.getDownTime(), origEvent.getEventTime(),
+ origEvent.getAction(), keyCode, 0);
+ Message msg;
+ if (keyCode == KeyEvent.KEYCODE_CAMERA) {
+ msg = mHandler.obtainMessage(MSG_CAMERA_LONG_PRESS, event);
+ } else {
+ msg = mHandler.obtainMessage(MSG_DISPATCH_VOLKEY_WITH_WAKE_LOCK, event);
+ }
+ msg.setAsynchronous(true);
+ mHandler.sendMessageDelayed(msg, ViewConfiguration.getLongPressTimeout());
+ }
+
/**
* Returns true if the key can have global actions attached to it.
* We reserve all power management keys for the system since they require
@@ -5195,6 +5992,34 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
/**
+ * Check if the given keyCode represents a key that is considered a wake key
+ * and is currently enabled by the user in Settings or for another reason.
+ */
+ private boolean isWakeKeyEnabled(int keyCode) {
+ switch (keyCode) {
+ case KeyEvent.KEYCODE_VOLUME_UP:
+ case KeyEvent.KEYCODE_VOLUME_DOWN:
+ case KeyEvent.KEYCODE_VOLUME_MUTE:
+ // Volume keys are still wake keys if the device is docked.
+ return mVolumeWakeScreen || mDockMode != Intent.EXTRA_DOCK_STATE_UNDOCKED;
+ case KeyEvent.KEYCODE_BACK:
+ return mBackWakeScreen;
+ case KeyEvent.KEYCODE_MENU:
+ return mMenuWakeScreen;
+ case KeyEvent.KEYCODE_ASSIST:
+ return mAssistWakeScreen;
+ case KeyEvent.KEYCODE_APP_SWITCH:
+ return mAppSwitchWakeScreen;
+ case KeyEvent.KEYCODE_CAMERA:
+ case KeyEvent.KEYCODE_FOCUS:
+ return mCameraWakeScreen;
+ case KeyEvent.KEYCODE_HOME:
+ return mHomeWakeScreen;
+ }
+ return true;
+ }
+
+ /**
* When the screen is off we ignore some keys that might otherwise typically
* be considered wake keys. We filter them out here.
*
@@ -5207,9 +6032,9 @@ public class PhoneWindowManager implements WindowManagerPolicy {
case KeyEvent.KEYCODE_VOLUME_UP:
case KeyEvent.KEYCODE_VOLUME_DOWN:
case KeyEvent.KEYCODE_VOLUME_MUTE:
- return mDockMode != Intent.EXTRA_DOCK_STATE_UNDOCKED;
+ return mVolumeWakeScreen || mDockMode != Intent.EXTRA_DOCK_STATE_UNDOCKED;
- // ignore media and camera keys
+ // ignore media keys
case KeyEvent.KEYCODE_MUTE:
case KeyEvent.KEYCODE_HEADSETHOOK:
case KeyEvent.KEYCODE_MEDIA_PLAY:
@@ -5222,8 +6047,21 @@ public class PhoneWindowManager implements WindowManagerPolicy {
case KeyEvent.KEYCODE_MEDIA_RECORD:
case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD:
case KeyEvent.KEYCODE_MEDIA_AUDIO_TRACK:
- case KeyEvent.KEYCODE_CAMERA:
return false;
+
+ case KeyEvent.KEYCODE_BACK:
+ return mBackWakeScreen;
+ case KeyEvent.KEYCODE_MENU:
+ return mMenuWakeScreen;
+ case KeyEvent.KEYCODE_ASSIST:
+ return mAssistWakeScreen;
+ case KeyEvent.KEYCODE_APP_SWITCH:
+ return mAppSwitchWakeScreen;
+ case KeyEvent.KEYCODE_CAMERA:
+ case KeyEvent.KEYCODE_FOCUS:
+ return mCameraWakeScreen;
+ case KeyEvent.KEYCODE_HOME:
+ return mHomeWakeScreen;
}
return true;
}
@@ -5268,7 +6106,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
IDreamManager dreamManager = getDreamManager();
try {
- if (dreamManager != null && dreamManager.isDreaming()) {
+ if (dreamManager != null && dreamManager.isDreaming() && !dreamManager.isDozing()) {
return true;
}
} catch (RemoteException e) {
@@ -5430,6 +6268,10 @@ public class PhoneWindowManager implements WindowManagerPolicy {
// current user.
mSettingsObserver.onChange(false);
+ if (mGlobalActions != null) {
+ mGlobalActions.updatePowerMenuActions();
+ }
+
// force a re-application of focused window sysui visibility.
// the window may never have been shown for this user
// e.g. the keyguard when going through the new-user setup flow
@@ -5477,6 +6319,24 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
}
+
+ BroadcastReceiver mWifiDisplayReceiver = new BroadcastReceiver() {
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ if (action.equals(ACTION_WIFI_DISPLAY_VIDEO)) {
+ int state = intent.getIntExtra("state", 0);
+ if(state == 1) {
+ mWifiDisplayConnected = true;
+ } else {
+ mWifiDisplayConnected = false;
+ }
+ mWifiDisplayCustomRotation =
+ intent.getIntExtra("wfd_UIBC_rot", -1);
+ updateRotation(true);
+ }
+ }
+ };
+
// Called on the PowerManager's Notifier thread.
@Override
public void startedGoingToSleep(int why) {
@@ -5671,10 +6531,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
if (!mKeyguardDrawnOnce && mAwake) {
mKeyguardDrawnOnce = true;
enableScreen = true;
- if (mBootMessageNeedsHiding) {
- mBootMessageNeedsHiding = false;
- hideBootMessages();
- }
} else {
enableScreen = false;
}
@@ -5694,9 +6550,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
private void handleHideBootMessage() {
synchronized (mLock) {
- if (!mKeyguardDrawnOnce) {
- mBootMessageNeedsHiding = true;
- return; // keyguard hasn't drawn the first time yet, not done booting
+ if (!mKeyguardDrawComplete) {
+ return; // keyguard hasn't completed drawing, not done booting.
}
}
@@ -5829,8 +6684,11 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
final int preferredRotation;
- if (mLidState == LID_OPEN && mLidOpenRotation >= 0) {
- // Ignore sensor when lid switch is open and rotation is forced.
+ if ((mLidState == LID_OPEN && mLidOpenRotation >= 0)
+ && !(mHasRemovableLid
+ && mDockMode == Intent.EXTRA_DOCK_STATE_UNDOCKED)) {
+ // Ignore sensor when lid switch is open and rotation is forced
+ // and a removable lid was not undocked.
preferredRotation = mLidOpenRotation;
} else if (mDockMode == Intent.EXTRA_DOCK_STATE_CAR
&& (mCarDockEnablesAccelerometer || mCarDockRotation >= 0)) {
@@ -5848,10 +6706,13 @@ public class PhoneWindowManager implements WindowManagerPolicy {
// enable 180 degree rotation while docked.
preferredRotation = mDeskDockEnablesAccelerometer
? sensorRotation : mDeskDockRotation;
- } else if (mHdmiPlugged && mDemoHdmiRotationLock) {
+ } else if ((mHdmiPlugged || mWifiDisplayConnected) && mDemoHdmiRotationLock) {
// Ignore sensor when plugged into HDMI when demo HDMI rotation lock enabled.
// Note that the dock orientation overrides the HDMI orientation.
preferredRotation = mDemoHdmiRotation;
+ } else if (mWifiDisplayConnected && (mWifiDisplayCustomRotation > -1)) {
+ // Ignore sensor when WFD is active and UIBC rotation is enabled
+ preferredRotation = mWifiDisplayCustomRotation;
} else if (mHdmiPlugged && mDockMode == Intent.EXTRA_DOCK_STATE_UNDOCKED
&& mUndockedHdmiRotation >= 0) {
// Ignore sensor when plugged into HDMI and an undocked orientation has
@@ -5889,10 +6750,14 @@ public class PhoneWindowManager implements WindowManagerPolicy {
mAllowAllRotations = mContext.getResources().getBoolean(
com.android.internal.R.bool.config_allowAllRotations) ? 1 : 0;
}
- if (sensorRotation != Surface.ROTATION_180
- || mAllowAllRotations == 1
- || orientation == ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR
- || orientation == ActivityInfo.SCREEN_ORIENTATION_FULL_USER) {
+
+ // use sensor orientation if it's forced, or if the user has allowed it
+ boolean useSensorRotation =
+ orientation == ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR
+ || orientation == ActivityInfo.SCREEN_ORIENTATION_FULL_USER
+ || RotationPolicy.isRotationAllowed(sensorRotation, mUserRotationAngles,
+ mAllowAllRotations != 0);
+ if (useSensorRotation) {
preferredRotation = sensorRotation;
} else {
preferredRotation = lastRotation;
@@ -6060,6 +6925,9 @@ public class PhoneWindowManager implements WindowManagerPolicy {
mKeyguardDelegate = new KeyguardServiceDelegate(mContext);
mKeyguardDelegate.onSystemReady();
+ mEdgeGestureManager = EdgeGestureManager.getInstance();
+ mEdgeGestureManager.setEdgeGestureActivationListener(mEdgeGestureActivationListener);
+
readCameraLensCoverState();
updateUiMode();
boolean bindKeyguardNow;
@@ -6295,14 +7163,37 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
private void applyLidSwitchState() {
- if (mLidState == LID_CLOSED && mLidControlsSleep) {
- mPowerManager.goToSleep(SystemClock.uptimeMillis(),
- PowerManager.GO_TO_SLEEP_REASON_LID_SWITCH,
- PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE);
- }
+ mPowerManager.setKeyboardVisibility(isBuiltInKeyboardVisible());
+ if (mLidControlsSleep) {
+ IDreamManager dreamManager = getDreamManager();
+ if (dreamManager != null) {
+ try {
+ dreamManager.setLidState(mLidState);
+ } catch (RemoteException e) {
+ }
+ }
- synchronized (mLock) {
- updateWakeGestureListenerLp();
+ if (mLidState == LID_CLOSED) {
+ if (mFocusedWindow != null && (mFocusedWindow.getAttrs().flags
+ & WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON) != 0) {
+ // if an application requests that the screen be turned on
+ // and there's a closed device cover, don't turn the screen off!
+ return;
+ }
+
+ TelecomManager telephonyService = getTelecommService();
+ if (!(telephonyService == null
+ || telephonyService.isRinging())) {
+ mPowerManager.goToSleep(SystemClock.uptimeMillis(),
+ PowerManager.GO_TO_SLEEP_REASON_LID_SWITCH,
+ PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE);
+ }
+
+ }
+
+ synchronized (mLock) {
+ updateWakeGestureListenerLp();
+ }
}
}
@@ -6377,7 +7268,9 @@ public class PhoneWindowManager implements WindowManagerPolicy {
ActivityInfo ai = null;
ResolveInfo info = mContext.getPackageManager().resolveActivityAsUser(
intent,
- PackageManager.MATCH_DEFAULT_ONLY | PackageManager.GET_META_DATA,
+ PackageManager.MATCH_DEFAULT_ONLY
+ | PackageManager.GET_META_DATA
+ | PackageManager.GET_RESOLVED_FILTER,
mCurrentUserId);
if (info != null) {
ai = info.activityInfo;
@@ -6600,13 +7493,38 @@ public class PhoneWindowManager implements WindowManagerPolicy {
return 0;
}
- int tmpVisibility = PolicyControl.getSystemUiVisibility(win, null)
+ int tmpVisibility = WindowManagerPolicyControl.getSystemUiVisibility(win, null)
& ~mResettingSystemUiFlags
& ~mForceClearedSystemUiFlags;
+ boolean wasCleared = mClearedBecauseOfForceShow;
if (mForcingShowNavBar && win.getSurfaceLayer() < mForcingShowNavBarLayer) {
- tmpVisibility &= ~PolicyControl.adjustClearableFlags(win, View.SYSTEM_UI_CLEARABLE_FLAGS);
+ tmpVisibility &=
+ ~WindowManagerPolicyControl.adjustClearableFlags(win, View.SYSTEM_UI_CLEARABLE_FLAGS);
+ mClearedBecauseOfForceShow = true;
+ } else {
+ mClearedBecauseOfForceShow = false;
}
- tmpVisibility = updateLightStatusBarLw(tmpVisibility);
+
+ // The window who requested navbar force showing disappeared and next window wants
+ // to hide navbar. Instead of hiding we will make it transient. SystemUI will take care
+ // about hiding after timeout. This should not happen if next window is keyguard because
+ // transient state have more priority than translucent (why?) and cause bad UX
+ if (wasCleared && !mClearedBecauseOfForceShow
+ && (tmpVisibility & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0) {
+ mNavigationBarController.showTransient();
+ tmpVisibility |= View.NAVIGATION_BAR_TRANSIENT;
+ mWindowManagerFuncs.addSystemUIVisibilityFlag(View.NAVIGATION_BAR_TRANSIENT);
+ }
+
+ boolean topWindowWasKeyguard = mTopWindowIsKeyguard;
+ mTopWindowIsKeyguard = (win.getAttrs().privateFlags & PRIVATE_FLAG_KEYGUARD) != 0;
+ if (topWindowWasKeyguard && !mTopWindowIsKeyguard
+ && (tmpVisibility & View.SYSTEM_UI_FLAG_FULLSCREEN) != 0) {
+ mStatusBarController.showTransient();
+ tmpVisibility |= View.STATUS_BAR_TRANSIENT;
+ mWindowManagerFuncs.addSystemUIVisibilityFlag(View.STATUS_BAR_TRANSIENT);
+ }
+
final int visibility = updateSystemBarsLw(win, mLastSystemUiFlags, tmpVisibility);
final int diff = visibility ^ mLastSystemUiFlags;
final boolean needsMenu = win.getNeedsMenuLw(mTopFullscreenOpaqueWindowState);
@@ -6645,7 +7563,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
// If the top fullscreen-or-dimming window is also the top fullscreen, respect
// its light flag.
vis &= ~View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
- vis |= PolicyControl.getSystemUiVisibility(statusColorWin, null)
+ vis |= WindowManagerPolicyControl.getSystemUiVisibility(statusColorWin, null)
& View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
} else if (statusColorWin != null && statusColorWin.isDimming()) {
// Otherwise if it's dimming, clear the light flag.
@@ -6688,7 +7606,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
(vis & View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY) != 0;
boolean hideStatusBarWM =
mTopFullscreenOpaqueWindowState != null &&
- (PolicyControl.getWindowFlags(mTopFullscreenOpaqueWindowState, null)
+ (WindowManagerPolicyControl.getWindowFlags(mTopFullscreenOpaqueWindowState, null)
& WindowManager.LayoutParams.FLAG_FULLSCREEN) != 0;
boolean hideStatusBarSysui =
(vis & View.SYSTEM_UI_FLAG_FULLSCREEN) != 0;
@@ -6784,6 +7702,15 @@ public class PhoneWindowManager implements WindowManagerPolicy {
// overridden by qemu.hw.mainkeys in the emulator.
@Override
public boolean hasNavigationBar() {
+ return mHasNavigationBar || mDevForceNavbar;
+ }
+
+ @Override
+ public boolean hasPermanentMenuKey() {
+ return !hasNavigationBar() && mHasPermanentMenuKey;
+ }
+
+ public boolean needsNavigationBar() {
return mHasNavigationBar;
}
@@ -7017,7 +7944,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
mGlobalKeyManager.dump(prefix, pw);
mStatusBarController.dump(pw, prefix);
mNavigationBarController.dump(pw, prefix);
- PolicyControl.dump(prefix, pw);
+ WindowManagerPolicyControl.dump(prefix, pw);
if (mWakeGestureListener != null) {
mWakeGestureListener.dump(pw, prefix);
diff --git a/services/core/java/com/android/server/policy/PolicyControl.java b/services/core/java/com/android/server/policy/PolicyControl.java
index dbafc42..0f6fc58 100644
--- a/services/core/java/com/android/server/policy/PolicyControl.java
+++ b/services/core/java/com/android/server/policy/PolicyControl.java
@@ -125,6 +125,10 @@ public class PolicyControl {
}
}
+ public static boolean isImmersiveFiltersActive() {
+ return sImmersiveStatusFilter != null || sImmersiveNavigationFilter != null;
+ }
+
public static void dump(String prefix, PrintWriter pw) {
dump("sImmersiveStatusFilter", sImmersiveStatusFilter, prefix, pw);
dump("sImmersiveNavigationFilter", sImmersiveNavigationFilter, prefix, pw);
diff --git a/services/core/java/com/android/server/policy/SystemGesturesPointerEventListener.java b/services/core/java/com/android/server/policy/SystemGesturesPointerEventListener.java
index e4bd21d..5e694a5 100644
--- a/services/core/java/com/android/server/policy/SystemGesturesPointerEventListener.java
+++ b/services/core/java/com/android/server/policy/SystemGesturesPointerEventListener.java
@@ -42,6 +42,7 @@ public class SystemGesturesPointerEventListener implements PointerEventListener
private static final int SWIPE_FROM_TOP = 1;
private static final int SWIPE_FROM_BOTTOM = 2;
private static final int SWIPE_FROM_RIGHT = 3;
+ private static final int SWIPE_FROM_LEFT = 4;
private final Context mContext;
private final int mSwipeStartThreshold;
@@ -121,6 +122,9 @@ public class SystemGesturesPointerEventListener implements PointerEventListener
} else if (swipe == SWIPE_FROM_RIGHT) {
if (DEBUG) Slog.d(TAG, "Firing onSwipeFromRight");
mCallbacks.onSwipeFromRight();
+ } else if (swipe == SWIPE_FROM_LEFT) {
+ if (DEBUG) Slog.d(TAG, "Firing onSwipeFromLeft");
+ mCallbacks.onSwipeFromLeft();
}
}
break;
@@ -203,6 +207,11 @@ public class SystemGesturesPointerEventListener implements PointerEventListener
&& elapsed < SWIPE_TIMEOUT_MS) {
return SWIPE_FROM_BOTTOM;
}
+ if (fromX <= mSwipeStartThreshold
+ && x > fromX + mSwipeDistanceThreshold
+ && elapsed < SWIPE_TIMEOUT_MS) {
+ return SWIPE_FROM_LEFT;
+ }
if (fromX >= screenWidth - mSwipeStartThreshold
&& x < fromX - mSwipeDistanceThreshold
&& elapsed < SWIPE_TIMEOUT_MS) {
@@ -247,6 +256,7 @@ public class SystemGesturesPointerEventListener implements PointerEventListener
void onFling(int durationMs);
void onDown();
void onUpOrCancel();
+ void onSwipeFromLeft();
void onDebug();
}
}
diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
index 7ae3c79..936dcb1 100644
--- a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
@@ -364,7 +364,7 @@ public class KeyguardServiceDelegate {
public void showScrim() {
synchronized (mKeyguardState) {
- if (!mKeyguardState.deviceHasKeyguard) return;
+ if (!mKeyguardState.deviceHasKeyguard || !mScrim.isAttachedToWindow()) return;
mScrimHandler.post(new Runnable() {
@Override
public void run() {
diff --git a/services/core/java/com/android/server/power/Notifier.java b/services/core/java/com/android/server/power/Notifier.java
index 7108f4a..e0bb48f 100644
--- a/services/core/java/com/android/server/power/Notifier.java
+++ b/services/core/java/com/android/server/power/Notifier.java
@@ -29,10 +29,6 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.hardware.input.InputManagerInternal;
-import android.media.AudioManager;
-import android.media.Ringtone;
-import android.media.RingtoneManager;
-import android.net.Uri;
import android.os.BatteryStats;
import android.os.Handler;
import android.os.Looper;
@@ -78,8 +74,7 @@ final class Notifier {
private static final int MSG_USER_ACTIVITY = 1;
private static final int MSG_BROADCAST = 2;
- private static final int MSG_WIRELESS_CHARGING_STARTED = 3;
- private static final int MSG_SCREEN_BRIGHTNESS_BOOST_CHANGED = 4;
+ private static final int MSG_SCREEN_BRIGHTNESS_BOOST_CHANGED = 3;
private final Object mLock = new Object();
@@ -502,11 +497,6 @@ final class Notifier {
if (DEBUG) {
Slog.d(TAG, "onWirelessChargingStarted");
}
-
- mSuspendBlocker.acquire();
- Message msg = mHandler.obtainMessage(MSG_WIRELESS_CHARGING_STARTED);
- msg.setAsynchronous(true);
- mHandler.sendMessage(msg);
}
private void updatePendingBroadcastLocked() {
@@ -642,25 +632,6 @@ final class Notifier {
}
};
- private void playWirelessChargingStartedSound() {
- final boolean enabled = Settings.Global.getInt(mContext.getContentResolver(),
- Settings.Global.CHARGING_SOUNDS_ENABLED, 1) != 0;
- final String soundPath = Settings.Global.getString(mContext.getContentResolver(),
- Settings.Global.WIRELESS_CHARGING_STARTED_SOUND);
- if (enabled && soundPath != null) {
- final Uri soundUri = Uri.parse("file://" + soundPath);
- if (soundUri != null) {
- final Ringtone sfx = RingtoneManager.getRingtone(mContext, soundUri);
- if (sfx != null) {
- sfx.setStreamType(AudioManager.STREAM_SYSTEM);
- sfx.play();
- }
- }
- }
-
- mSuspendBlocker.release();
- }
-
private final class NotifierHandler extends Handler {
public NotifierHandler(Looper looper) {
super(looper, null, true /*async*/);
@@ -676,10 +647,6 @@ final class Notifier {
case MSG_BROADCAST:
sendNextBroadcast();
break;
-
- case MSG_WIRELESS_CHARGING_STARTED:
- playWirelessChargingStartedSound();
- break;
case MSG_SCREEN_BRIGHTNESS_BOOST_CHANGED:
sendBrightnessBoostChangedBroadcast();
break;
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index f7a8970..76d4a27 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -18,10 +18,12 @@ package com.android.server.power;
import android.app.ActivityManager;
import android.util.SparseIntArray;
+
import com.android.internal.app.IAppOpsService;
import com.android.internal.app.IBatteryStats;
import com.android.internal.os.BackgroundThread;
import com.android.server.EventLogTags;
+import com.android.server.LocalServices;
import com.android.server.ServiceThread;
import com.android.server.SystemService;
import com.android.server.am.BatteryStatsService;
@@ -29,6 +31,8 @@ import com.android.server.lights.Light;
import com.android.server.lights.LightsManager;
import com.android.server.Watchdog;
+import cyanogenmod.power.PerformanceManagerInternal;
+
import android.Manifest;
import android.app.AppOpsManager;
import android.content.BroadcastReceiver;
@@ -39,6 +43,9 @@ import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.database.ContentObserver;
+import android.hardware.Sensor;
+import android.hardware.SensorEvent;
+import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.hardware.SystemSensorManager;
import android.hardware.display.DisplayManagerInternal;
@@ -63,6 +70,7 @@ import android.os.UserHandle;
import android.os.WorkSource;
import android.provider.Settings;
import android.service.dreams.DreamManagerInternal;
+import android.telephony.TelephonyManager;
import android.util.EventLog;
import android.util.Slog;
import android.util.TimeUtils;
@@ -74,6 +82,7 @@ import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
+import cyanogenmod.providers.CMSettings;
import libcore.util.Objects;
import static android.os.PowerManagerInternal.POWER_HINT_INTERACTION;
@@ -100,6 +109,8 @@ public final class PowerManagerService extends SystemService
// Message: Sent when the screen brightness boost expires.
private static final int MSG_SCREEN_BRIGHTNESS_BOOST_TIMEOUT = 3;
+ private static final int MSG_WAKE_UP = 5;
+
// Dirty bit: mWakeLocks changed
private static final int DIRTY_WAKE_LOCKS = 1 << 0;
// Dirty bit: mWakefulness changed
@@ -156,9 +167,18 @@ public final class PowerManagerService extends SystemService
// Power features defined in hardware/libhardware/include/hardware/power.h.
private static final int POWER_FEATURE_DOUBLE_TAP_TO_WAKE = 1;
+ private static final int DEFAULT_BUTTON_ON_DURATION = 5 * 1000;
+
// Default setting for double tap to wake.
private static final int DEFAULT_DOUBLE_TAP_TO_WAKE = 0;
+ private static final int BUTTON_ON_DURATION = 5 * 1000;
+
+ private static final float PROXIMITY_NEAR_THRESHOLD = 5.0f;
+
+ // Max time (microseconds) to allow a CPU boost for
+ private static final int MAX_CPU_BOOST_TIME = 5000000;
+
private final Context mContext;
private final ServiceThread mHandlerThread;
private final PowerManagerHandler mHandler;
@@ -174,6 +194,16 @@ public final class PowerManagerService extends SystemService
private SettingsObserver mSettingsObserver;
private DreamManagerInternal mDreamManager;
private Light mAttentionLight;
+ private Light mButtonsLight;
+ private Light mKeyboardLight;
+ private Light mCapsLight;
+ private Light mFnLight;
+
+ private int mButtonTimeout;
+ private int mButtonBrightness;
+ private int mButtonBrightnessSettingDefault;
+ private int mKeyboardBrightness;
+ private int mKeyboardBrightnessSettingDefault;
private final Object mLock = new Object();
@@ -351,6 +381,9 @@ public final class PowerManagerService extends SystemService
// Whether device supports double tap to wake.
private boolean mSupportsDoubleTapWakeConfig;
+ // Default value for proximity prevent accidental wakeups
+ private boolean mProximityWakeEnabledByDefaultConfig;
+
// The screen off timeout setting value in milliseconds.
private int mScreenOffTimeoutSetting;
@@ -362,9 +395,12 @@ public final class PowerManagerService extends SystemService
private int mMaximumScreenOffTimeoutFromDeviceAdmin = Integer.MAX_VALUE;
// The stay on while plugged in setting.
- // A bitfield of battery conditions under which to make the screen stay on.
+ // 0: Not enabled; 1: debugging over usb; >2: charging.
private int mStayOnWhilePluggedInSetting;
+ // True if the device should wake up when plugged or unplugged
+ private int mWakeUpWhenPluggedOrUnpluggedSetting;
+
// True if the device should stay on.
private boolean mStayOn;
@@ -393,6 +429,11 @@ public final class PowerManagerService extends SystemService
// Use -1 to disable.
private int mScreenBrightnessOverrideFromWindowManager = -1;
+ // The button brightness setting override from the window manager
+ // to allow the current foreground activity to override the button brightness.
+ // Use -1 to disable.
+ private int mButtonBrightnessOverrideFromWindowManager = -1;
+
// The user activity timeout override from the window manager
// to allow the current foreground activity to override the user activity timeout.
// Use -1 to disable.
@@ -453,6 +494,9 @@ public final class PowerManagerService extends SystemService
private final ArrayList<PowerManagerInternal.LowPowerModeListener> mLowPowerModeListeners
= new ArrayList<PowerManagerInternal.LowPowerModeListener>();
+ //track the blocked uids.
+ private final ArrayList<Integer> mBlockedUids = new ArrayList<Integer>();
+
private native void nativeInit();
private static native void nativeAcquireSuspendBlocker(String name);
@@ -461,6 +505,19 @@ public final class PowerManagerService extends SystemService
private static native void nativeSetAutoSuspend(boolean enable);
private static native void nativeSendPowerHint(int hintId, int data);
private static native void nativeSetFeature(int featureId, int data);
+ private static native int nativeGetFeature(int featureId);
+
+ private boolean mKeyboardVisible = false;
+
+ private SensorManager mSensorManager;
+ private Sensor mProximitySensor;
+ private boolean mProximityWakeEnabled;
+ private int mProximityTimeOut;
+ private boolean mProximityWakeSupported;
+ android.os.PowerManager.WakeLock mProximityWakeLock;
+ SensorEventListener mProximityListener;
+
+ private PerformanceManagerInternal mPerf;
public PowerManagerService(Context context) {
super(context);
@@ -506,6 +563,7 @@ public final class PowerManagerService extends SystemService
userActivityNoUpdateLocked(
now, PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, Process.SYSTEM_UID);
updatePowerStateLocked();
+ mPerf = LocalServices.getService(PerformanceManagerInternal.class);
}
}
}
@@ -523,6 +581,8 @@ public final class PowerManagerService extends SystemService
mScreenBrightnessSettingMinimum = pm.getMinimumScreenBrightnessSetting();
mScreenBrightnessSettingMaximum = pm.getMaximumScreenBrightnessSetting();
mScreenBrightnessSettingDefault = pm.getDefaultScreenBrightnessSetting();
+ mButtonBrightnessSettingDefault = pm.getDefaultButtonBrightness();
+ mKeyboardBrightnessSettingDefault = pm.getDefaultKeyboardBrightness();
SensorManager sensorManager = new SystemSensorManager(mContext, mHandler.getLooper());
@@ -540,30 +600,40 @@ public final class PowerManagerService extends SystemService
mLightsManager = getLocalService(LightsManager.class);
mAttentionLight = mLightsManager.getLight(LightsManager.LIGHT_ID_ATTENTION);
+ mButtonsLight = mLightsManager.getLight(LightsManager.LIGHT_ID_BUTTONS);
+ mKeyboardLight = mLightsManager.getLight(LightsManager.LIGHT_ID_KEYBOARD);
+ mCapsLight = mLightsManager.getLight(LightsManager.LIGHT_ID_CAPS);
+ mFnLight = mLightsManager.getLight(LightsManager.LIGHT_ID_FUNC);
// Initialize display power management.
mDisplayManagerInternal.initPowerManagement(
mDisplayPowerCallbacks, mHandler, sensorManager);
- // Register for broadcasts from other components of the system.
- IntentFilter filter = new IntentFilter();
- filter.addAction(Intent.ACTION_BATTERY_CHANGED);
- filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
- mContext.registerReceiver(new BatteryReceiver(), filter, null, mHandler);
+ // Initialize proximity sensor
+ mSensorManager = (SensorManager) mContext.getSystemService(Context.SENSOR_SERVICE);
+ mProximitySensor = mSensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);
+ }
+
+ // Register for broadcasts from other components of the system.
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(Intent.ACTION_BATTERY_CHANGED);
+ filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
+ mContext.registerReceiver(new BatteryReceiver(), filter, null, mHandler);
- filter = new IntentFilter();
- filter.addAction(Intent.ACTION_DREAMING_STARTED);
- filter.addAction(Intent.ACTION_DREAMING_STOPPED);
- mContext.registerReceiver(new DreamReceiver(), filter, null, mHandler);
+ filter = new IntentFilter();
+ filter.addAction(Intent.ACTION_DREAMING_STARTED);
+ filter.addAction(Intent.ACTION_DREAMING_STOPPED);
+ mContext.registerReceiver(new DreamReceiver(), filter, null, mHandler);
- filter = new IntentFilter();
- filter.addAction(Intent.ACTION_USER_SWITCHED);
- mContext.registerReceiver(new UserSwitchedReceiver(), filter, null, mHandler);
+ filter = new IntentFilter();
+ filter.addAction(Intent.ACTION_USER_SWITCHED);
+ mContext.registerReceiver(new UserSwitchedReceiver(), filter, null, mHandler);
- filter = new IntentFilter();
- filter.addAction(Intent.ACTION_DOCK_EVENT);
- mContext.registerReceiver(new DockReceiver(), filter, null, mHandler);
+ filter = new IntentFilter();
+ filter.addAction(Intent.ACTION_DOCK_EVENT);
+ mContext.registerReceiver(new DockReceiver(), filter, null, mHandler);
+ synchronized (mLock) {
// Register for settings changes.
final ContentResolver resolver = mContext.getContentResolver();
resolver.registerContentObserver(Settings.Secure.getUriFor(
@@ -605,6 +675,22 @@ public final class PowerManagerService extends SystemService
resolver.registerContentObserver(Settings.Secure.getUriFor(
Settings.Secure.DOUBLE_TAP_TO_WAKE),
false, mSettingsObserver, UserHandle.USER_ALL);
+ resolver.registerContentObserver(CMSettings.Secure.getUriFor(
+ CMSettings.Secure.BUTTON_BRIGHTNESS),
+ false, mSettingsObserver, UserHandle.USER_ALL);
+ resolver.registerContentObserver(CMSettings.Secure.getUriFor(
+ CMSettings.Secure.KEYBOARD_BRIGHTNESS),
+ false, mSettingsObserver, UserHandle.USER_ALL);
+ resolver.registerContentObserver(CMSettings.Secure.getUriFor(
+ CMSettings.Secure.BUTTON_BACKLIGHT_TIMEOUT),
+ false, mSettingsObserver, UserHandle.USER_ALL);
+ resolver.registerContentObserver(CMSettings.System.getUriFor(
+ CMSettings.System.PROXIMITY_ON_WAKE),
+ false, mSettingsObserver, UserHandle.USER_ALL);
+ resolver.registerContentObserver(CMSettings.Global.getUriFor(
+ CMSettings.Global.WAKE_WHEN_PLUGGED_OR_UNPLUGGED),
+ false, mSettingsObserver, UserHandle.USER_ALL);
+
// Go.
readConfigurationLocked();
updateSettingsLocked();
@@ -652,6 +738,17 @@ public final class PowerManagerService extends SystemService
com.android.internal.R.fraction.config_maximumScreenDimRatio, 1, 1);
mSupportsDoubleTapWakeConfig = resources.getBoolean(
com.android.internal.R.bool.config_supportDoubleTapWake);
+ mProximityTimeOut = resources.getInteger(
+ org.cyanogenmod.platform.internal.R.integer.config_proximityCheckTimeout);
+ mProximityWakeSupported = resources.getBoolean(
+ org.cyanogenmod.platform.internal.R.bool.config_proximityCheckOnWake);
+ mProximityWakeEnabledByDefaultConfig = resources.getBoolean(
+ org.cyanogenmod.platform.internal.R.bool.config_proximityCheckOnWakeEnabledByDefault);
+ if (mProximityWakeSupported) {
+ PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
+ mProximityWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
+ "ProximityWakeLock");
+ }
}
private void updateSettingsLocked() {
@@ -676,9 +773,14 @@ public final class PowerManagerService extends SystemService
Settings.Secure.SLEEP_TIMEOUT, DEFAULT_SLEEP_TIMEOUT,
UserHandle.USER_CURRENT);
mStayOnWhilePluggedInSetting = Settings.Global.getInt(resolver,
- Settings.Global.STAY_ON_WHILE_PLUGGED_IN, BatteryManager.BATTERY_PLUGGED_AC);
+ Settings.Global.STAY_ON_WHILE_PLUGGED_IN, 0);
mTheaterModeEnabled = Settings.Global.getInt(mContext.getContentResolver(),
Settings.Global.THEATER_MODE_ON, 0) == 1;
+ mWakeUpWhenPluggedOrUnpluggedSetting = CMSettings.Global.getInt(resolver,
+ CMSettings.Global.WAKE_WHEN_PLUGGED_OR_UNPLUGGED,
+ (mWakeUpWhenPluggedOrUnpluggedConfig ? 1 : 0));
+ mProximityWakeEnabled = CMSettings.System.getInt(resolver,
+ CMSettings.System.PROXIMITY_ON_WAKE, mProximityWakeEnabledByDefaultConfig ? 1 : 0) == 1;
if (mSupportsDoubleTapWakeConfig) {
boolean doubleTapWakeEnabled = Settings.Secure.getIntForUser(resolver,
@@ -722,6 +824,17 @@ public final class PowerManagerService extends SystemService
updateLowPowerModeLocked();
}
+ mButtonTimeout = CMSettings.Secure.getIntForUser(resolver,
+ CMSettings.Secure.BUTTON_BACKLIGHT_TIMEOUT,
+ DEFAULT_BUTTON_ON_DURATION, UserHandle.USER_CURRENT);
+
+ mButtonBrightness = CMSettings.Secure.getIntForUser(resolver,
+ CMSettings.Secure.BUTTON_BRIGHTNESS, mButtonBrightnessSettingDefault,
+ UserHandle.USER_CURRENT);
+ mKeyboardBrightness = CMSettings.Secure.getIntForUser(resolver,
+ CMSettings.Secure.KEYBOARD_BRIGHTNESS, mKeyboardBrightnessSettingDefault,
+ UserHandle.USER_CURRENT);
+
mDirty |= DIRTY_SETTINGS;
}
@@ -733,6 +846,7 @@ public final class PowerManagerService extends SystemService
// Turn setting off if powered
Settings.Global.putInt(mContext.getContentResolver(),
Settings.Global.LOW_POWER_MODE, 0);
+ // update performance profile
mLowPowerModeSetting = false;
}
final boolean autoLowPowerModeEnabled = !mIsPowered && mAutoLowPowerModeConfigured
@@ -800,6 +914,15 @@ public final class PowerManagerService extends SystemService
}
mWakeLocks.add(wakeLock);
setWakeLockDisabledStateLocked(wakeLock);
+ if(mBlockedUids.contains(new Integer(uid)) && uid != Process.myUid()) {
+ //wakelock acquisition for blocked uid, disable it.
+ if (DEBUG_SPEW) {
+ Slog.d(TAG, "uid is blocked disabling wakeLock flags=0x" +
+ Integer.toHexString(flags) + " tag=" + tag + " uid=" + uid +
+ " pid =" + pid);
+ }
+ updateBlockedWakelock(wakeLock, true);
+ }
notifyAcquire = true;
}
@@ -1377,7 +1500,7 @@ public final class PowerManagerService extends SystemService
private boolean shouldWakeUpWhenPluggedOrUnpluggedLocked(
boolean wasPowered, int oldPlugType, boolean dockedOnWirelessCharger) {
// Don't wake when powered unless configured to do so.
- if (!mWakeUpWhenPluggedOrUnpluggedConfig) {
+ if (mWakeUpWhenPluggedOrUnpluggedSetting == 0) {
return false;
}
@@ -1419,7 +1542,16 @@ public final class PowerManagerService extends SystemService
final boolean wasStayOn = mStayOn;
if (mStayOnWhilePluggedInSetting != 0
&& !isMaximumScreenOffTimeoutFromDeviceAdminEnforcedLocked()) {
- mStayOn = mBatteryManagerInternal.isPowered(mStayOnWhilePluggedInSetting);
+ switch (mStayOnWhilePluggedInSetting) {
+ case 1: // Debugging only over usb
+ mStayOn = ((mPlugType & BatteryManager.BATTERY_PLUGGED_USB) != 0)
+ && Settings.Global.getInt(mContext.getContentResolver(),
+ Settings.Global.ADB_ENABLED, 0) != 0;;
+ break;
+ default: // charging
+ mStayOn = mIsPowered;
+ break;
+ }
} else {
mStayOn = false;
}
@@ -1532,10 +1664,38 @@ public final class PowerManagerService extends SystemService
+ screenOffTimeout - screenDimDuration;
if (now < nextTimeout) {
mUserActivitySummary = USER_ACTIVITY_SCREEN_BRIGHT;
+ if (mWakefulness == WAKEFULNESS_AWAKE) {
+ int buttonBrightness, keyboardBrightness;
+ if (mButtonBrightnessOverrideFromWindowManager >= 0) {
+ buttonBrightness = mButtonBrightnessOverrideFromWindowManager;
+ keyboardBrightness = mButtonBrightnessOverrideFromWindowManager;
+ } else {
+ buttonBrightness = mButtonBrightness;
+ keyboardBrightness = mKeyboardBrightness;
+ }
+
+ mKeyboardLight.setBrightness(mKeyboardVisible ?
+ keyboardBrightness : 0);
+ if (mButtonTimeout != 0
+ && now > mLastUserActivityTime + mButtonTimeout) {
+ mButtonsLight.setBrightness(0);
+ } else {
+ if (!mProximityPositive) {
+ mButtonsLight.setBrightness(buttonBrightness);
+ if (buttonBrightness != 0 && mButtonTimeout != 0) {
+ nextTimeout = now + mButtonTimeout;
+ }
+ }
+ }
+ }
} else {
nextTimeout = mLastUserActivityTime + screenOffTimeout;
if (now < nextTimeout) {
mUserActivitySummary = USER_ACTIVITY_SCREEN_DIM;
+ if (mWakefulness == WAKEFULNESS_AWAKE) {
+ mButtonsLight.setBrightness(0);
+ mKeyboardLight.setBrightness(0);
+ }
}
}
}
@@ -1799,7 +1959,7 @@ public final class PowerManagerService extends SystemService
}
// Dream has ended or will be stopped. Update the power state.
- if (isItBedTimeYetLocked()) {
+ if (isItBedTimeYetLocked() && !mDreamsActivatedOnSleepByDefaultConfig) {
goToSleepNoUpdateLocked(SystemClock.uptimeMillis(),
PowerManager.GO_TO_SLEEP_REASON_TIMEOUT, 0, Process.SYSTEM_UID);
updatePowerStateLocked();
@@ -2819,6 +2979,10 @@ public final class PowerManagerService extends SystemService
case MSG_SCREEN_BRIGHTNESS_BOOST_TIMEOUT:
handleScreenBrightnessBoostTimeout();
break;
+ case MSG_WAKE_UP:
+ cleanupProximity();
+ ((Runnable) msg.obj).run();
+ break;
}
}
}
@@ -2998,6 +3162,22 @@ public final class PowerManagerService extends SystemService
}
}
+ private void cleanupProximity() {
+ synchronized (mProximityWakeLock) {
+ cleanupProximityLocked();
+ }
+ }
+
+ private void cleanupProximityLocked() {
+ if (mProximityWakeLock.isHeld()) {
+ mProximityWakeLock.release();
+ }
+ if (mProximityListener != null) {
+ mSensorManager.unregisterListener(mProximityListener);
+ mProximityListener = null;
+ }
+ }
+
private final class BinderService extends IPowerManager.Stub {
@Override // Binder call
public void acquireWakeLockWithUid(IBinder lock, int flags, String tag,
@@ -3153,7 +3333,46 @@ public final class PowerManagerService extends SystemService
}
@Override // Binder call
- public void wakeUp(long eventTime, String reason, String opPackageName) {
+ public void setKeyboardVisibility(boolean visible) {
+ synchronized (mLock) {
+ if (DEBUG_SPEW) {
+ Slog.d(TAG, "setKeyboardVisibility: " + visible);
+ }
+ if (mKeyboardVisible != visible) {
+ mKeyboardVisible = visible;
+ if (!visible) {
+ // If hiding keyboard, turn off leds
+ setKeyboardLight(false, 1);
+ setKeyboardLight(false, 2);
+ }
+ synchronized (mLock) {
+ mDirty |= DIRTY_USER_ACTIVITY;
+ updatePowerStateLocked();
+ }
+ }
+ }
+ }
+
+ @Override // Binder call
+ public void setKeyboardLight(boolean on, int key) {
+ if (key == 1) {
+ if (on)
+ mCapsLight.setColor(0x00ffffff);
+ else
+ mCapsLight.turnOff();
+ } else if (key == 2) {
+ if (on)
+ mFnLight.setColor(0x00ffffff);
+ else
+ mFnLight.turnOff();
+ }
+ }
+
+ /**
+ * @hide
+ */
+ private void wakeUp(final long eventTime, final String reason, final String opPackageName,
+ boolean checkProximity) {
if (eventTime > SystemClock.uptimeMillis()) {
throw new IllegalArgumentException("event time must not be in the future");
}
@@ -3162,12 +3381,84 @@ public final class PowerManagerService extends SystemService
android.Manifest.permission.DEVICE_POWER, null);
final int uid = Binder.getCallingUid();
- final long ident = Binder.clearCallingIdentity();
- try {
- wakeUpInternal(eventTime, reason, uid, opPackageName, uid);
- } finally {
- Binder.restoreCallingIdentity(ident);
+ Runnable r = new Runnable() {
+ @Override
+ public void run() {
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ wakeUpInternal(eventTime, reason, uid, opPackageName, uid);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+ };
+ if (checkProximity) {
+ runWithProximityCheck(r);
+ } else {
+ r.run();
+ }
+ }
+
+ private void runWithProximityCheck(Runnable r) {
+ if (mHandler.hasMessages(MSG_WAKE_UP)) {
+ // There is already a message queued;
+ return;
}
+
+ TelephonyManager tm = (TelephonyManager)mContext.getSystemService(
+ Context.TELEPHONY_SERVICE);
+ boolean hasIncomingCall = tm.getCallState() == TelephonyManager.CALL_STATE_RINGING;
+
+ if (mProximityWakeSupported && mProximityWakeEnabled && mProximitySensor != null
+ && !hasIncomingCall) {
+ Message msg = mHandler.obtainMessage(MSG_WAKE_UP);
+ msg.obj = r;
+ mHandler.sendMessageDelayed(msg, mProximityTimeOut);
+ runPostProximityCheck(r);
+ } else {
+ r.run();
+ }
+ }
+
+ private void runPostProximityCheck(final Runnable r) {
+ if (mSensorManager == null) {
+ r.run();
+ return;
+ }
+ synchronized (mProximityWakeLock) {
+ mProximityWakeLock.acquire();
+ mProximityListener = new SensorEventListener() {
+ @Override
+ public void onSensorChanged(SensorEvent event) {
+ cleanupProximityLocked();
+ if (!mHandler.hasMessages(MSG_WAKE_UP)) {
+ Slog.w(TAG, "The proximity sensor took too long, wake event already triggered!");
+ return;
+ }
+ mHandler.removeMessages(MSG_WAKE_UP);
+ float distance = event.values[0];
+ if (distance >= PROXIMITY_NEAR_THRESHOLD ||
+ distance >= mProximitySensor.getMaximumRange()) {
+ r.run();
+ }
+ }
+
+ @Override
+ public void onAccuracyChanged(Sensor sensor, int accuracy) {}
+ };
+ mSensorManager.registerListener(mProximityListener,
+ mProximitySensor, SensorManager.SENSOR_DELAY_FASTEST);
+ }
+ }
+
+ @Override // Binder call
+ public void wakeUpWithProximityCheck(long eventTime, String reason, String opPackageName) {
+ wakeUp(eventTime, reason, opPackageName, true);
+ }
+
+ @Override // Binder call
+ public void wakeUp(long eventTime, String reason, String opPackageName) {
+ wakeUp(eventTime, reason, opPackageName, false);
}
@Override // Binder call
@@ -3432,6 +3723,11 @@ public final class PowerManagerService extends SystemService
}
@Override // Binder call
+ public void cpuBoost(int duration) {
+ mPerf.cpuBoost(duration);
+ }
+
+ @Override // Binder call
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (mContext.checkCallingOrSelfPermission(Manifest.permission.DUMP)
!= PackageManager.PERMISSION_GRANTED) {
@@ -3448,6 +3744,53 @@ public final class PowerManagerService extends SystemService
Binder.restoreCallingIdentity(ident);
}
}
+
+ /* updates the blocked uids, so if a wake lock is acquired for it
+ * can be released.
+ */
+ public void updateBlockedUids(int uid, boolean isBlocked) {
+ boolean changed = false;
+ if (DEBUG_SPEW) Slog.v(TAG, "updateBlockedUids: uid = " + uid +
+ "isBlocked = " + isBlocked);
+ if (Binder.getCallingUid() != Process.SYSTEM_UID) {
+ if (DEBUG_SPEW) Slog.v(TAG, "UpdateBlockedUids is not allowed");
+ return;
+ }
+ synchronized(mLock) {
+ for (int index = 0; index < mWakeLocks.size(); index++) {
+ WakeLock wl = mWakeLocks.get(index);
+ if(wl != null) {
+ // update the wakelock for the blocked uid
+ if ((wl.mOwnerUid == uid || checkWorkSourceObjectId(uid, wl)) ||
+ (wl.mTag.startsWith("*sync*") && wl.mOwnerUid == Process.SYSTEM_UID)) {
+ if(updateBlockedWakelock(wl, isBlocked)){
+ changed = true;
+ }
+ }
+ }
+ }
+ if(isBlocked) {
+ mBlockedUids.add(new Integer(uid));
+ }
+ else {
+ mBlockedUids.clear();
+ }
+ }
+ if(changed){
+ mDirty |= DIRTY_WAKE_LOCKS;
+ updatePowerStateLocked();
+ }
+ }
+ }
+
+ private void setButtonBrightnessOverrideFromWindowManagerInternal(int brightness) {
+ synchronized (mLock) {
+ if (mButtonBrightnessOverrideFromWindowManager != brightness) {
+ mButtonBrightnessOverrideFromWindowManager = brightness;
+ mDirty |= DIRTY_SETTINGS;
+ updatePowerStateLocked();
+ }
+ }
}
private final class LocalService extends PowerManagerInternal {
@@ -3462,8 +3805,15 @@ public final class PowerManagerService extends SystemService
@Override
public void setButtonBrightnessOverrideFromWindowManager(int screenBrightness) {
- // Do nothing.
- // Button lights are not currently supported in the new implementation.
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null);
+
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ setButtonBrightnessOverrideFromWindowManagerInternal(screenBrightness);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+
}
@Override
@@ -3539,5 +3889,52 @@ public final class PowerManagerService extends SystemService
public void powerHint(int hintId, int data) {
powerHintInternal(hintId, data);
}
+
+ @Override
+ public boolean setPowerSaveMode(boolean mode) {
+ return setLowPowerModeInternal(mode);
+ }
+
+ @Override
+ public int getFeature(int featureId) {
+ return nativeGetFeature(featureId);
+ }
+
+ @Override
+ public void setFeature(int featureId, int data) {
+ nativeSetFeature(featureId, data);
+ }
+ }
+
+ private boolean updateBlockedWakelock(WakeLock wakeLock, boolean update) {
+ if (wakeLock != null && ((wakeLock.mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK)
+ == PowerManager.PARTIAL_WAKE_LOCK )) {
+ if(wakeLock.mDisabled != update){
+ wakeLock.mDisabled = update;
+ if (wakeLock.mDisabled) {
+ // This wake lock is no longer being respected.
+ notifyWakeLockReleasedLocked(wakeLock);
+ } else {
+ notifyWakeLockAcquiredLocked(wakeLock);
+ }
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private boolean checkWorkSourceObjectId(int uid, WakeLock wl) {
+ try {
+ for (int index = 0; index < wl.mWorkSource.size(); index++) {
+ if (uid == wl.mWorkSource.get(index)) {
+ if (DEBUG_SPEW) Slog.v(TAG, "WS uid matched");
+ return true;
+ }
+ }
+ }
+ catch (Exception e) {
+ return false;
+ }
+ return false;
}
}
diff --git a/services/core/java/com/android/server/power/ShutdownThread.java b/services/core/java/com/android/server/power/ShutdownThread.java
index dd8648d..9b8ea14 100644
--- a/services/core/java/com/android/server/power/ShutdownThread.java
+++ b/services/core/java/com/android/server/power/ShutdownThread.java
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2008 The Android Open Source Project
+ * Copyright (C) 2013 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.
@@ -21,9 +22,11 @@ import android.app.ActivityManagerNative;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.IActivityManager;
+import android.app.KeyguardManager;
import android.app.ProgressDialog;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.IBluetoothManager;
+import android.content.pm.ThemeUtils;
import android.media.AudioAttributes;
import android.nfc.NfcAdapter;
import android.nfc.INfcAdapter;
@@ -32,7 +35,13 @@ import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.media.AudioManager;
+import android.media.MediaPlayer;
+import android.media.MediaPlayer.OnCompletionListener;
+import android.os.FileUtils;
import android.os.Handler;
+import android.os.Message;
import android.os.PowerManager;
import android.os.RemoteException;
import android.os.ServiceManager;
@@ -44,19 +53,30 @@ import android.os.Vibrator;
import android.os.SystemVibrator;
import android.os.storage.IMountService;
import android.os.storage.IMountShutdownObserver;
+import android.provider.Settings;
import android.system.ErrnoException;
import android.system.Os;
+import android.widget.ListView;
import com.android.internal.telephony.ITelephony;
import com.android.server.pm.PackageManagerService;
-
+import com.android.server.power.PowerManagerService;
import android.util.Log;
+import android.view.IWindowManager;
import android.view.WindowManager;
+import java.lang.reflect.Method;
+
+import cyanogenmod.providers.CMSettings;
+import dalvik.system.PathClassLoader;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.OutputStreamWriter;
public final class ShutdownThread extends Thread {
// constants
@@ -74,6 +94,8 @@ public final class ShutdownThread extends Thread {
private static final int RADIO_STOP_PERCENT = 18;
private static final int MOUNT_SERVICE_STOP_PERCENT = 20;
+ private static final String SOFT_REBOOT = "soft_reboot";
+
// length of vibration before shutting down
private static final int SHUTDOWN_VIBRATE_MS = 500;
@@ -85,7 +107,11 @@ public final class ShutdownThread extends Thread {
private static final String UNCRYPT_STATUS_FILE = "/cache/recovery/uncrypt_status";
private static final String UNCRYPT_PACKAGE_FILE = "/cache/recovery/uncrypt_file";
+ // recovery command
+ private static File RECOVERY_COMMAND_FILE = new File("/cache/recovery/command");
+
private static boolean mReboot;
+ private static boolean mRebootWipe = false;
private static boolean mRebootSafeMode;
private static boolean mRebootUpdate;
private static String mRebootReason;
@@ -111,10 +137,20 @@ public final class ShutdownThread extends Thread {
private PowerManager.WakeLock mCpuWakeLock;
private PowerManager.WakeLock mScreenWakeLock;
private Handler mHandler;
+ private static MediaPlayer mMediaPlayer;
+ private static final String OEM_BOOTANIMATION_FILE = "/oem/media/shutdownanimation.zip";
+ private static final String SYSTEM_BOOTANIMATION_FILE = "/system/media/shutdownanimation.zip";
+ private static final String SYSTEM_ENCRYPTED_BOOTANIMATION_FILE = "/system/media/shutdownanimation-encrypted.zip";
+
+ private static final String SHUTDOWN_MUSIC_FILE = "/system/media/shutdown.wav";
+ private static final String OEM_SHUTDOWN_MUSIC_FILE = "/oem/media/shutdown.wav";
+
+ private boolean isShutdownMusicPlaying = false;
private static AlertDialog sConfirmDialog;
private ProgressDialog mProgressDialog;
+ private static AudioManager mAudioManager;
private ShutdownThread() {
}
@@ -127,9 +163,20 @@ public final class ShutdownThread extends Thread {
* @param confirm true if user confirmation is needed before shutting down.
*/
public static void shutdown(final Context context, boolean confirm) {
+ final Context uiContext = getUiContext(context);
mReboot = false;
mRebootSafeMode = false;
- shutdownInner(context, confirm);
+ shutdownInner(uiContext, confirm);
+ }
+
+ private static boolean isAdvancedRebootPossible(final Context context) {
+ KeyguardManager km = (KeyguardManager) context.getSystemService(Context.KEYGUARD_SERVICE);
+ boolean keyguardLocked = km.inKeyguardRestrictedInputMode() && km.isKeyguardSecure();
+ boolean advancedRebootEnabled = CMSettings.Secure.getInt(context.getContentResolver(),
+ CMSettings.Secure.ADVANCED_REBOOT, 0) == 1;
+ boolean isPrimaryUser = UserHandle.getCallingUserId() == UserHandle.USER_OWNER;
+
+ return advancedRebootEnabled && !keyguardLocked && isPrimaryUser;
}
static void shutdownInner(final Context context, boolean confirm) {
@@ -142,33 +189,90 @@ public final class ShutdownThread extends Thread {
}
}
+ boolean showRebootOption = false;
+
+ String[] actionsArray;
+ String actions = CMSettings.Secure.getStringForUser(context.getContentResolver(),
+ CMSettings.Secure.POWER_MENU_ACTIONS, UserHandle.USER_CURRENT);
+ if (actions == null) {
+ actionsArray = context.getResources().getStringArray(
+ com.android.internal.R.array.config_globalActionsList);
+ } else {
+ actionsArray = actions.split("\\|");
+ }
+
+ for (int i = 0; i < actionsArray.length; i++) {
+ if (actionsArray[i].equals("reboot")) {
+ showRebootOption = true;
+ break;
+ }
+ }
final int longPressBehavior = context.getResources().getInteger(
com.android.internal.R.integer.config_longPressOnPowerBehavior);
- final int resourceId = mRebootSafeMode
+ int resourceId = mRebootSafeMode
? com.android.internal.R.string.reboot_safemode_confirm
: (longPressBehavior == 2
? com.android.internal.R.string.shutdown_confirm_question
: com.android.internal.R.string.shutdown_confirm);
+ if (showRebootOption && !mRebootSafeMode) {
+ resourceId = com.android.internal.R.string.reboot_confirm;
+ }
Log.d(TAG, "Notifying thread to start shutdown longPressBehavior=" + longPressBehavior);
if (confirm) {
final CloseDialogReceiver closer = new CloseDialogReceiver(context);
+ final boolean advancedReboot = isAdvancedRebootPossible(context);
+ final Context uiContext = getUiContext(context);
+
if (sConfirmDialog != null) {
sConfirmDialog.dismiss();
+ sConfirmDialog = null;
}
- sConfirmDialog = new AlertDialog.Builder(context)
+ AlertDialog.Builder confirmDialogBuilder = new AlertDialog.Builder(uiContext)
.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() {
+ : showRebootOption
+ ? com.android.internal.R.string.reboot_title
+ : com.android.internal.R.string.power_off);
+
+ if (!advancedReboot || mRebootSafeMode) {
+ confirmDialogBuilder.setMessage(resourceId);
+ } else {
+ confirmDialogBuilder
+ .setSingleChoiceItems(com.android.internal.R.array.shutdown_reboot_options,
+ 0, null);
+ }
+
+ confirmDialogBuilder.setPositiveButton(com.android.internal.R.string.yes,
+ new DialogInterface.OnClickListener() {
+ @Override
public void onClick(DialogInterface dialog, int which) {
+ if (!mRebootSafeMode && advancedReboot) {
+ boolean softReboot = false;
+ ListView reasonsList = ((AlertDialog)dialog).getListView();
+ int selected = reasonsList.getCheckedItemPosition();
+ if (selected != ListView.INVALID_POSITION) {
+ String actions[] = context.getResources().getStringArray(
+ com.android.internal.R.array.shutdown_reboot_actions);
+ if (selected >= 0 && selected < actions.length) {
+ mRebootReason = actions[selected];
+ if (actions[selected].equals(SOFT_REBOOT)) {
+ doSoftReboot();
+ return;
+ }
+ }
+ }
+
+ mReboot = true;
+ }
beginShutdownSequence(context);
- }
- })
- .setNegativeButton(com.android.internal.R.string.no, null)
- .create();
+ }
+ });
+
+ confirmDialogBuilder.setNegativeButton(com.android.internal.R.string.no, null);
+ sConfirmDialog = confirmDialogBuilder.create();
+
closer.dialog = sConfirmDialog;
sConfirmDialog.setOnDismissListener(closer);
sConfirmDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
@@ -178,6 +282,18 @@ public final class ShutdownThread extends Thread {
}
}
+ private static void doSoftReboot() {
+ try {
+ final IActivityManager am =
+ ActivityManagerNative.asInterface(ServiceManager.checkService("activity"));
+ if (am != null) {
+ am.restart();
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "failure trying to perform soft reboot", e);
+ }
+ }
+
private static class CloseDialogReceiver extends BroadcastReceiver
implements DialogInterface.OnDismissListener {
private Context mContext;
@@ -209,13 +325,35 @@ public final class ShutdownThread extends Thread {
* @param confirm true if user confirmation is needed before shutting down.
*/
public static void reboot(final Context context, String reason, boolean confirm) {
+ final Context uiContext = getUiContext(context);
mReboot = true;
mRebootSafeMode = false;
mRebootUpdate = false;
mRebootReason = reason;
- shutdownInner(context, confirm);
+ shutdownInner(uiContext, confirm);
+ }
+
+ private static String getShutdownMusicFilePath() {
+ final String[] fileName = {OEM_SHUTDOWN_MUSIC_FILE, SHUTDOWN_MUSIC_FILE};
+ File checkFile = null;
+ for(String music : fileName) {
+ checkFile = new File(music);
+ if (checkFile.exists()) {
+ return music;
+ }
+ }
+ return null;
}
+ private static void lockDevice() {
+ IWindowManager wm = IWindowManager.Stub.asInterface(ServiceManager
+ .getService(Context.WINDOW_SERVICE));
+ try {
+ wm.updateRotation(false, false);
+ } catch (RemoteException e) {
+ Log.w(TAG, "boot animation can not lock device!");
+ }
+ }
/**
* Request a reboot into safe mode. Must be called from a Looper thread in which its UI
* is shown.
@@ -262,6 +400,13 @@ public final class ShutdownThread extends Thread {
// UI: spinning circle only (no progress bar)
if (PowerManager.REBOOT_RECOVERY.equals(mRebootReason)) {
mRebootUpdate = new File(UNCRYPT_PACKAGE_FILE).exists();
+ if (RECOVERY_COMMAND_FILE.exists()) {
+ try {
+ mRebootWipe = new String(FileUtils.readTextFile(
+ RECOVERY_COMMAND_FILE, 0, null)).contains("wipe");
+ } catch (IOException e) {
+ }
+ }
if (mRebootUpdate) {
pd.setTitle(context.getText(com.android.internal.R.string.reboot_to_update_title));
pd.setMessage(context.getText(
@@ -271,22 +416,41 @@ public final class ShutdownThread extends Thread {
pd.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
pd.setProgress(0);
pd.setIndeterminate(false);
- } else {
+ } else if (mRebootWipe) {
// Factory reset path. Set the dialog message accordingly.
pd.setTitle(context.getText(com.android.internal.R.string.reboot_to_reset_title));
pd.setMessage(context.getText(
com.android.internal.R.string.reboot_to_reset_message));
pd.setIndeterminate(true);
+ } else {
+ pd.setTitle(context.getText(com.android.internal.R.string.reboot_title));
+ pd.setMessage(context.getText(com.android.internal.R.string.reboot_progress));
+ pd.setIndeterminate(true);
}
} else {
- 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_title));
+ 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);
- pd.show();
+ //acquire audio focus to make the other apps to stop playing muisc
+ mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
+ mAudioManager.requestAudioFocus(null,
+ AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
+
+ if (!checkAnimationFileExist()) {
+ // throw up an indeterminate system dialog to indicate radio is
+ // shutting down.
+ pd.setCancelable(false);
+ pd.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
+
+ pd.show();
+ }
sInstance.mProgressDialog = pd;
sInstance.mContext = context;
@@ -417,6 +581,40 @@ public final class ShutdownThread extends Thread {
sInstance.setRebootProgress(PACKAGE_MANAGER_STOP_PERCENT, null);
}
+ String shutDownFile = null;
+
+ //showShutdownAnimation() is called from here to sync
+ //music and animation properly
+ if(checkAnimationFileExist()) {
+ lockDevice();
+ showShutdownAnimation();
+
+ if (!isSilentMode()
+ && (shutDownFile = getShutdownMusicFilePath()) != null) {
+ isShutdownMusicPlaying = true;
+ shutdownMusicHandler.obtainMessage(0, shutDownFile).sendToTarget();
+ }
+ }
+
+ Log.i(TAG, "wait for shutdown music");
+ final long endTimeForMusic = SystemClock.elapsedRealtime() + MAX_BROADCAST_TIME;
+ synchronized (mActionDoneSync) {
+ while (isShutdownMusicPlaying) {
+ long delay = endTimeForMusic - SystemClock.elapsedRealtime();
+ if (delay <= 0) {
+ Log.w(TAG, "play shutdown music timeout!");
+ break;
+ }
+ try {
+ mActionDoneSync.wait(delay);
+ } catch (InterruptedException e) {
+ }
+ }
+ if (!isShutdownMusicPlaying) {
+ Log.i(TAG, "play shutdown music complete.");
+ }
+ }
+
// Shutdown radios.
shutdownRadios(MAX_RADIO_WAIT_TIME);
if (mRebootUpdate) {
@@ -507,11 +705,10 @@ public final class ShutdownThread extends Thread {
ITelephony.Stub.asInterface(ServiceManager.checkService("phone"));
final IBluetoothManager bluetooth =
IBluetoothManager.Stub.asInterface(ServiceManager.checkService(
- BluetoothAdapter.BLUETOOTH_MANAGER_SERVICE));
+ BluetoothAdapter.BLUETOOTH_MANAGER_SERVICE));
try {
- nfcOff = nfc == null ||
- nfc.getState() == NfcAdapter.STATE_OFF;
+ nfcOff = nfc == null || nfc.getState() == NfcAdapter.STATE_OFF;
if (!nfcOff) {
Log.w(TAG, "Turning off NFC...");
nfc.disable(false); // Don't persist new state
@@ -619,6 +816,7 @@ public final class ShutdownThread extends Thread {
* @param reason reason for reboot
*/
public static void rebootOrShutdown(final Context context, boolean reboot, String reason) {
+ deviceRebootOrShutdown(reboot, reason);
if (reboot) {
Log.i(TAG, "Rebooting, reason: " + reason);
PowerManagerService.lowLevelReboot(reason);
@@ -722,4 +920,90 @@ public final class ShutdownThread extends Thread {
Log.w(TAG, "Timed out waiting for uncrypt.");
}
}
+
+ private static void deviceRebootOrShutdown(boolean reboot, String reason) {
+ Class<?> cl;
+ String deviceShutdownClassName = "com.qti.server.power.ShutdownOem";
+ try {
+ cl = Class.forName(deviceShutdownClassName);
+ Method m;
+ try {
+ m = cl.getMethod("rebootOrShutdown", new Class[] {boolean.class, String.class});
+ m.invoke(cl.newInstance(), reboot, reason);
+ } catch (NoSuchMethodException ex) {
+ Log.e(TAG, "rebootOrShutdown method not found in class " + deviceShutdownClassName);
+ } catch (Exception ex) {
+ Log.e(TAG, "Unknown exception hit while trying to invode rebootOrShutdown");
+ }
+ } catch (ClassNotFoundException e) {
+ Log.e(TAG, "Unable to find class " + deviceShutdownClassName);
+ } catch (Exception e) {
+ Log.e(TAG, "Unknown exception while trying to invoke rebootOrShutdown");
+ }
+ }
+
+ private static boolean checkAnimationFileExist() {
+ if (new File(OEM_BOOTANIMATION_FILE).exists()
+ || new File(SYSTEM_BOOTANIMATION_FILE).exists()
+ || new File(SYSTEM_ENCRYPTED_BOOTANIMATION_FILE).exists())
+ return true;
+ else
+ return false;
+ }
+
+ private static boolean isSilentMode() {
+ return mAudioManager.isSilentMode();
+ }
+
+ private static void showShutdownAnimation() {
+ /*
+ * When boot completed, "service.bootanim.exit" property is set to 1.
+ * Bootanimation checks this property to stop showing the boot animation.
+ * Since we use the same code for shutdown animation, we
+ * need to reset this property to 0. If this is not set to 0 then shutdown
+ * will stop and exit after displaying the first frame of the animation
+ */
+ SystemProperties.set("service.bootanim.exit", "0");
+
+ SystemProperties.set("ctl.start", "bootanim");
+ }
+
+ private Handler shutdownMusicHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ String path = (String) msg.obj;
+ mMediaPlayer = new MediaPlayer();
+ try
+ {
+ mMediaPlayer.reset();
+ mMediaPlayer.setDataSource(path);
+ mMediaPlayer.prepare();
+ mMediaPlayer.start();
+ mMediaPlayer.setOnCompletionListener(new OnCompletionListener() {
+ @Override
+ public void onCompletion(MediaPlayer mp) {
+ synchronized (mActionDoneSync) {
+ isShutdownMusicPlaying = false;
+ mActionDoneSync.notifyAll();
+ }
+ }
+ });
+ } catch (IOException e) {
+ Log.d(TAG, "play shutdown music error:" + e);
+ }
+ }
+ };
+
+ private static Context getUiContext(Context context) {
+ Context uiContext = null;
+ if (context != null) {
+ uiContext = ThemeUtils.createUiContext(context);
+ if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEVISION)) {
+ uiContext.setTheme(com.android.internal.R.style.Theme_Leanback_Dialog_Alert);
+ } else {
+ uiContext.setTheme(android.R.style.Theme_DeviceDefault_Light_DarkActionBar);
+ }
+ }
+ return uiContext != null ? uiContext : context;
+ }
}
diff --git a/services/core/java/com/android/server/tv/TvInputHal.java b/services/core/java/com/android/server/tv/TvInputHal.java
index a035826..a775c5a 100644
--- a/services/core/java/com/android/server/tv/TvInputHal.java
+++ b/services/core/java/com/android/server/tv/TvInputHal.java
@@ -146,7 +146,7 @@ final class TvInputHal implements Handler.Callback {
private void firstFrameCapturedFromNative(int deviceId, int streamId) {
mHandler.sendMessage(
- mHandler.obtainMessage(EVENT_STREAM_CONFIGURATION_CHANGED, deviceId, streamId));
+ mHandler.obtainMessage(EVENT_FIRST_FRAME_CAPTURED, deviceId, streamId));
}
// Handler.Callback implementation
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index 7784884..ee926a4 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -106,6 +106,8 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
static final int MAX_WALLPAPER_COMPONENT_LOG_LENGTH = 128;
static final String WALLPAPER = "wallpaper";
static final String WALLPAPER_INFO = "wallpaper_info.xml";
+ static final String KEYGUARD_WALLPAPER = "keyguard_wallpaper";
+ static final String KEYGUARD_WALLPAPER_INFO = "keyguard_wallpaper_info.xml";
/**
* Observes the wallpaper for changes and notifies all IWallpaperServiceCallbacks
@@ -116,17 +118,21 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
private class WallpaperObserver extends FileObserver {
final WallpaperData mWallpaper;
+ final KeyguardWallpaperData mKeyguardWallpaper;
final File mWallpaperDir;
final File mWallpaperFile;
final File mWallpaperInfoFile;
+ final File mKeyguardWallpaperFile;
- public WallpaperObserver(WallpaperData wallpaper) {
+ public WallpaperObserver(WallpaperData wallpaper, KeyguardWallpaperData keyguardWallpaper) {
super(getWallpaperDir(wallpaper.userId).getAbsolutePath(),
CLOSE_WRITE | MOVED_TO | DELETE | DELETE_SELF);
mWallpaperDir = getWallpaperDir(wallpaper.userId);
mWallpaper = wallpaper;
mWallpaperFile = new File(mWallpaperDir, WALLPAPER);
mWallpaperInfoFile = new File(mWallpaperDir, WALLPAPER_INFO);
+ mKeyguardWallpaper = keyguardWallpaper;
+ mKeyguardWallpaperFile = new File(mWallpaperDir, KEYGUARD_WALLPAPER);
}
@Override
@@ -145,6 +151,12 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
Binder.restoreCallingIdentity(origId);
}
if (mWallpaperFile.equals(changedFile)) {
+ // changing the wallpaper means we'll need to back up the new one
+ long origId = Binder.clearCallingIdentity();
+ BackupManager bm = new BackupManager(mContext);
+ bm.dataChanged();
+ Binder.restoreCallingIdentity(origId);
+
notifyCallbacksLocked(mWallpaper);
final boolean written = (event == CLOSE_WRITE || event == MOVED_TO);
if (mWallpaper.wallpaperComponent == null
@@ -157,6 +169,13 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
false, mWallpaper, null);
saveSettingsLocked(mWallpaper);
}
+ } else if (mKeyguardWallpaperFile.equals(changedFile)) {
+ notifyCallbacksLocked(mKeyguardWallpaper);
+ if (event == CLOSE_WRITE
+ || mKeyguardWallpaper.imageWallpaperPending) {
+ mKeyguardWallpaper.imageWallpaperPending = false;
+ saveSettingsLocked(mKeyguardWallpaper);
+ }
}
}
}
@@ -176,6 +195,8 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
final ComponentName mImageWallpaper;
SparseArray<WallpaperData> mWallpaperMap = new SparseArray<WallpaperData>();
+ SparseArray<KeyguardWallpaperData> mKeyguardWallpaperMap
+ = new SparseArray<KeyguardWallpaperData>();
int mCurrentUserId;
@@ -227,6 +248,37 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
}
}
+ static class KeyguardWallpaperData {
+
+ int userId;
+
+ File wallpaperFile;
+
+ /**
+ * Client is currently writing a new image wallpaper.
+ */
+ boolean imageWallpaperPending;
+
+ /**
+ * Resource name if using a picture from the wallpaper gallery
+ */
+ String name = "";
+
+ /**
+ * List of callbacks registered they should each be notified when the wallpaper is changed.
+ */
+ private RemoteCallbackList<IWallpaperManagerCallback> callbacks
+ = new RemoteCallbackList<IWallpaperManagerCallback>();
+
+ int width = -1;
+ int height = -1;
+
+ KeyguardWallpaperData(int userId) {
+ this.userId = userId;
+ wallpaperFile = new File(getWallpaperDir(userId), KEYGUARD_WALLPAPER);
+ }
+ }
+
class WallpaperConnection extends IWallpaperConnection.Stub
implements ServiceConnection {
final WallpaperInfo mInfo;
@@ -486,6 +538,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
mMonitor.register(context, null, UserHandle.ALL, true);
getWallpaperDir(UserHandle.USER_OWNER).mkdirs();
loadSettingsLocked(UserHandle.USER_OWNER);
+ loadKeyguardSettingsLocked(UserHandle.USER_OWNER);
}
private static File getWallpaperDir(int userId) {
@@ -504,8 +557,9 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
public void systemRunning() {
if (DEBUG) Slog.v(TAG, "systemReady");
WallpaperData wallpaper = mWallpaperMap.get(UserHandle.USER_OWNER);
+ KeyguardWallpaperData keyguardWallpaper = mKeyguardWallpaperMap.get(UserHandle.USER_OWNER);
switchWallpaper(wallpaper, null);
- wallpaper.wallpaperObserver = new WallpaperObserver(wallpaper);
+ wallpaper.wallpaperObserver = new WallpaperObserver(wallpaper, keyguardWallpaper);
wallpaper.wallpaperObserver.startWatching();
IntentFilter userFilter = new IntentFilter();
@@ -572,6 +626,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
wallpaper.wallpaperObserver = null;
}
mWallpaperMap.remove(userId);
+ mKeyguardWallpaperMap.remove(userId);
}
}
}
@@ -584,6 +639,11 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
wallpaperFile.delete();
File wallpaperInfoFile = new File(getWallpaperDir(userId), WALLPAPER_INFO);
wallpaperInfoFile.delete();
+ File keyguardWallpaperFile = new File(getWallpaperDir(userId), KEYGUARD_WALLPAPER);
+ keyguardWallpaperFile.delete();
+ File keyguardWallpaperInfoFile = new File(getWallpaperDir(userId),
+ KEYGUARD_WALLPAPER_INFO);
+ keyguardWallpaperInfoFile.delete();
}
}
@@ -591,9 +651,10 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
synchronized (mLock) {
mCurrentUserId = userId;
WallpaperData wallpaper = getWallpaperSafeLocked(userId);
+ KeyguardWallpaperData keyguardWallpaper = getKeyguardWallpaperSafeLocked(userId);
// Not started watching yet, in case wallpaper data was loaded for other reasons.
if (wallpaper.wallpaperObserver == null) {
- wallpaper.wallpaperObserver = new WallpaperObserver(wallpaper);
+ wallpaper.wallpaperObserver = new WallpaperObserver(wallpaper, keyguardWallpaper);
wallpaper.wallpaperObserver.startWatching();
}
switchWallpaper(wallpaper, reply);
@@ -669,6 +730,40 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
}
}
+ /**
+ * @hide
+ */
+ public void clearKeyguardWallpaper() {
+ if (DEBUG) Slog.v(TAG, "clearWallpaper");
+ synchronized (mLock) {
+ clearKeyguardWallpaperLocked(UserHandle.getCallingUserId(), null);
+ }
+ }
+
+ void clearKeyguardWallpaperLocked(int userId, IRemoteCallback reply) {
+ KeyguardWallpaperData wallpaper = mKeyguardWallpaperMap.get(userId);
+ final long ident = Binder.clearCallingIdentity();
+ wallpaper.imageWallpaperPending = false;
+ wallpaper.height = -1;
+ wallpaper.width = -1;
+ wallpaper.name = "";
+
+ File f = new File(getWallpaperDir(userId), KEYGUARD_WALLPAPER);
+ if (f.exists()) {
+ f.delete();
+ }
+ if (userId != mCurrentUserId)
+ return;
+ Binder.restoreCallingIdentity(ident);
+
+ if (reply != null) {
+ try {
+ reply.sendResult(null);
+ } catch (RemoteException e1) {
+ }
+ }
+ }
+
public boolean hasNamedWallpaper(String name) {
synchronized (mLock) {
List<UserInfo> users;
@@ -837,6 +932,31 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
}
}
+ /** @hide */
+ public ParcelFileDescriptor getKeyguardWallpaper(IWallpaperManagerCallback cb,
+ Bundle outParams) {
+ synchronized (mLock) {
+ int wallpaperUserId = mCurrentUserId;
+ KeyguardWallpaperData wallpaper = mKeyguardWallpaperMap.get(wallpaperUserId);
+ try {
+ if (outParams != null) {
+ outParams.putInt("width", wallpaper.width);
+ outParams.putInt("height", wallpaper.height);
+ }
+ wallpaper.callbacks.register(cb);
+ File f = new File(getWallpaperDir(wallpaperUserId), KEYGUARD_WALLPAPER);
+ if (!f.exists()) {
+ return null;
+ }
+ return ParcelFileDescriptor.open(f, MODE_READ_ONLY);
+ } catch (FileNotFoundException e) {
+ /* Shouldn't happen as we check to see if the file exists */
+ Slog.w(TAG, "Error getting wallpaper", e);
+ }
+ return null;
+ }
+ }
+
public WallpaperInfo getWallpaperInfo() {
int userId = UserHandle.getCallingUserId();
synchronized (mLock) {
@@ -848,6 +968,15 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
}
}
+ /** @hide */
+ public boolean isKeyguardWallpaperSet() {
+ int userId = UserHandle.getCallingUserId();
+ synchronized (mLock) {
+ KeyguardWallpaperData data = mKeyguardWallpaperMap.get(userId);
+ return data.wallpaperFile.exists();
+ }
+ }
+
public ParcelFileDescriptor setWallpaper(String name, String callingPackage) {
checkPermission(android.Manifest.permission.SET_WALLPAPER);
if (!isWallpaperSupported(callingPackage)) {
@@ -901,6 +1030,58 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
}
}
+ public ParcelFileDescriptor setKeyguardWallpaper(String name, String callingPackage) {
+ checkPermission(android.Manifest.permission.SET_KEYGUARD_WALLPAPER);
+ if (!isWallpaperSupported(callingPackage)) {
+ return null;
+ }
+ synchronized (mLock) {
+ if (DEBUG) Slog.v(TAG, "setKeyguardWallpaper");
+ int userId = UserHandle.getCallingUserId();
+ KeyguardWallpaperData wallpaper = mKeyguardWallpaperMap.get(userId);
+ if (wallpaper == null) {
+ throw new IllegalStateException("Keyguard wallpaper not yet initialized for user "
+ + userId);
+ }
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ ParcelFileDescriptor pfd = updateKeyguardWallpaperBitmapLocked(name, wallpaper);
+ if (pfd != null) {
+ wallpaper.imageWallpaperPending = true;
+ }
+ return pfd;
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+ }
+
+ public ParcelFileDescriptor updateKeyguardWallpaperBitmapLocked(String name,
+ KeyguardWallpaperData wallpaper) {
+ if (name == null) name = "";
+ try {
+ File dir = getWallpaperDir(wallpaper.userId);
+ if (!dir.exists()) {
+ dir.mkdir();
+ FileUtils.setPermissions(
+ dir.getPath(),
+ FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH,
+ -1, -1);
+ }
+ File file = new File(dir, KEYGUARD_WALLPAPER);
+ ParcelFileDescriptor fd = ParcelFileDescriptor.open(file,
+ MODE_CREATE|MODE_READ_WRITE|MODE_TRUNCATE);
+ if (!SELinux.restorecon(file)) {
+ return null;
+ }
+ wallpaper.name = name;
+ return fd;
+ } catch (FileNotFoundException e) {
+ Slog.w(TAG, "Error setting wallpaper", e);
+ }
+ return null;
+ }
+
// ToDo: Remove this version of the function
public void setWallpaperComponent(ComponentName name) {
checkPermission(android.Manifest.permission.SET_WALLPAPER_COMPONENT);
@@ -1125,6 +1306,22 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
mContext.sendBroadcastAsUser(intent, new UserHandle(mCurrentUserId));
}
+ private void notifyCallbacksLocked(KeyguardWallpaperData wallpaper) {
+ final int n = wallpaper.callbacks.beginBroadcast();
+ for (int i = 0; i < n; i++) {
+ try {
+ wallpaper.callbacks.getBroadcastItem(i).onKeyguardWallpaperChanged();
+ } catch (RemoteException e) {
+
+ // The RemoteCallbackList will take care of removing
+ // the dead object for us.
+ }
+ }
+ wallpaper.callbacks.finishBroadcast();
+ final Intent intent = new Intent(Intent.ACTION_KEYGUARD_WALLPAPER_CHANGED);
+ mContext.sendBroadcastAsUser(intent, new UserHandle(mCurrentUserId));
+ }
+
private void checkPermission(String permission) {
if (PackageManager.PERMISSION_GRANTED!= mContext.checkCallingOrSelfPermission(permission)) {
throw new SecurityException("Access denied to process: " + Binder.getCallingPid()
@@ -1142,7 +1339,11 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
}
private static JournaledFile makeJournaledFile(int userId) {
- final String base = new File(getWallpaperDir(userId), WALLPAPER_INFO).getAbsolutePath();
+ return makeJournaledFile(WALLPAPER_INFO, userId);
+ }
+
+ private static JournaledFile makeJournaledFile(String name, int userId) {
+ final String base = new File(getWallpaperDir(userId), name).getAbsolutePath();
return new JournaledFile(new File(base), new File(base + ".tmp"));
}
@@ -1195,6 +1396,36 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
}
}
+ private void saveSettingsLocked(KeyguardWallpaperData wallpaper) {
+ JournaledFile journal = makeJournaledFile(KEYGUARD_WALLPAPER_INFO, wallpaper.userId);
+ FileOutputStream stream = null;
+ try {
+ stream = new FileOutputStream(journal.chooseForWrite(), false);
+ XmlSerializer out = new FastXmlSerializer();
+ out.setOutput(stream, "utf-8");
+ out.startDocument(null, true);
+
+ out.startTag(null, "kwp");
+ out.attribute(null, "width", Integer.toString(wallpaper.width));
+ out.attribute(null, "height", Integer.toString(wallpaper.height));
+ out.attribute(null, "name", wallpaper.name);
+ out.endTag(null, "kwp");
+
+ out.endDocument();
+ stream.close();
+ journal.commit();
+ } catch (IOException e) {
+ try {
+ if (stream != null) {
+ stream.close();
+ }
+ } catch (IOException ex) {
+ // Ignore
+ }
+ journal.rollback();
+ }
+ }
+
private void migrateFromOld() {
File oldWallpaper = new File(WallpaperBackupHelper.WALLPAPER_IMAGE_KEY);
File oldInfo = new File(WallpaperBackupHelper.WALLPAPER_INFO_KEY);
@@ -1232,6 +1463,16 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
return wallpaper;
}
+ private KeyguardWallpaperData getKeyguardWallpaperSafeLocked(int userId) {
+ KeyguardWallpaperData wallpaper = mKeyguardWallpaperMap.get(userId);
+ if (wallpaper == null) {
+ loadKeyguardSettingsLocked(userId);
+ wallpaper = mKeyguardWallpaperMap.get(userId);
+ }
+ return wallpaper;
+ }
+
+
private void loadSettingsLocked(int userId) {
if (DEBUG) Slog.v(TAG, "loadSettingsLocked");
@@ -1326,6 +1567,80 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
}
}
+ private void loadKeyguardSettingsLocked(int userId) {
+ if (DEBUG) Slog.v(TAG, "loadKeyguardSettingsLocked");
+
+ JournaledFile journal = makeJournaledFile(KEYGUARD_WALLPAPER_INFO, userId);
+ FileInputStream stream = null;
+ File file = journal.chooseForRead();
+ KeyguardWallpaperData keyguardWallpaper = mKeyguardWallpaperMap.get(userId);
+ if (keyguardWallpaper == null) {
+ keyguardWallpaper = new KeyguardWallpaperData(userId);
+ mKeyguardWallpaperMap.put(userId, keyguardWallpaper);
+ }
+ boolean success = false;
+ try {
+ stream = new FileInputStream(file);
+ XmlPullParser parser = Xml.newPullParser();
+ parser.setInput(stream, null);
+
+ int type;
+ do {
+ type = parser.next();
+ if (type == XmlPullParser.START_TAG) {
+ String tag = parser.getName();
+ if ("kwp".equals(tag)) {
+ keyguardWallpaper.width = Integer.parseInt(parser.getAttributeValue(null,
+ "width"));
+ keyguardWallpaper.height = Integer.parseInt(parser
+ .getAttributeValue(null, "height"));
+ keyguardWallpaper.name = parser.getAttributeValue(null, "name");
+ if (DEBUG) {
+ Slog.v(TAG, "mWidth:" + keyguardWallpaper.width);
+ Slog.v(TAG, "mHeight:" + keyguardWallpaper.height);
+ Slog.v(TAG, "mName:" + keyguardWallpaper.name);
+ }
+ }
+ }
+ } while (type != XmlPullParser.END_DOCUMENT);
+ success = true;
+ } catch (FileNotFoundException e) {
+ Slog.w(TAG, "no current wallpaper -- first boot?");
+ } catch (NullPointerException e) {
+ Slog.w(TAG, "failed parsing " + file + " " + e);
+ } catch (NumberFormatException e) {
+ Slog.w(TAG, "failed parsing " + file + " " + e);
+ } catch (XmlPullParserException e) {
+ Slog.w(TAG, "failed parsing " + file + " " + e);
+ } catch (IOException e) {
+ Slog.w(TAG, "failed parsing " + file + " " + e);
+ } catch (IndexOutOfBoundsException e) {
+ Slog.w(TAG, "failed parsing " + file + " " + e);
+ }
+ try {
+ if (stream != null) {
+ stream.close();
+ }
+ } catch (IOException e) {
+ // Ignore
+ }
+
+ if (!success) {
+ keyguardWallpaper.width = -1;
+ keyguardWallpaper.height = -1;
+ keyguardWallpaper.name = "";
+ }
+
+ // We always want to have some reasonable width hint.
+ int baseSize = getMaximumSizeDimension();
+ if (keyguardWallpaper.width < baseSize) {
+ keyguardWallpaper.width = baseSize;
+ }
+ if (keyguardWallpaper.height < baseSize) {
+ keyguardWallpaper.height = baseSize;
+ }
+ }
+
private int getMaximumSizeDimension() {
WindowManager wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
Display d = wm.getDefaultDisplay();
diff --git a/services/core/java/com/android/server/wm/BlurLayer.java b/services/core/java/com/android/server/wm/BlurLayer.java
new file mode 100644
index 0000000..b54ac9e
--- /dev/null
+++ b/services/core/java/com/android/server/wm/BlurLayer.java
@@ -0,0 +1,313 @@
+/*
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ *
+ * Copyright (C) 2014 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.wm;
+
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.os.SystemClock;
+import android.util.Slog;
+import android.view.DisplayInfo;
+import android.view.SurfaceControl;
+
+import java.io.PrintWriter;
+
+public class BlurLayer {
+ private static final String TAG = "BlurLayer";
+ private static final boolean DEBUG = false;
+
+ /** Reference to the owner of this object. */
+ final DisplayContent mDisplayContent;
+
+ /** Actual surface that blurs */
+ SurfaceControl mBlurSurface;
+
+ /** Last value passed to mBlurSurface.setBlur() */
+ float mBlur = 0;
+
+ /** Last value passed to mBlurSurface.setLayer() */
+ int mLayer = -1;
+
+ /** Next values to pass to mBlurSurface.setPosition() and mBlurSurface.setSize() */
+ Rect mBounds = new Rect();
+
+ /** Last values passed to mBlurSurface.setPosition() and mBlurSurface.setSize() */
+ Rect mLastBounds = new Rect();
+
+ /** True after mBlurSurface.show() has been called, false after mBlurSurface.hide(). */
+ private boolean mShowing = false;
+
+ /** Value of mBlur when beginning transition to mTargetBlur */
+ float mStartBlur = 0;
+
+ /** Final value of mBlur following transition */
+ float mTargetBlur = 0;
+
+ /** Time in units of SystemClock.uptimeMillis() at which the current transition started */
+ long mStartTime;
+
+ /** Time in milliseconds to take to transition from mStartBlur to mTargetBlur */
+ long mDuration;
+
+ /** Owning stack */
+ final TaskStack mStack;
+
+ BlurLayer(WindowManagerService service, TaskStack stack, DisplayContent displayContent) {
+ mStack = stack;
+ mDisplayContent = displayContent;
+ final int displayId = mDisplayContent.getDisplayId();
+ if (DEBUG) Slog.v(TAG, "Ctor: displayId=" + displayId);
+ SurfaceControl.openTransaction();
+ try {
+ if (WindowManagerService.DEBUG_SURFACE_TRACE) {
+ mBlurSurface = new WindowStateAnimator.SurfaceTrace(service.mFxSession,
+ "BlurSurface",
+ 16, 16, PixelFormat.OPAQUE,
+ SurfaceControl.FX_SURFACE_BLUR | SurfaceControl.HIDDEN);
+ } else {
+ mBlurSurface = new SurfaceControl(service.mFxSession, TAG,
+ 16, 16, PixelFormat.OPAQUE,
+ SurfaceControl.FX_SURFACE_BLUR | SurfaceControl.HIDDEN);
+ }
+ if (WindowManagerService.SHOW_TRANSACTIONS ||
+ WindowManagerService.SHOW_SURFACE_ALLOC) Slog.i(TAG,
+ " BLUR " + mBlurSurface + ": CREATE");
+ mBlurSurface.setLayerStack(displayId);
+ } catch (Exception e) {
+ Slog.e(WindowManagerService.TAG, "Exception creating Blur surface", e);
+ } finally {
+ SurfaceControl.closeTransaction();
+ }
+ }
+
+ /** Return true if blur layer is showing */
+ boolean isBlurring() {
+ return mTargetBlur != 0;
+ }
+
+ /** Return true if in a transition period */
+ boolean isAnimating() {
+ return mTargetBlur != mBlur;
+ }
+
+ float getTargetBlur() {
+ return mTargetBlur;
+ }
+
+ void setLayer(int layer) {
+ if (mLayer != layer) {
+ mLayer = layer;
+ mBlurSurface.setLayer(layer);
+ }
+ }
+
+ int getLayer() {
+ return mLayer;
+ }
+
+ private void setBlur(float blur) {
+ if (mBlur != blur) {
+ if (DEBUG) Slog.v(TAG, "setBlur blur=" + blur);
+ try {
+ mBlurSurface.setBlur(blur);
+ if (blur == 0 && mShowing) {
+ if (DEBUG) Slog.v(TAG, "setBlur hiding");
+ mBlurSurface.hide();
+ mShowing = false;
+ } else if (blur > 0 && !mShowing) {
+ if (DEBUG) Slog.v(TAG, "setBlur showing");
+ mBlurSurface.show();
+ mShowing = true;
+ }
+ } catch (RuntimeException e) {
+ Slog.w(TAG, "Failure setting blur immediately", e);
+ }
+ mBlur = blur;
+ }
+ }
+
+ void adjustBounds() {
+ final int dw, dh;
+ final float xPos, yPos;
+ if (!mStack.isFullscreen()) {
+ dw = mBounds.width();
+ dh = mBounds.height();
+ xPos = mBounds.left;
+ yPos = mBounds.top;
+ } else {
+ // Set surface size to screen size.
+ final DisplayInfo info = mDisplayContent.getDisplayInfo();
+ dw = info.logicalWidth;
+ dh = info.logicalHeight;
+ xPos = 0;
+ yPos = 0;
+ }
+
+ mBlurSurface.setPosition(xPos, yPos);
+ mBlurSurface.setSize(dw, dh);
+ mLastBounds.set(mBounds);
+ }
+
+ void setBounds(Rect bounds) {
+ mBounds.set(bounds);
+ if (isBlurring() && !mLastBounds.equals(bounds)) {
+ try {
+ SurfaceControl.openTransaction();
+ adjustBounds();
+ } catch (RuntimeException e) {
+ Slog.w(TAG, "Failure setting size", e);
+ } finally {
+ SurfaceControl.closeTransaction();
+ }
+ }
+ }
+
+ /**
+ * @param duration The time to test.
+ * @return True if the duration would lead to an earlier end to the current animation.
+ */
+ private boolean durationEndsEarlier(long duration) {
+ return SystemClock.uptimeMillis() + duration < mStartTime + mDuration;
+ }
+
+ /** Jump to the end of the animation.
+ * NOTE: Must be called with Surface transaction open. */
+ void show() {
+ if (isAnimating()) {
+ if (DEBUG) Slog.v(TAG, "show: immediate");
+ show(mLayer, mTargetBlur, 0);
+ }
+ }
+
+ /**
+ * Begin an animation to a new dim value.
+ * NOTE: Must be called with Surface transaction open.
+ *
+ * @param layer The layer to set the surface to.
+ * @param blur The dim value to end at.
+ * @param duration How long to take to get there in milliseconds.
+ */
+ void show(int layer, float blur, long duration) {
+ if (DEBUG) Slog.v(TAG, "show: layer=" + layer + " blur=" + blur
+ + " duration=" + duration);
+ if (mBlurSurface == null) {
+ Slog.e(TAG, "show: no Surface");
+ // Make sure isAnimating() returns false.
+ mTargetBlur = mBlur = 0;
+ return;
+ }
+
+ if (!mLastBounds.equals(mBounds)) {
+ adjustBounds();
+ }
+ setLayer(layer);
+
+ long curTime = SystemClock.uptimeMillis();
+ final boolean animating = isAnimating();
+ if ((animating && (mTargetBlur != blur || durationEndsEarlier(duration)))
+ || (!animating && mBlur != blur)) {
+ if (duration <= 0) {
+ // No animation required, just set values.
+ setBlur(blur);
+ } else {
+ // Start or continue animation with new parameters.
+ mStartBlur = mBlur;
+ mStartTime = curTime;
+ mDuration = duration;
+ }
+ }
+ if (DEBUG) Slog.v(TAG, "show: mStartBlur=" + mStartBlur + " mStartTime=" + mStartTime);
+ mTargetBlur = blur;
+ }
+
+ /** Immediate hide.
+ * NOTE: Must be called with Surface transaction open. */
+ void hide() {
+ if (mShowing) {
+ if (DEBUG) Slog.v(TAG, "hide: immediate");
+ hide(0);
+ }
+ }
+
+ /**
+ * Gradually fade to transparent.
+ * NOTE: Must be called with Surface transaction open.
+ *
+ * @param duration Time to fade in milliseconds.
+ */
+ void hide(long duration) {
+ if (mShowing && (mTargetBlur != 0 || durationEndsEarlier(duration))) {
+ if (DEBUG) Slog.v(TAG, "hide: duration=" + duration);
+ show(mLayer, 0, duration);
+ }
+ }
+
+ /**
+ * Advance the dimming per the last #show(int, float, long) call.
+ * NOTE: Must be called with Surface transaction open.
+ *
+ * @return True if animation is still required after this step.
+ */
+ boolean stepAnimation() {
+ if (mBlurSurface == null) {
+ Slog.e(TAG, "stepAnimation: null Surface");
+ // Ensure that isAnimating() returns false;
+ mTargetBlur = mBlur = 0;
+ return false;
+ }
+
+ if (isAnimating()) {
+ final long curTime = SystemClock.uptimeMillis();
+ final float blurDelta = mTargetBlur - mStartBlur;
+ float blur = mStartBlur + blurDelta * (curTime - mStartTime) / mDuration;
+ if (blurDelta > 0 && blur > mTargetBlur ||
+ blurDelta < 0 && blur < mTargetBlur) {
+ // Don't exceed limits.
+ blur = mTargetBlur;
+ }
+ if (DEBUG) Slog.v(TAG, "stepAnimation: curTime=" + curTime + " blur=" + blur);
+ setBlur(blur);
+ }
+
+ return isAnimating();
+ }
+
+ /** Cleanup */
+ void destroySurface() {
+ if (DEBUG) Slog.v(TAG, "destroySurface.");
+ if (mBlurSurface != null) {
+ mBlurSurface.destroy();
+ mBlurSurface = null;
+ }
+ }
+
+ public void printTo(String prefix, PrintWriter pw) {
+ pw.print(prefix); pw.print("mBlurSurface="); pw.print(mBlurSurface);
+ pw.print(" mLayer="); pw.print(mLayer);
+ pw.print(" mBlur="); pw.println(mBlur);
+ pw.print(prefix); pw.print("mLastBounds="); pw.print(mLastBounds.toShortString());
+ pw.print(" mBounds="); pw.println(mBounds.toShortString());
+ pw.print(prefix); pw.print("Last animation: ");
+ pw.print(" mDuration="); pw.print(mDuration);
+ pw.print(" mStartTime="); pw.print(mStartTime);
+ pw.print(" curTime="); pw.println(SystemClock.uptimeMillis());
+ pw.print(prefix); pw.print(" mStartBlur="); pw.print(mStartBlur);
+ pw.print(" mTargetBlur="); pw.println(mTargetBlur);
+ }
+}
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 4db0b1e..331ddbf 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -301,6 +301,35 @@ class DisplayContent {
}
}
+ boolean animateBlurLayers() {
+ boolean result = false;
+ for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
+ result |= mStacks.get(stackNdx).animateBlurLayers();
+ }
+ return result;
+ }
+
+ void resetBlurring() {
+ for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
+ mStacks.get(stackNdx).resetBlurringTag();
+ }
+ }
+
+ boolean isBlurring() {
+ for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
+ if (mStacks.get(stackNdx).isBlurring()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ void stopBlurringIfNeeded() {
+ for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
+ mStacks.get(stackNdx).stopBlurringIfNeeded();
+ }
+ }
+
void close() {
for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
mStacks.get(stackNdx).close();
diff --git a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
index 7dd716e..7e5c807 100644
--- a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
+++ b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
@@ -51,6 +51,7 @@ class ScreenRotationAnimation {
BlackFrame mExitingBlackFrame;
BlackFrame mEnteringBlackFrame;
int mWidth, mHeight;
+ int mSnapshotRotation;
int mOriginalRotation;
int mOriginalWidth, mOriginalHeight;
@@ -221,13 +222,26 @@ class ScreenRotationAnimation {
originalWidth = displayInfo.logicalWidth;
originalHeight = displayInfo.logicalHeight;
}
- if (originalRotation == Surface.ROTATION_90
- || originalRotation == Surface.ROTATION_270) {
- mWidth = originalHeight;
- mHeight = originalWidth;
+ // Allow for abnormal hardware orientation
+ mSnapshotRotation = (4 - android.os.SystemProperties.getInt("ro.sf.hwrotation",0) / 90) % 4;
+ if (mSnapshotRotation == Surface.ROTATION_0 || mSnapshotRotation == Surface.ROTATION_180) {
+ if (originalRotation == Surface.ROTATION_90
+ || originalRotation == Surface.ROTATION_270) {
+ mWidth = originalHeight;
+ mHeight = originalWidth;
+ } else {
+ mWidth = originalWidth;
+ mHeight = originalHeight;
+ }
} else {
- mWidth = originalWidth;
- mHeight = originalHeight;
+ if (originalRotation == Surface.ROTATION_90
+ || originalRotation == Surface.ROTATION_270) {
+ mWidth = originalWidth;
+ mHeight = originalHeight;
+ } else {
+ mWidth = originalHeight;
+ mHeight = originalWidth;
+ }
}
mOriginalRotation = originalRotation;
@@ -346,7 +360,7 @@ class ScreenRotationAnimation {
// Compute the transformation matrix that must be applied
// to the snapshot to make it stay in the same original position
// with the current screen rotation.
- int delta = DisplayContent.deltaRotation(rotation, Surface.ROTATION_0);
+ int delta = DisplayContent.deltaRotation(rotation, mSnapshotRotation);
createRotationMatrix(delta, mWidth, mHeight, mSnapshotInitialMatrix);
if (DEBUG_STATE) Slog.v(TAG, "**** ROTATION: " + delta);
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index a8ba0f9..f0793b8 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -429,6 +429,34 @@ final class Session extends IWindowSession.Stub
}
}
+ /**
+ * @hide
+ */
+ public int getLastWallpaperX() {
+ synchronized(mService.mWindowMap) {
+ long ident = Binder.clearCallingIdentity();
+ try {
+ return mService.getLastWallpaperX();
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+ }
+
+ /**
+ * @hide
+ */
+ public int getLastWallpaperY() {
+ synchronized(mService.mWindowMap) {
+ long ident = Binder.clearCallingIdentity();
+ try {
+ return mService.getLastWallpaperY();
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+ }
+
public Bundle sendWallpaperCommand(IBinder window, String action, int x, int y,
int z, Bundle extras, boolean sync) {
synchronized(mService.mWindowMap) {
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index 985bbfb..480da44 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -37,6 +37,8 @@ public class TaskStack {
/** Amount of time in milliseconds to animate the dim surface from one value to another,
* when no window animation is driving it. */
private static final int DEFAULT_DIM_DURATION = 200;
+ private static final int DEFAULT_BLUR_DURATION = 50;
+ private static final float MAX_BLUR_AMOUNT = 1.0f;
/** Unique identifier */
final int mStackId;
@@ -78,6 +80,10 @@ public class TaskStack {
* then stop any dimming. */
boolean mDimmingTag;
+ boolean mBlurringTag;
+ BlurLayer mBlurLayer;
+ WindowStateAnimator mBlurWinAnimator;
+
/** Application tokens that are exiting, but still on screen for animations. */
final AppTokenList mExitingAppTokens = new AppTokenList();
@@ -162,6 +168,7 @@ public class TaskStack {
}
mDimLayer.setBounds(bounds);
+ mBlurLayer.setBounds(bounds);
mAnimationBackgroundSurface.setBounds(bounds);
mBounds.set(bounds);
mRotation = rotation;
@@ -363,6 +370,7 @@ public class TaskStack {
mDisplayContent = displayContent;
mDimLayer = new DimLayer(mService, this, displayContent);
mAnimationBackgroundSurface = new DimLayer(mService, this, displayContent);
+ mBlurLayer = new BlurLayer(mService, this, displayContent);
updateDisplayInfo();
}
@@ -386,7 +394,6 @@ public class TaskStack {
if (doAnotherLayoutPass) {
mService.requestTraversalLocked();
}
-
close();
}
@@ -395,6 +402,10 @@ public class TaskStack {
mAnimationBackgroundSurface.hide();
}
+ private long getBlurBehindFadeDuration(long duration) {
+ return getDimBehindFadeDuration(duration);
+ }
+
private long getDimBehindFadeDuration(long duration) {
TypedValue tv = new TypedValue();
mService.mContext.getResources().getValue(
@@ -498,6 +509,82 @@ public class TaskStack {
}
}
+ boolean animateBlurLayers() {
+ boolean result = false;
+ final int blurLayer;
+ final float blurAmount;
+ if (mBlurWinAnimator == null) {
+ blurLayer = mBlurLayer.getLayer();
+ blurAmount = 0;
+ } else {
+ blurLayer = mBlurWinAnimator.mAnimLayer - WindowManagerService.LAYER_OFFSET_BLUR;
+ blurAmount = mBlurWinAnimator.mWin.mAttrs.blurAmount;
+ }
+ final float targetBlur = mBlurLayer.getTargetBlur();
+ if (targetBlur != blurAmount) {
+ if (mBlurWinAnimator == null) {
+ mBlurLayer.hide(DEFAULT_BLUR_DURATION);
+ } else {
+ long duration = (mBlurWinAnimator.mAnimating && mBlurWinAnimator.mAnimation != null)
+ ? mBlurWinAnimator.mAnimation.computeDurationHint()
+ : DEFAULT_BLUR_DURATION;
+ if (targetBlur > blurAmount) {
+ duration = getBlurBehindFadeDuration(duration);
+ }
+ if (duration > DEFAULT_BLUR_DURATION)
+ duration = DEFAULT_BLUR_DURATION;
+ mBlurLayer.show(blurLayer, blurAmount, duration);
+ }
+ } else if (mBlurLayer.getLayer() != blurLayer) {
+ mBlurLayer.setLayer(blurLayer);
+ }
+ if (mBlurLayer.isAnimating()) {
+ if (!mService.okToDisplay()) {
+ // Jump to the end of the animation.
+ mBlurLayer.show();
+ } else {
+ result = mBlurLayer.stepAnimation();
+ }
+ }
+ return result;
+ }
+
+ void resetBlurringTag() {
+ mBlurringTag = false;
+ }
+
+ void setBlurringTag() {
+ mBlurringTag = true;
+ }
+
+ boolean testBlurringTag() {
+ return mBlurringTag;
+ }
+
+ boolean isBlurring() {
+ return mBlurLayer.isBlurring();
+ }
+
+ boolean isBlurring(WindowStateAnimator winAnimator) {
+ return mBlurWinAnimator == winAnimator && mBlurLayer.isBlurring();
+ }
+
+ void stopBlurringIfNeeded() {
+ if (!mBlurringTag && isBlurring()) {
+ mBlurWinAnimator = null;
+ }
+ }
+
+ void startBlurringIfNeeded(WindowStateAnimator newWinAnimator) {
+ final WindowStateAnimator existingBlurWinAnimator = mBlurWinAnimator;
+ // Don't turn on for an unshown surface, or for any layer but the highest blur layer.
+ if (newWinAnimator.mSurfaceShown && (existingBlurWinAnimator == null
+ || !existingBlurWinAnimator.mSurfaceShown
+ || existingBlurWinAnimator.mAnimLayer < newWinAnimator.mAnimLayer)) {
+ mBlurWinAnimator = newWinAnimator;
+ }
+ }
+
void switchUser() {
int top = mTasks.size();
for (int taskNdx = 0; taskNdx < top; ++taskNdx) {
@@ -519,6 +606,10 @@ public class TaskStack {
mDimLayer.destroySurface();
mDimLayer = null;
}
+ if (mBlurLayer != null) {
+ mBlurLayer.destroySurface();
+ mBlurLayer = null;
+ }
mDisplayContent = null;
}
@@ -537,6 +628,11 @@ public class TaskStack {
mDimLayer.printTo(prefix + " ", pw);
pw.print(prefix); pw.print("mDimWinAnimator="); pw.println(mDimWinAnimator);
}
+ if (mBlurLayer.isBlurring()) {
+ pw.print(prefix); pw.println("mBlurLayer:");
+ mBlurLayer.printTo(prefix, pw);
+ pw.print(prefix); pw.print("mBlurWinAnimator="); pw.println(mBlurWinAnimator);
+ }
if (!mExitingAppTokens.isEmpty()) {
pw.println();
pw.println(" Exiting application tokens:");
diff --git a/services/core/java/com/android/server/wm/Watermark.java b/services/core/java/com/android/server/wm/Watermark.java
index e226e3d..3ae783e 100644
--- a/services/core/java/com/android/server/wm/Watermark.java
+++ b/services/core/java/com/android/server/wm/Watermark.java
@@ -23,6 +23,7 @@ import android.graphics.PorterDuff;
import android.graphics.Rect;
import android.graphics.Typeface;
import android.graphics.Paint.FontMetricsInt;
+import android.os.SystemProperties;
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.TypedValue;
@@ -76,6 +77,14 @@ class Watermark {
else c2 -= '0';
builder.append((char)(255-((c1*16)+c2)));
}
+
+ int appendDisplayVersion = (WindowManagerService.getPropertyInt(tokens, 10,
+ TypedValue.COMPLEX_UNIT_PX, 0, dm));
+ if (appendDisplayVersion != 0) {
+ builder.append(" - ");
+ builder.append(SystemProperties.get("ro.cm.display.version"));
+ }
+
mText = builder.toString();
if (false) {
Log.i(WindowManagerService.TAG, "Final text: " + mText);
@@ -149,27 +158,32 @@ class Watermark {
if (c != null) {
c.drawColor(0, PorterDuff.Mode.CLEAR);
- int deltaX = mDeltaX;
- int deltaY = mDeltaY;
-
- // deltaX shouldn't be close to a round fraction of our
- // x step, or else things will line up too much.
- int div = (dw+mTextWidth)/deltaX;
- int rem = (dw+mTextWidth) - (div*deltaX);
- int qdelta = deltaX/4;
- if (rem < qdelta || rem > (deltaX-qdelta)) {
- deltaX += deltaX/3;
- }
+ if (mDeltaX != 0 || mDeltaY != 0) {
+ int deltaX = mDeltaX;
+ int deltaY = mDeltaY;
+
+ // deltaX shouldn't be close to a round fraction of our
+ // x step, or else things will line up too much.
+ int div = (dw+mTextWidth)/deltaX;
+ int rem = (dw+mTextWidth) - (div*deltaX);
+ int qdelta = deltaX/4;
+ if (rem < qdelta || rem > (deltaX-qdelta)) {
+ deltaX += deltaX/3;
+ }
- int y = -mTextHeight;
- int x = -mTextWidth;
- while (y < (dh+mTextHeight)) {
- c.drawText(mText, x, y, mTextPaint);
- x += deltaX;
- if (x >= dw) {
- x -= (dw+mTextWidth);
- y += deltaY;
+ int y = -mTextHeight;
+ int x = -mTextWidth;
+ while (y < (dh+mTextHeight)) {
+ c.drawText(mText, x, y, mTextPaint);
+ x += deltaX;
+ if (x >= dw) {
+ x -= (dw+mTextWidth);
+ y += deltaY;
+ }
}
+ } else {
+ c.drawText(mText, dw - mTextWidth,
+ dh - mTextHeight*4, mTextPaint);
}
mSurface.unlockCanvasAndPost(c);
}
diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java
index 85a9624..5d9878f 100644
--- a/services/core/java/com/android/server/wm/WindowAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowAnimator.java
@@ -92,10 +92,13 @@ public class WindowAnimator {
boolean mKeyguardGoingAway;
boolean mKeyguardGoingAwayToNotificationShade;
boolean mKeyguardGoingAwayDisableWindowAnimations;
+ boolean mKeyguardGoingAwayShowingMedia;
/** Use one animation for all entering activities after keyguard is dismissed. */
Animation mPostKeyguardExitAnimation;
+ private final boolean mBlurUiEnabled;
+
// forceHiding states.
static final int KEYGUARD_NOT_SHOWN = 0;
static final int KEYGUARD_SHOWN = 1;
@@ -116,6 +119,9 @@ public class WindowAnimator {
mContext = service.mContext;
mPolicy = service.mPolicy;
+ mBlurUiEnabled = mContext.getResources().getBoolean(
+ com.android.internal.R.bool.config_ui_blur_enabled);
+
mAnimationFrameCallback = new Choreographer.FrameCallback() {
public void doFrame(long frameTimeNs) {
synchronized (mService.mWindowMap) {
@@ -214,7 +220,7 @@ public class WindowAnimator {
// Only hide windows if the keyguard is active and not animating away.
boolean keyguardOn = mPolicy.isKeyguardShowingOrOccluded()
- && mForceHiding != KEYGUARD_ANIMATING_OUT;
+ && (mForceHiding != KEYGUARD_ANIMATING_OUT && !mBlurUiEnabled);
return keyguardOn && !allowWhenLocked && (win.getDisplayId() == Display.DEFAULT_DISPLAY);
}
@@ -223,7 +229,7 @@ public class WindowAnimator {
final WindowList windows = mService.getWindowListLocked(displayId);
- if (mKeyguardGoingAway) {
+ if (mKeyguardGoingAway && !mBlurUiEnabled) {
for (int i = windows.size() - 1; i >= 0; i--) {
WindowState win = windows.get(i);
if (!mPolicy.isKeyguardHostWindow(win.mAttrs)) {
@@ -237,7 +243,8 @@ public class WindowAnimator {
// Create a new animation to delay until keyguard is gone on its own.
winAnimator.mAnimation = new AlphaAnimation(1.0f, 1.0f);
- winAnimator.mAnimation.setDuration(KEYGUARD_ANIM_TIMEOUT_MS);
+ winAnimator.mAnimation.setDuration(
+ mBlurUiEnabled ? 0 : KEYGUARD_ANIM_TIMEOUT_MS);
winAnimator.mAnimationIsEntrance = false;
winAnimator.mAnimationStartTime = -1;
winAnimator.mKeyguardGoingAwayAnimation = true;
@@ -327,7 +334,8 @@ public class WindowAnimator {
if (nowAnimating && win.mWinAnimator.mKeyguardGoingAwayAnimation) {
mForceHiding = KEYGUARD_ANIMATING_OUT;
} else {
- mForceHiding = win.isDrawnLw() ? KEYGUARD_SHOWN : KEYGUARD_NOT_SHOWN;
+ mForceHiding = win.isDrawnLw() && !mBlurUiEnabled ?
+ KEYGUARD_SHOWN : KEYGUARD_NOT_SHOWN;
}
}
if (DEBUG_KEYGUARD || WindowManagerService.DEBUG_VISIBILITY) Slog.v(TAG,
@@ -486,7 +494,7 @@ public class WindowAnimator {
&& !mKeyguardGoingAwayDisableWindowAnimations) {
if (DEBUG_KEYGUARD) Slog.d(TAG, "updateWindowsLocked: wallpaper animating away");
Animation a = mPolicy.createForceHideWallpaperExitAnimation(
- mKeyguardGoingAwayToNotificationShade);
+ mKeyguardGoingAwayToNotificationShade, mKeyguardGoingAwayShowingMedia);
if (a != null) {
wallpaper.mWinAnimator.setAnimation(a);
}
@@ -697,6 +705,7 @@ public class WindowAnimator {
}
mAnimating |= mService.getDisplayContentLocked(displayId).animateDimLayers();
+ mAnimating |= mService.getDisplayContentLocked(displayId).animateBlurLayers();
//TODO (multidisplay): Magnification is supported only for the default display.
if (mService.mAccessibilityController != null
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 71bbdb6..60ddd85 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -154,7 +154,9 @@ import java.util.List;
import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
+import static android.view.WindowManager.LayoutParams.FLAG_BLUR_BEHIND;
import static android.view.WindowManager.LayoutParams.FLAG_DIM_BEHIND;
+import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
import static android.view.WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
import static android.view.WindowManager.LayoutParams.FLAG_SECURE;
@@ -247,7 +249,17 @@ public class WindowManagerService extends IWindowManager.Stub
/**
* Dim surface layer is immediately below target window.
*/
- static final int LAYER_OFFSET_DIM = 1;
+ static final int LAYER_OFFSET_DIM = 1+1;
+
+ /**
+ * Blur surface layer is immediately below dim layer.
+ */
+ static final int LAYER_OFFSET_BLUR = 2+1;
+
+ /**
+ * Blur_with_masking layer is immediately below blur layer.
+ */
+ static final int LAYER_OFFSET_BLUR_WITH_MASKING = 1;
/**
* FocusedStackFrame layer is immediately above focused window.
@@ -298,6 +310,7 @@ public class WindowManagerService extends IWindowManager.Stub
private static final String SYSTEM_SECURE = "ro.secure";
private static final String SYSTEM_DEBUGGABLE = "ro.debuggable";
+ private static final String PERSIST_SYS_LCD_DENSITY = "persist.sys.lcd_density";
private static final String DENSITY_OVERRIDE = "ro.config.density_override";
private static final String SIZE_OVERRIDE = "ro.config.size_override";
@@ -307,6 +320,8 @@ public class WindowManagerService extends IWindowManager.Stub
final private KeyguardDisableHandler mKeyguardDisableHandler;
+ private final int mSfHwRotation;
+
final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
@@ -997,6 +1012,9 @@ public class WindowManagerService extends IWindowManager.Stub
SurfaceControl.closeTransaction();
}
+ // Load hardware rotation from prop
+ mSfHwRotation = android.os.SystemProperties.getInt("ro.sf.hwrotation",0) / 90;
+
updateCircularDisplayMaskIfNeeded();
showEmulatorDisplayOverlayIfNeeded();
}
@@ -2145,6 +2163,36 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
+ public int getLastWallpaperX() {
+ int curTokenIndex = mWallpaperTokens.size();
+ while (curTokenIndex > 0) {
+ curTokenIndex--;
+ WindowToken token = mWallpaperTokens.get(curTokenIndex);
+ int curWallpaperIndex = token.windows.size();
+ while (curWallpaperIndex > 0) {
+ curWallpaperIndex--;
+ WindowState wallpaperWin = token.windows.get(curWallpaperIndex);
+ return wallpaperWin.mXOffset;
+ }
+ }
+ return -1;
+ }
+
+ public int getLastWallpaperY() {
+ int curTokenIndex = mWallpaperTokens.size();
+ while (curTokenIndex > 0) {
+ curTokenIndex--;
+ WindowToken token = mWallpaperTokens.get(curTokenIndex);
+ int curWallpaperIndex = token.windows.size();
+ while (curWallpaperIndex > 0) {
+ curWallpaperIndex--;
+ WindowState wallpaperWin = token.windows.get(curWallpaperIndex);
+ return wallpaperWin.mYOffset;
+ }
+ }
+ return -1;
+ }
+
boolean updateWallpaperOffsetLocked(WindowState wallpaperWin, int dw, int dh,
boolean sync) {
boolean changed = false;
@@ -2734,7 +2782,7 @@ public class WindowManagerService extends IWindowManager.Stub
// to hold off on removing the window until the animation is done.
// If the display is frozen, just remove immediately, since the
// animation wouldn't be seen.
- if (win.mHasSurface && okToDisplay()) {
+ if (win.mHasSurface && okToDisplay() && !win.mBinderDied) {
// If we are not currently running the exit animation, we
// need to see about starting one.
wasVisible = win.isWinVisibleLw();
@@ -3800,7 +3848,7 @@ public class WindowManagerService extends IWindowManager.Stub
}
public int getOrientationLocked() {
- if (mDisplayFrozen) {
+ if (mDisplayFrozen || mAppsFreezingScreen > 0) {
if (mLastWindowForcedOrientation != ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED) {
if (DEBUG_ORIENTATION) Slog.v(TAG, "Display is frozen, return "
+ mLastWindowForcedOrientation);
@@ -3825,8 +3873,8 @@ public class WindowManagerService extends IWindowManager.Stub
continue;
}
int req = win.mAttrs.screenOrientation;
- if((req == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED) ||
- (req == ActivityInfo.SCREEN_ORIENTATION_BEHIND)){
+ if ((req == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED) ||
+ (req == ActivityInfo.SCREEN_ORIENTATION_BEHIND)) {
continue;
}
@@ -3856,7 +3904,7 @@ public class WindowManagerService extends IWindowManager.Stub
}
if (DEBUG_ORIENTATION) Slog.v(TAG,
"No one is requesting an orientation when the screen is locked");
- return mLastKeyguardForcedOrientation;
+ return mLastWindowForcedOrientation = mLastKeyguardForcedOrientation;
}
}
@@ -5466,7 +5514,7 @@ public class WindowManagerService extends IWindowManager.Stub
@Override
public void keyguardGoingAway(boolean disableWindowAnimations,
- boolean keyguardGoingToNotificationShade) {
+ boolean keyguardGoingToNotificationShade, boolean keyguardShowingMedia) {
if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DISABLE_KEYGUARD)
!= PackageManager.PERMISSION_GRANTED) {
throw new SecurityException("Requires DISABLE_KEYGUARD permission");
@@ -5477,6 +5525,7 @@ public class WindowManagerService extends IWindowManager.Stub
mAnimator.mKeyguardGoingAway = true;
mAnimator.mKeyguardGoingAwayToNotificationShade = keyguardGoingToNotificationShade;
mAnimator.mKeyguardGoingAwayDisableWindowAnimations = disableWindowAnimations;
+ mAnimator.mKeyguardGoingAwayShowingMedia = keyguardShowingMedia;
requestTraversalLocked();
}
}
@@ -5621,6 +5670,11 @@ public class WindowManagerService extends IWindowManager.Stub
mPointerEventDispatcher.unregisterInputEventListener(listener);
}
+ @Override
+ public void addSystemUIVisibilityFlag(int flags) {
+ mLastStatusBarVisibility |= flags;
+ }
+
// Called by window manager policy. Not exposed externally.
@Override
public int getLidState() {
@@ -5777,7 +5831,7 @@ public class WindowManagerService extends IWindowManager.Stub
boolean wallpaperEnabled = mContext.getResources().getBoolean(
com.android.internal.R.bool.config_enableWallpaperService)
&& !mOnlyCore;
- boolean haveKeyguard = true;
+ boolean haveKeyguard = false;
// TODO(multidisplay): Expand to all displays?
final WindowList windows = getDefaultWindowListLocked();
final int N = windows.size();
@@ -6202,10 +6256,13 @@ public class WindowManagerService extends IWindowManager.Stub
int retryCount = 0;
WindowState appWin = null;
- final boolean appIsImTarget = mInputMethodTarget != null
- && mInputMethodTarget.mAppToken != null
- && mInputMethodTarget.mAppToken.appToken != null
- && mInputMethodTarget.mAppToken.appToken.asBinder() == appToken;
+ boolean appIsImTarget;
+ synchronized(mWindowMap) {
+ appIsImTarget = mInputMethodTarget != null
+ && mInputMethodTarget.mAppToken != null
+ && mInputMethodTarget.mAppToken.appToken != null
+ && mInputMethodTarget.mAppToken.appToken.asBinder() == appToken;
+ }
final int aboveAppLayer = (mPolicy.windowTypeToLayerLw(TYPE_APPLICATION) + 1)
* TYPE_LAYER_MULTIPLIER + TYPE_LAYER_OFFSET;
@@ -6359,6 +6416,8 @@ public class WindowManagerService extends IWindowManager.Stub
// The screenshot API does not apply the current screen rotation.
int rot = getDefaultDisplayContentLocked().getDisplay().getRotation();
+ // Allow for abnormal hardware orientation
+ rot = (rot + mSfHwRotation) % 4;
if (rot == Surface.ROTATION_90 || rot == Surface.ROTATION_270) {
rot = (rot == Surface.ROTATION_90) ? Surface.ROTATION_270 : Surface.ROTATION_90;
@@ -8558,6 +8617,9 @@ public class WindowManagerService extends IWindowManager.Stub
@Override
public int getInitialDisplayDensity(int displayId) {
+ if (displayId == Display.DEFAULT_DISPLAY) {
+ return DisplayMetrics.DENSITY_DEVICE_DEFAULT;
+ }
synchronized (mWindowMap) {
final DisplayContent displayContent = getDisplayContentLocked(displayId);
if (displayContent != null && displayContent.hasAccess(Binder.getCallingUid())) {
@@ -8571,6 +8633,9 @@ public class WindowManagerService extends IWindowManager.Stub
@Override
public int getBaseDisplayDensity(int displayId) {
+ if (displayId == Display.DEFAULT_DISPLAY) {
+ return DisplayMetrics.DENSITY_PREFERRED;
+ }
synchronized (mWindowMap) {
final DisplayContent displayContent = getDisplayContentLocked(displayId);
if (displayContent != null && displayContent.hasAccess(Binder.getCallingUid())) {
@@ -8598,6 +8663,7 @@ public class WindowManagerService extends IWindowManager.Stub
synchronized(mWindowMap) {
final DisplayContent displayContent = getDisplayContentLocked(displayId);
if (displayContent != null) {
+ SystemProperties.set(PERSIST_SYS_LCD_DENSITY, Integer.toString(density));
setForcedDisplayDensityLocked(displayContent, density);
Settings.Global.putString(mContext.getContentResolver(),
Settings.Global.DISPLAY_DENSITY_FORCED, Integer.toString(density));
@@ -8606,6 +8672,10 @@ public class WindowManagerService extends IWindowManager.Stub
} finally {
Binder.restoreCallingIdentity(ident);
}
+ try {
+ ActivityManagerNative.getDefault().restart();
+ } catch (RemoteException e) {
+ }
}
// displayContent must not be null
@@ -8634,6 +8704,7 @@ public class WindowManagerService extends IWindowManager.Stub
synchronized(mWindowMap) {
final DisplayContent displayContent = getDisplayContentLocked(displayId);
if (displayContent != null) {
+ SystemProperties.set(PERSIST_SYS_LCD_DENSITY, null);
setForcedDisplayDensityLocked(displayContent,
displayContent.mInitialDisplayDensity);
Settings.Global.putString(mContext.getContentResolver(),
@@ -8643,6 +8714,10 @@ public class WindowManagerService extends IWindowManager.Stub
} finally {
Binder.restoreCallingIdentity(ident);
}
+ try {
+ ActivityManagerNative.getDefault().restart();
+ } catch (RemoteException e) {
+ }
}
// displayContent must not be null
@@ -8902,7 +8977,7 @@ public class WindowManagerService extends IWindowManager.Stub
anyLayerChanged = true;
}
final TaskStack stack = w.getStack();
- if (layerChanged && stack != null && stack.isDimming(winAnimator)) {
+ if (layerChanged && stack != null && (stack.isDimming(winAnimator) || stack.isBlurring(winAnimator))) {
// Force an animation pass just to update the mDimLayer layer.
scheduleAnimationLocked();
}
@@ -9804,6 +9879,31 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
+ private void handleFlagBlurBehind(WindowState w) {
+ final WindowManager.LayoutParams attrs = w.mAttrs;
+ if ((attrs.flags & FLAG_BLUR_BEHIND) != 0
+ && w.isDisplayedLw()
+ && !w.mExiting) {
+ final WindowStateAnimator winAnimator = w.mWinAnimator;
+ final TaskStack stack = w.getStack();
+ if (stack == null) {
+ return;
+ }
+ stack.setBlurringTag();
+ if (!stack.isBlurring(winAnimator)) {
+ if (localLOGV) Slog.v(TAG, "Win " + w + " start blurring");
+ stack.startBlurringIfNeeded(winAnimator);
+ }
+ }
+ }
+
+ private void handlePrivateFlagBlurWithMasking(WindowState w) {
+ final WindowManager.LayoutParams attrs = w.mAttrs;
+ boolean hideForced = !w.isDisplayedLw() || w.mExiting;
+ final WindowStateAnimator winAnimator = w.mWinAnimator;
+ winAnimator.updateBlurWithMaskingState(attrs, hideForced);
+ }
+
private void updateAllDrawnLocked(DisplayContent displayContent) {
// See if any windows have been drawn, so they (and others
// associated with them) can now be shown.
@@ -9979,6 +10079,7 @@ public class WindowManagerService extends IWindowManager.Stub
mInnerFields.mObscured = false;
mInnerFields.mSyswin = false;
displayContent.resetDimming();
+ displayContent.resetBlurring();
// Only used if default window
final boolean someoneLosingFocus = !mLosingFocus.isEmpty();
@@ -10003,6 +10104,11 @@ public class WindowManagerService extends IWindowManager.Stub
handleFlagDimBehind(w);
}
+ if (stack != null && !stack.testBlurringTag()) {
+ handleFlagBlurBehind(w);
+ }
+ handlePrivateFlagBlurWithMasking(w);
+
if (isDefaultDisplay && obscuredChanged && (mWallpaperTarget == w)
&& w.isVisibleLw()) {
// This is the wallpaper target and its obscured state
@@ -10142,6 +10248,7 @@ public class WindowManagerService extends IWindowManager.Stub
true /* inTraversal, must call performTraversalInTrans... below */);
getDisplayContentLocked(displayId).stopDimmingIfNeeded();
+ getDisplayContentLocked(displayId).stopBlurringIfNeeded();
if (updateAllDrawn) {
updateAllDrawnLocked(displayContent);
@@ -11097,6 +11204,16 @@ public class WindowManagerService extends IWindowManager.Stub
}
@Override
+ public boolean hasPermanentMenuKey() {
+ return mPolicy.hasPermanentMenuKey();
+ }
+
+ @Override
+ public boolean needsNavigationBar() {
+ return mPolicy.needsNavigationBar();
+ }
+
+ @Override
public void lockNow(Bundle options) {
mPolicy.lockNow(options);
}
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index c2548de..3bef41b 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -333,6 +333,9 @@ final class WindowState implements WindowManagerPolicy.WindowState {
/** Is this window now (or just being) removed? */
boolean mRemoved;
+ /** Is this window going to be removed from binderDied callback? */
+ boolean mBinderDied;
+
/**
* Temp for keeping track of windows that have been removed when
* rebuilding window list.
@@ -1209,9 +1212,11 @@ final class WindowState implements WindowManagerPolicy.WindowState {
WindowState win = mService.windowForClientLocked(mSession, mClient, false);
Slog.i(TAG, "WIN DEATH: " + win);
if (win != null) {
+ win.mBinderDied = true;
mService.removeWindowLocked(win);
} else if (mHasSurface) {
Slog.e(TAG, "!!! LEAK !!! Window removed but surface still valid.");
+ WindowState.this.mBinderDied = true;
mService.removeWindowLocked(WindowState.this);
}
}
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 42042b9..342a2ac 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -29,6 +29,7 @@ import static com.android.server.wm.WindowManagerService.SHOW_SURFACE_ALLOC;
import static com.android.server.wm.WindowManagerService.localLOGV;
import static com.android.server.wm.WindowManagerService.LayoutFields.SET_ORIENTATION_CHANGE_COMPLETE;
import static com.android.server.wm.WindowManagerService.LayoutFields.SET_TURN_ON_SCREEN;
+import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
import android.content.Context;
import android.graphics.Matrix;
@@ -94,6 +95,13 @@ class WindowStateAnimator {
SurfaceControl mSurfaceControl;
SurfaceControl mPendingDestroySurface;
+ int mLayerStack;
+
+ SurfaceControl mSurfaceControlBlur;
+ SurfaceControl mPendingDestroySurfaceBlur;
+ boolean mSurfaceBlurShown; // last value
+ boolean mSurfaceBlurScaleNeeded;
+ final static int BLUR_LAYER_OFFSET = WindowManagerService.LAYER_OFFSET_BLUR_WITH_MASKING;
/**
* Set when we have changed the size of the surface, to know that
@@ -503,6 +511,12 @@ class WindowStateAnimator {
} catch (RuntimeException e) {
Slog.w(TAG, "Exception hiding surface in " + mWin);
}
+ if (mSurfaceControlBlur != null) {
+ try { mSurfaceControlBlur.hide(); }
+ catch (RuntimeException e) {
+ Slog.w(TAG, "Exception hiding surface blur in " + mWin);
+ }
+ }
}
}
}
@@ -791,6 +805,24 @@ class WindowStateAnimator {
flags |= SurfaceControl.SECURE;
}
+ final boolean consumingNavBar =
+ (attrs.flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0
+ && (attrs.systemUiVisibility & View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) == 0
+ && (attrs.systemUiVisibility & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0;
+
+ final DisplayContent displayContent = w.getDisplayContent();
+
+ int defaultWidth = 1;
+ int defaultHeight = 1;
+ if (displayContent != null) {
+ final DisplayInfo displayInfo = displayContent.getDisplayInfo();
+ // When we need to expand the window with FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
+ // set the default width and height of the window to the size of the display
+ // we can use.
+ defaultWidth = consumingNavBar ? displayInfo.logicalWidth : displayInfo.appWidth;
+ defaultHeight = consumingNavBar ? displayInfo.logicalHeight : displayInfo.appHeight;
+ }
+
int width;
int height;
if ((attrs.flags & LayoutParams.FLAG_SCALED) != 0) {
@@ -799,17 +831,17 @@ class WindowStateAnimator {
width = w.mRequestedWidth;
height = w.mRequestedHeight;
} else {
- width = w.mCompatFrame.width();
- height = w.mCompatFrame.height();
+ width = consumingNavBar ? defaultWidth : w.mCompatFrame.width();
+ height = consumingNavBar ? defaultHeight : w.mCompatFrame.height();
}
// Something is wrong and SurfaceFlinger will not like this,
// try to revert to sane values
if (width <= 0) {
- width = 1;
+ width = defaultWidth;
}
if (height <= 0) {
- height = 1;
+ height = defaultHeight;
}
float left = w.mFrame.left + w.mXOffset;
@@ -916,9 +948,9 @@ class WindowStateAnimator {
try {
mSurfaceControl.setPosition(left, top);
mSurfaceLayer = mAnimLayer;
- final DisplayContent displayContent = w.getDisplayContent();
if (displayContent != null) {
- mSurfaceControl.setLayerStack(displayContent.getDisplay().getLayerStack());
+ mLayerStack = displayContent.getDisplay().getLayerStack();
+ mSurfaceControl.setLayerStack(mLayerStack);
}
mSurfaceControl.setLayer(mAnimLayer);
mSurfaceControl.setAlpha(0);
@@ -935,6 +967,7 @@ class WindowStateAnimator {
}
if (WindowManagerService.localLOGV) Slog.v(
TAG, "Created surface " + this);
+ updateBlurWithMaskingState(attrs, false);
}
return mSurfaceControl;
}
@@ -978,6 +1011,13 @@ class WindowStateAnimator {
}
mPendingDestroySurface = mSurfaceControl;
}
+
+ if (mSurfaceControlBlur != null && mPendingDestroySurfaceBlur != mSurfaceControlBlur) {
+ if (mPendingDestroySurfaceBlur != null) {
+ mPendingDestroySurfaceBlur.destroy();
+ }
+ mPendingDestroySurfaceBlur = mSurfaceControlBlur;
+ }
} else {
if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) {
RuntimeException e = null;
@@ -988,6 +1028,9 @@ class WindowStateAnimator {
WindowManagerService.logSurface(mWin, "DESTROY", e);
}
mSurfaceControl.destroy();
+ if (mSurfaceControlBlur != null) {
+ mSurfaceControlBlur.destroy();
+ }
}
mService.hideWallpapersLocked(mWin);
} catch (RuntimeException e) {
@@ -998,6 +1041,7 @@ class WindowStateAnimator {
mSurfaceShown = false;
mSurfaceControl = null;
+ mSurfaceControlBlur = null;
mWin.mHasSurface = false;
mDrawState = NO_SURFACE;
}
@@ -1015,6 +1059,9 @@ class WindowStateAnimator {
WindowManagerService.logSurface(mWin, "DESTROY PENDING", e);
}
mPendingDestroySurface.destroy();
+ if (mPendingDestroySurfaceBlur != null) {
+ mPendingDestroySurfaceBlur.destroy();
+ }
mService.hideWallpapersLocked(mWin);
}
} catch (RuntimeException e) {
@@ -1024,6 +1071,7 @@ class WindowStateAnimator {
}
mSurfaceDestroyDeferred = false;
mPendingDestroySurface = null;
+ mPendingDestroySurfaceBlur = null;
}
void computeShownFrameLocked() {
@@ -1400,6 +1448,9 @@ class WindowStateAnimator {
if (WindowManagerService.SHOW_TRANSACTIONS) WindowManagerService.logSurface(w,
"POS " + left + ", " + top, null);
mSurfaceControl.setPosition(left, top);
+ if (mSurfaceControlBlur != null) {
+ mSurfaceControlBlur.setPosition(left, top);
+ }
} catch (RuntimeException e) {
Slog.w(TAG, "Error positioning surface of " + w
+ " pos=(" + left + "," + top + ")", e);
@@ -1419,6 +1470,9 @@ class WindowStateAnimator {
if (WindowManagerService.SHOW_TRANSACTIONS) WindowManagerService.logSurface(w,
"SIZE " + width + "x" + height, null);
mSurfaceControl.setSize(width, height);
+ if (mSurfaceControlBlur != null) {
+ mSurfaceControlBlur.setSize(width, height);
+ }
mSurfaceControl.setMatrix(
mDsDx * w.mHScale, mDtDx * w.mVScale,
mDsDy * w.mHScale, mDtDy * w.mVScale);
@@ -1430,6 +1484,12 @@ class WindowStateAnimator {
stack.startDimmingIfNeeded(this);
}
}
+ if ((w.mAttrs.flags & LayoutParams.FLAG_BLUR_BEHIND) != 0) {
+ final TaskStack stack = w.getStack();
+ if (stack != null) {
+ stack.startBlurringIfNeeded(this);
+ }
+ }
} catch (RuntimeException e) {
// If something goes wrong with the surface (such
// as running out of memory), don't take down the
@@ -1515,6 +1575,14 @@ class WindowStateAnimator {
mDsDx * w.mHScale, mDtDx * w.mVScale,
mDsDy * w.mHScale, mDtDy * w.mVScale);
+ if (mSurfaceControlBlur != null) {
+ mSurfaceControlBlur.setAlpha(mShownAlpha);
+ mSurfaceControlBlur.setLayer(mAnimLayer-BLUR_LAYER_OFFSET);
+ mSurfaceControlBlur.setMatrix(
+ mDsDx*w.mHScale, mDtDx*w.mVScale,
+ mDsDy*w.mHScale, mDtDy*w.mVScale);
+ }
+
if (mLastHidden && mDrawState == HAS_DRAWN) {
if (WindowManagerService.SHOW_TRANSACTIONS) WindowManagerService.logSurface(w,
"SHOW (performLayout)", null);
@@ -1605,6 +1673,9 @@ class WindowStateAnimator {
if (WindowManagerService.SHOW_TRANSACTIONS) WindowManagerService.logSurface(mWin,
"POS " + left + ", " + top, null);
mSurfaceControl.setPosition(mWin.mFrame.left + left, mWin.mFrame.top + top);
+ if (mSurfaceControlBlur != null) {
+ mSurfaceControlBlur.setPosition(mWin.mFrame.left + left, mWin.mFrame.top + top);
+ }
updateSurfaceWindowCrop(false);
} catch (RuntimeException e) {
Slog.w(TAG, "Error positioning surface of " + mWin
@@ -1783,6 +1854,9 @@ class WindowStateAnimator {
if (mSurfaceControl != null) {
mSurfaceShown = true;
mSurfaceControl.show();
+ if (mSurfaceControlBlur != null) {
+ mSurfaceControlBlur.show();
+ }
if (mWin.mTurnOnScreen) {
if (DEBUG_VISIBILITY) Slog.v(TAG,
"Show surface turning screen on: " + mWin);
@@ -1977,4 +2051,66 @@ class WindowStateAnimator {
sb.append('}');
return sb.toString();
}
+
+ void updateBlurWithMaskingState(WindowManager.LayoutParams attrs, boolean hideForced) {
+ boolean blurVisible = !hideForced && 0 != (attrs.privateFlags &
+ (WindowManager.LayoutParams.PRIVATE_FLAG_BLUR_WITH_MASKING |
+ WindowManager.LayoutParams.PRIVATE_FLAG_BLUR_WITH_MASKING_SCALED) );
+ boolean blurScaleNeeded = blurVisible && 0 != (attrs.privateFlags &
+ WindowManager.LayoutParams.PRIVATE_FLAG_BLUR_WITH_MASKING_SCALED);
+
+ if (mSurfaceBlurShown == blurVisible && mSurfaceBlurScaleNeeded == blurScaleNeeded) return;
+ mSurfaceBlurShown = blurVisible;
+ mSurfaceBlurScaleNeeded = blurScaleNeeded;
+
+ if (!blurVisible) {
+ // we don't destroy mSurfaceControlBlur
+ if (mSurfaceControlBlur != null) {
+ mSurfaceControlBlur.hide();
+ } else {
+ // nothing to do
+ }
+ return;
+ }
+
+ if (mSurfaceControl == null) return;
+
+ if (blurVisible) {
+ if (null == mSurfaceControlBlur) {
+ int flags = SurfaceControl.HIDDEN | SurfaceControl.FX_SURFACE_BLUR;
+ final boolean isHwAccelerated = (attrs.flags &
+ WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED) != 0;
+ final int format = isHwAccelerated ? PixelFormat.TRANSLUCENT : attrs.format;
+ if (!PixelFormat.formatHasAlpha(attrs.format)) {
+ flags |= SurfaceControl.OPAQUE;
+ }
+
+ mSurfaceControlBlur = new SurfaceControl(
+ mSession.mSurfaceSession,
+ attrs.getTitle().toString() + " blur",
+ (int)mSurfaceW, (int)mSurfaceH, format, flags);
+ }
+
+ SurfaceControl.openTransaction();
+ try {
+ mSurfaceControlBlur.setPosition(mSurfaceX, mSurfaceY);
+ mSurfaceControlBlur.setLayerStack(mLayerStack);
+ mSurfaceControlBlur.setLayer(mAnimLayer-BLUR_LAYER_OFFSET);
+ mSurfaceControlBlur.setAlpha(mShownAlpha);
+ mSurfaceControlBlur.setBlur(1.0f);
+ mSurfaceControlBlur.setBlurMaskSurface(mSurfaceControl);
+ final int BLUR_MASKING_SAMPLING = 4;
+ mSurfaceControlBlur.setBlurMaskSampling(blurScaleNeeded ? BLUR_MASKING_SAMPLING : 1);
+ mSurfaceControlBlur.setBlurMaskAlphaThreshold(attrs.blurMaskAlphaThreshold);
+ } catch (RuntimeException e) {
+ Slog.w(TAG, "Error creating blur surface", e);
+ } finally {
+ SurfaceControl.closeTransaction();
+ }
+
+ if (mSurfaceShown) {
+ mSurfaceControlBlur.show();
+ }
+ }
+ }
}
diff --git a/services/core/jni/Android.mk b/services/core/jni/Android.mk
index 98d8d08..69488b1 100644
--- a/services/core/jni/Android.mk
+++ b/services/core/jni/Android.mk
@@ -72,3 +72,10 @@ LOCAL_SHARED_LIBRARIES += \
libGLESv2 \
libnetutils \
+ifeq ($(BOARD_USES_QC_TIME_SERVICES),true)
+LOCAL_CFLAGS += -DHAVE_QC_TIME_SERVICES=1
+LOCAL_SHARED_LIBRARIES += libtime_genoff
+$(shell mkdir -p $(OUT)/obj/SHARED_LIBRARIES/libtime_genoff_intermediates/)
+$(shell touch $(OUT)/obj/SHARED_LIBRARIES/libtime_genoff_intermediates/export_includes)
+endif
+
diff --git a/services/core/jni/com_android_server_AlarmManagerService.cpp b/services/core/jni/com_android_server_AlarmManagerService.cpp
index 3fd0f84..5d1e7af 100644
--- a/services/core/jni/com_android_server_AlarmManagerService.cpp
+++ b/services/core/jni/com_android_server_AlarmManagerService.cpp
@@ -40,6 +40,12 @@
#include <linux/android_alarm.h>
#include <linux/rtc.h>
+#if HAVE_QC_TIME_SERVICES
+extern "C" {
+#include <private/time_genoff.h>
+}
+#endif
+
namespace android {
static const size_t N_ANDROID_TIMERFDS = ANDROID_ALARM_TYPE_COUNT + 1;
@@ -49,6 +55,7 @@ static const clockid_t android_alarm_to_clockid[N_ANDROID_TIMERFDS] = {
CLOCK_BOOTTIME_ALARM,
CLOCK_BOOTTIME,
CLOCK_MONOTONIC,
+ CLOCK_POWEROFF_ALARM,
CLOCK_REALTIME,
};
/* to match the legacy alarm driver implementation, we need an extra
@@ -61,6 +68,7 @@ public:
virtual ~AlarmImpl();
virtual int set(int type, struct timespec *ts) = 0;
+ virtual int clear(int type, struct timespec *ts) = 0;
virtual int setTime(struct timeval *tv) = 0;
virtual int waitForAlarm() = 0;
@@ -75,6 +83,7 @@ public:
AlarmImplAlarmDriver(int fd) : AlarmImpl(&fd, 1) { }
int set(int type, struct timespec *ts);
+ int clear(int type, struct timespec *ts);
int setTime(struct timeval *tv);
int waitForAlarm();
};
@@ -87,6 +96,7 @@ public:
~AlarmImplTimerFd();
int set(int type, struct timespec *ts);
+ int clear(int type, struct timespec *ts);
int setTime(struct timeval *tv);
int waitForAlarm();
@@ -114,6 +124,30 @@ int AlarmImplAlarmDriver::set(int type, struct timespec *ts)
return ioctl(fds[0], ANDROID_ALARM_SET(type), ts);
}
+int AlarmImplAlarmDriver::clear(int type, struct timespec *ts)
+{
+ return ioctl(fds[0], ANDROID_ALARM_CLEAR(type), ts);
+}
+
+#if HAVE_QC_TIME_SERVICES
+static int setTimeServicesTime(time_bases_type base, long int secs)
+{
+ int rc = 0;
+ time_genoff_info_type time_set;
+ uint64_t value = secs;
+ time_set.base = base;
+ time_set.unit = TIME_SECS;
+ time_set.operation = T_SET;
+ time_set.ts_val = &value;
+ rc = time_genoff_operation(&time_set);
+ if (rc) {
+ ALOGE("Error setting generic offset: %d. Still setting system time\n", rc);
+ rc = -1;
+ }
+ return rc;
+}
+#endif
+
int AlarmImplAlarmDriver::setTime(struct timeval *tv)
{
struct timespec ts;
@@ -122,6 +156,10 @@ int AlarmImplAlarmDriver::setTime(struct timeval *tv)
ts.tv_sec = tv->tv_sec;
ts.tv_nsec = tv->tv_usec * 1000;
res = ioctl(fds[0], ANDROID_ALARM_SET_RTC, &ts);
+#if HAVE_QC_TIME_SERVICES
+ setTimeServicesTime(ATS_USER, (tv->tv_sec));
+#endif
+
if (res < 0)
ALOGV("ANDROID_ALARM_SET_RTC ioctl failed: %s\n", strerror(errno));
return res;
@@ -160,6 +198,23 @@ int AlarmImplTimerFd::set(int type, struct timespec *ts)
return timerfd_settime(fds[type], TFD_TIMER_ABSTIME, &spec, NULL);
}
+int AlarmImplTimerFd::clear(int type, struct timespec *ts)
+{
+ if (type > ANDROID_ALARM_TYPE_COUNT) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ ts->tv_sec = 0;
+ ts->tv_nsec = 0;
+
+ struct itimerspec spec;
+ memset(&spec, 0, sizeof(spec));
+ memcpy(&spec.it_value, ts, sizeof(spec.it_value));
+
+ return timerfd_settime(fds[type], TFD_TIMER_ABSTIME, &spec, NULL);
+}
+
int AlarmImplTimerFd::setTime(struct timeval *tv)
{
struct rtc_time rtc;
@@ -441,6 +496,23 @@ static void android_server_AlarmManagerService_set(JNIEnv*, jobject, jlong nativ
}
}
+static void android_server_AlarmManagerService_clear(JNIEnv*, jobject, jlong nativeData, jint type,
+jlong seconds, jlong nanoseconds)
+{
+ AlarmImpl *impl = reinterpret_cast<AlarmImpl *>(nativeData);
+ struct timespec ts;
+ ts.tv_sec = seconds;
+ ts.tv_nsec = nanoseconds;
+
+ int result = impl->clear(type, &ts);
+ if (result < 0)
+ {
+ ALOGE("Unable to clear alarm %lld.%09lld: %s\n",
+ static_cast<long long>(seconds),
+ static_cast<long long>(nanoseconds), strerror(errno));
+ }
+}
+
static jint android_server_AlarmManagerService_waitForAlarm(JNIEnv*, jobject, jlong nativeData)
{
AlarmImpl *impl = reinterpret_cast<AlarmImpl *>(nativeData);
@@ -465,6 +537,7 @@ static JNINativeMethod sMethods[] = {
{"init", "()J", (void*)android_server_AlarmManagerService_init},
{"close", "(J)V", (void*)android_server_AlarmManagerService_close},
{"set", "(JIJJ)V", (void*)android_server_AlarmManagerService_set},
+ {"clear", "(JIJJ)V", (void*)android_server_AlarmManagerService_clear},
{"waitForAlarm", "(J)I", (void*)android_server_AlarmManagerService_waitForAlarm},
{"setKernelTime", "(JJ)I", (void*)android_server_AlarmManagerService_setKernelTime},
{"setKernelTimezone", "(JI)I", (void*)android_server_AlarmManagerService_setKernelTimezone},
diff --git a/services/core/jni/com_android_server_PersistentDataBlockService.cpp b/services/core/jni/com_android_server_PersistentDataBlockService.cpp
index e842eeb..4ccfa56 100644
--- a/services/core/jni/com_android_server_PersistentDataBlockService.cpp
+++ b/services/core/jni/com_android_server_PersistentDataBlockService.cpp
@@ -17,6 +17,7 @@
#include <android_runtime/AndroidRuntime.h>
#include <JNIHelp.h>
#include <jni.h>
+#include <ScopedUtfChars.h>
#include <utils/misc.h>
#include <sys/ioctl.h>
@@ -77,8 +78,8 @@ namespace android {
static jlong com_android_server_PersistentDataBlockService_getBlockDeviceSize(JNIEnv *env, jclass, jstring jpath)
{
- const char *path = env->GetStringUTFChars(jpath, 0);
- int fd = open(path, O_RDONLY);
+ ScopedUtfChars path(env, jpath);
+ int fd = open(path.c_str(), O_RDONLY);
if (fd < 0)
return 0;
@@ -87,8 +88,8 @@ namespace android {
}
static int com_android_server_PersistentDataBlockService_wipe(JNIEnv *env, jclass, jstring jpath) {
- const char *path = env->GetStringUTFChars(jpath, 0);
- int fd = open(path, O_WRONLY);
+ ScopedUtfChars path(env, jpath);
+ int fd = open(path.c_str(), O_WRONLY);
if (fd < 0)
return 0;
diff --git a/services/core/jni/com_android_server_SystemServer.cpp b/services/core/jni/com_android_server_SystemServer.cpp
index 64514a9..3f46ec6 100644
--- a/services/core/jni/com_android_server_SystemServer.cpp
+++ b/services/core/jni/com_android_server_SystemServer.cpp
@@ -25,12 +25,24 @@
namespace android {
+void* sensorInit(void *arg) {
+ ALOGI("System server: starting sensor init.\n");
+ // Start the sensor service
+ SensorService::instantiate();
+ ALOGI("System server: sensor init done.\n");
+ return NULL;
+}
+
static void android_server_SystemServer_startSensorService(JNIEnv* /* env */, jobject /* clazz */) {
char propBuf[PROPERTY_VALUE_MAX];
+ pthread_t sensor_init_thread;
+
property_get("system_init.startsensorservice", propBuf, "1");
if (strcmp(propBuf, "1") == 0) {
- // Start the sensor service
- SensorService::instantiate();
+ // We are safe to move this to a new thread because
+ // Android frame work has taken care to check whether the
+ // service is started or not before using it.
+ pthread_create( &sensor_init_thread, NULL, &sensorInit, NULL);
}
}
diff --git a/services/core/jni/com_android_server_UsbMidiDevice.cpp b/services/core/jni/com_android_server_UsbMidiDevice.cpp
index 06b9bc3..e12a016 100644
--- a/services/core/jni/com_android_server_UsbMidiDevice.cpp
+++ b/services/core/jni/com_android_server_UsbMidiDevice.cpp
@@ -43,12 +43,26 @@ android_server_UsbMidiDevice_get_subdevice_count(JNIEnv *env, jobject /* thiz */
jint card, jint device)
{
char path[100];
+ int fd;
+ const int kMaxRetries = 10;
+ const int kSleepMicroseconds = 2000;
snprintf(path, sizeof(path), "/dev/snd/controlC%d", card);
- int fd = open(path, O_RDWR);
- if (fd < 0) {
- ALOGE("could not open %s", path);
- return 0;
+ // This control device may not have been created yet. So we should
+ // try to open it several times to prevent intermittent failure
+ // from a race condition.
+ int retryCounter = 0;
+ while ((fd = open(path, O_RDWR)) < 0) {
+ if (++retryCounter > kMaxRetries) {
+ ALOGE("timed out after %d tries, could not open %s", retryCounter, path);
+ return 0;
+ } else {
+ ALOGW("attempt #%d, could not open %s", retryCounter, path);
+ // Increase the sleep interval each time.
+ // 10 retries will total 2 * sum(1..10) = 110 milliseconds.
+ // Typically the device should be ready in 5-10 milliseconds.
+ usleep(kSleepMicroseconds * retryCounter);
+ }
}
struct snd_rawmidi_info info;
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index e29d0a9..94467a5 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -197,6 +197,8 @@ public:
void setSystemUiVisibility(int32_t visibility);
void setPointerSpeed(int32_t speed);
void setShowTouches(bool enabled);
+ void setStylusIconEnabled(bool enabled);
+ void setVolumeKeysRotation(int mode);
void setInteractive(bool interactive);
void reloadCalibration();
@@ -263,6 +265,12 @@ private:
// Show touches feature enable/disable.
bool showTouches;
+ // Show icon when stylus is used
+ bool stylusIconEnabled;
+
+ // Volume keys rotation mode (0 - off, 1 - phone, 2 - tablet)
+ int32_t volumeKeysRotationMode;
+
// Sprite controller singleton, created on first use.
sp<SpriteController> spriteController;
@@ -299,6 +307,8 @@ NativeInputManager::NativeInputManager(jobject contextObj,
mLocked.pointerSpeed = 0;
mLocked.pointerGesturesEnabled = true;
mLocked.showTouches = false;
+ mLocked.stylusIconEnabled = false;
+ mLocked.volumeKeysRotationMode = 0;
}
mInteractive = true;
@@ -446,6 +456,8 @@ void NativeInputManager::getReaderConfiguration(InputReaderConfiguration* outCon
outConfig->pointerGesturesEnabled = mLocked.pointerGesturesEnabled;
outConfig->showTouches = mLocked.showTouches;
+ outConfig->stylusIconEnabled = mLocked.stylusIconEnabled;
+ outConfig->volumeKeysRotationMode = mLocked.volumeKeysRotationMode;
outConfig->setDisplayInfo(false /*external*/, mLocked.internalViewport);
outConfig->setDisplayInfo(true /*external*/, mLocked.externalViewport);
@@ -770,6 +782,38 @@ void NativeInputManager::setShowTouches(bool enabled) {
InputReaderConfiguration::CHANGE_SHOW_TOUCHES);
}
+void NativeInputManager::setStylusIconEnabled(bool enabled) {
+ { // acquire lock
+ AutoMutex _l(mLock);
+
+ if (mLocked.stylusIconEnabled == enabled) {
+ return;
+ }
+
+ ALOGI("Setting stylus icon enabled to %s.", enabled ? "enabled" : "disabled");
+ mLocked.stylusIconEnabled = enabled;
+ } // release lock
+
+ mInputManager->getReader()->requestRefreshConfiguration(
+ InputReaderConfiguration::CHANGE_STYLUS_ICON_ENABLED);
+}
+
+void NativeInputManager::setVolumeKeysRotation(int mode) {
+ { // acquire lock
+ AutoMutex _l(mLock);
+
+ if (mLocked.volumeKeysRotationMode == mode) {
+ return;
+ }
+
+ ALOGI("Volume keys: rotation mode set to %d.", mode);
+ mLocked.volumeKeysRotationMode = mode;
+ } // release lock
+
+ mInputManager->getReader()->requestRefreshConfiguration(
+ InputReaderConfiguration::CHANGE_VOLUME_KEYS_ROTATION);
+}
+
void NativeInputManager::setInteractive(bool interactive) {
mInteractive = interactive;
}
@@ -1292,6 +1336,20 @@ static void nativeSetShowTouches(JNIEnv* /* env */,
im->setShowTouches(enabled);
}
+static void nativeSetStylusIconEnabled(JNIEnv* env,
+ jclass clazz, jlong ptr, jboolean enabled) {
+ NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
+
+ im->setStylusIconEnabled(enabled);
+}
+
+static void nativeSetVolumeKeysRotation(JNIEnv* env,
+ jclass clazz, jlong ptr, int mode) {
+ NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
+
+ im->setVolumeKeysRotation(mode);
+}
+
static void nativeSetInteractive(JNIEnv* env,
jclass clazz, jlong ptr, jboolean interactive) {
NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
@@ -1409,6 +1467,10 @@ static JNINativeMethod gInputManagerMethods[] = {
(void*) nativeSetPointerSpeed },
{ "nativeSetShowTouches", "(JZ)V",
(void*) nativeSetShowTouches },
+ { "nativeSetStylusIconEnabled", "(JZ)V",
+ (void*) nativeSetStylusIconEnabled },
+ { "nativeSetVolumeKeysRotation", "(JI)V",
+ (void*) nativeSetVolumeKeysRotation },
{ "nativeSetInteractive", "(JZ)V",
(void*) nativeSetInteractive },
{ "nativeReloadCalibration", "(J)V",
diff --git a/services/core/jni/com_android_server_lights_LightsService.cpp b/services/core/jni/com_android_server_lights_LightsService.cpp
index b2b2783..f8051f0 100644
--- a/services/core/jni/com_android_server_lights_LightsService.cpp
+++ b/services/core/jni/com_android_server_lights_LightsService.cpp
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2009 The Android Open Source Project
+ * Copyright (C) 2015 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.
@@ -41,6 +42,8 @@ enum {
LIGHT_INDEX_ATTENTION = 5,
LIGHT_INDEX_BLUETOOTH = 6,
LIGHT_INDEX_WIFI = 7,
+ LIGHT_INDEX_CAPS = 8,
+ LIGHT_INDEX_FUNC = 9,
LIGHT_COUNT
};
@@ -86,6 +89,10 @@ static jlong init_native(JNIEnv* /* env */, jobject /* clazz */)
= get_device(module, LIGHT_ID_BLUETOOTH);
devices->lights[LIGHT_INDEX_WIFI]
= get_device(module, LIGHT_ID_WIFI);
+ devices->lights[LIGHT_INDEX_CAPS]
+ = get_device(module, LIGHT_ID_CAPS);
+ devices->lights[LIGHT_INDEX_FUNC]
+ = get_device(module, LIGHT_ID_FUNC);
} else {
memset(devices, 0, sizeof(Devices));
}
@@ -104,21 +111,34 @@ static void finalize_native(JNIEnv* /* env */, jobject /* clazz */, jlong ptr)
}
static void setLight_native(JNIEnv* /* env */, jobject /* clazz */, jlong ptr,
- jint light, jint colorARGB, jint flashMode, jint onMS, jint offMS, jint brightnessMode)
+ jint light, jint colorARGB, jint flashMode, jint onMS, jint offMS, jint brightnessMode,
+ jint brightnessLevel, jint multipleLeds)
{
Devices* devices = (Devices*)ptr;
light_state_t state;
+ int colorAlpha;
if (light < 0 || light >= LIGHT_COUNT || devices->lights[light] == NULL) {
return ;
}
+ if (brightnessLevel > 0 && brightnessLevel <= 0xFF) {
+ colorAlpha = (colorARGB & 0xFF000000) >> 24;
+ if (colorAlpha == 0x00) {
+ colorAlpha = 0xFF;
+ }
+ colorAlpha = (colorAlpha * brightnessLevel) / 0xFF;
+ colorARGB = (colorAlpha << 24) + (colorARGB & 0x00FFFFFF);
+ }
+
memset(&state, 0, sizeof(light_state_t));
state.color = colorARGB;
state.flashMode = flashMode;
state.flashOnMS = onMS;
state.flashOffMS = offMS;
state.brightnessMode = brightnessMode;
+ state.ledsModes = 0 |
+ (multipleLeds ? LIGHT_MODE_MULTIPLE_LEDS : 0);
{
ALOGD_IF_SLOW(50, "Excessive delay setting light");
@@ -129,7 +149,7 @@ static void setLight_native(JNIEnv* /* env */, jobject /* clazz */, jlong ptr,
static JNINativeMethod method_table[] = {
{ "init_native", "()J", (void*)init_native },
{ "finalize_native", "(J)V", (void*)finalize_native },
- { "setLight_native", "(JIIIIII)V", (void*)setLight_native },
+ { "setLight_native", "(JIIIIIIII)V", (void*)setLight_native },
};
int register_android_server_LightsService(JNIEnv *env)
diff --git a/services/core/jni/com_android_server_location_GpsLocationProvider.cpp b/services/core/jni/com_android_server_location_GpsLocationProvider.cpp
index 5c27b1f..91eeb8b 100644
--- a/services/core/jni/com_android_server_location_GpsLocationProvider.cpp
+++ b/services/core/jni/com_android_server_location_GpsLocationProvider.cpp
@@ -641,7 +641,7 @@ static jint android_location_GpsLocationProvider_read_sv_status(JNIEnv* env, job
}
static void android_location_GpsLocationProvider_agps_set_reference_location_cellid(
- JNIEnv* /* env */, jobject /* obj */, jint type, jint mcc, jint mnc, jint lac, jint cid)
+ JNIEnv* /* env */, jobject /* obj */, jint type, jint mcc, jint mnc, jint lac, jint cid, jint psc)
{
AGpsRefLocation location;
@@ -657,6 +657,11 @@ static void android_location_GpsLocationProvider_agps_set_reference_location_cel
location.u.cellID.mcc = mcc;
location.u.cellID.mnc = mnc;
location.u.cellID.lac = lac;
+#ifdef AGPS_USE_PSC
+ location.u.cellID.psc = psc;
+#else
+ (void)psc;
+#endif
location.u.cellID.cid = cid;
break;
default:
@@ -1477,7 +1482,7 @@ static JNINativeMethod sMethods[] = {
"(ILjava/lang/String;)V",
(void*)android_location_GpsLocationProvider_agps_set_id},
{"native_agps_set_ref_location_cellid",
- "(IIIII)V",
+ "(IIIIII)V",
(void*)android_location_GpsLocationProvider_agps_set_reference_location_cellid},
{"native_set_agps_server",
"(ILjava/lang/String;I)V",
diff --git a/services/core/jni/com_android_server_power_PowerManagerService.cpp b/services/core/jni/com_android_server_power_PowerManagerService.cpp
index 1662755..509a6ca 100644
--- a/services/core/jni/com_android_server_power_PowerManagerService.cpp
+++ b/services/core/jni/com_android_server_power_PowerManagerService.cpp
@@ -148,11 +148,7 @@ static void nativeSendPowerHint(JNIEnv *env, jclass clazz, jint hintId, jint dat
int data_param = data;
if (gPowerModule && gPowerModule->powerHint) {
- if(data)
- gPowerModule->powerHint(gPowerModule, (power_hint_t)hintId, &data_param);
- else {
- gPowerModule->powerHint(gPowerModule, (power_hint_t)hintId, NULL);
- }
+ gPowerModule->powerHint(gPowerModule, (power_hint_t)hintId, &data_param);
}
}
@@ -164,6 +160,16 @@ static void nativeSetFeature(JNIEnv *env, jclass clazz, jint featureId, jint dat
}
}
+static jint nativeGetFeature(JNIEnv *env, jclass clazz, jint featureId) {
+ int value = -1;
+
+ if (gPowerModule && gPowerModule->getFeature) {
+ value = gPowerModule->getFeature(gPowerModule, (feature_t)featureId);
+ }
+
+ return (jint)value;
+}
+
// ----------------------------------------------------------------------------
static JNINativeMethod gPowerManagerServiceMethods[] = {
@@ -182,6 +188,8 @@ static JNINativeMethod gPowerManagerServiceMethods[] = {
(void*) nativeSendPowerHint },
{ "nativeSetFeature", "(II)V",
(void*) nativeSetFeature },
+ { "nativeGetFeature", "(I)I",
+ (void*) nativeGetFeature },
};
#define FIND_CLASS(var, className) \
diff --git a/services/core/jni/com_android_server_tv_TvInputHal.cpp b/services/core/jni/com_android_server_tv_TvInputHal.cpp
index 507bc9c..b7c19db 100644
--- a/services/core/jni/com_android_server_tv_TvInputHal.cpp
+++ b/services/core/jni/com_android_server_tv_TvInputHal.cpp
@@ -32,6 +32,8 @@
#include <utils/NativeHandle.h>
#include <hardware/tv_input.h>
+#include <jni/TvInputHalExtensions.h>
+
namespace android {
static struct {
@@ -71,37 +73,6 @@ static struct {
////////////////////////////////////////////////////////////////////////////////
-class BufferProducerThread : public Thread {
-public:
- BufferProducerThread(tv_input_device_t* device, int deviceId, const tv_stream_t* stream);
-
- virtual status_t readyToRun();
-
- void setSurface(const sp<Surface>& surface);
- void onCaptured(uint32_t seq, bool succeeded);
- void shutdown();
-
-private:
- Mutex mLock;
- Condition mCondition;
- sp<Surface> mSurface;
- tv_input_device_t* mDevice;
- int mDeviceId;
- tv_stream_t mStream;
- sp<ANativeWindowBuffer_t> mBuffer;
- enum {
- CAPTURING,
- CAPTURED,
- RELEASED,
- } mBufferState;
- uint32_t mSeq;
- bool mShutdown;
-
- virtual bool threadLoop();
-
- void setSurfaceLocked(const sp<Surface>& surface);
-};
-
BufferProducerThread::BufferProducerThread(
tv_input_device_t* device, int deviceId, const tv_stream_t* stream)
: Thread(false),
@@ -132,14 +103,14 @@ status_t BufferProducerThread::readyToRun() {
return NO_ERROR;
}
-void BufferProducerThread::setSurface(const sp<Surface>& surface) {
+int BufferProducerThread::setSurface(const sp<Surface>& surface) {
Mutex::Autolock autoLock(&mLock);
- setSurfaceLocked(surface);
+ return setSurfaceLocked(surface);
}
-void BufferProducerThread::setSurfaceLocked(const sp<Surface>& surface) {
+int BufferProducerThread::setSurfaceLocked(const sp<Surface>& surface) {
if (surface == mSurface) {
- return;
+ return NO_ERROR;
}
if (mBufferState == CAPTURING) {
@@ -157,6 +128,8 @@ void BufferProducerThread::setSurfaceLocked(const sp<Surface>& surface) {
mSurface = surface;
mCondition.broadcast();
+
+ return NO_ERROR;
}
void BufferProducerThread::onCaptured(uint32_t seq, bool succeeded) {
@@ -390,15 +363,37 @@ int JTvInputHal::addOrUpdateStream(int deviceId, int streamId, const sp<Surface>
if (connection.mThread != NULL) {
connection.mThread->shutdown();
}
- connection.mThread = new BufferProducerThread(mDevice, deviceId, &stream);
- connection.mThread->run();
+
+ connection.mThread = TvInputHalFactory::get()->createBufferProducerThread(mDevice, deviceId, &stream);
+ if (connection.mThread == NULL) {
+ ALOGE("No memory for BufferProducerThread");
+
+ // clean up
+ if (mDevice->close_stream(mDevice, deviceId, streamId) != 0) {
+ ALOGE("Couldn't remove stream");
+ }
+ return NO_MEMORY;
+ }
}
}
connection.mSurface = surface;
if (connection.mStreamType == TV_STREAM_TYPE_INDEPENDENT_VIDEO_SOURCE) {
connection.mSurface->setSidebandStream(connection.mSourceHandle);
} else if (connection.mStreamType == TV_STREAM_TYPE_BUFFER_PRODUCER) {
- connection.mThread->setSurface(surface);
+ if (NO_ERROR != connection.mThread->setSurface(surface))
+ {
+ ALOGE("failed to setSurface");
+ // clean up
+ connection.mThread.clear();
+ if (mDevice->close_stream(mDevice, deviceId, streamId) != 0) {
+ ALOGE("Couldn't remove stream");
+ }
+ if (connection.mSurface != NULL) {
+ connection.mSurface.clear();
+ }
+ return UNKNOWN_ERROR;
+ }
+ connection.mThread->run();
}
return NO_ERROR;
}
@@ -413,13 +408,6 @@ int JTvInputHal::removeStream(int deviceId, int streamId) {
// Nothing to do
return NO_ERROR;
}
- if (Surface::isValid(connection.mSurface)) {
- connection.mSurface.clear();
- }
- if (connection.mSurface != NULL) {
- connection.mSurface->setSidebandStream(NULL);
- connection.mSurface.clear();
- }
if (connection.mThread != NULL) {
connection.mThread->shutdown();
connection.mThread.clear();
@@ -431,6 +419,13 @@ int JTvInputHal::removeStream(int deviceId, int streamId) {
if (connection.mSourceHandle != NULL) {
connection.mSourceHandle.clear();
}
+ if (Surface::isValid(connection.mSurface)) {
+ connection.mSurface.clear();
+ }
+ if (connection.mSurface != NULL) {
+ connection.mSurface->setSidebandStream(NULL);
+ connection.mSurface.clear();
+ }
return NO_ERROR;
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index dedf1d9..b2cb2ff 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -95,6 +95,7 @@ import android.security.IKeyChainAliasCallback;
import android.security.IKeyChainService;
import android.security.KeyChain;
import android.security.KeyChain.KeyChainConnection;
+import android.security.KeyStore;
import android.service.persistentdata.PersistentDataBlockManager;
import android.text.TextUtils;
import android.util.Log;
@@ -4198,6 +4199,36 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
}
+ @Override
+ public boolean requireSecureKeyguard(int userHandle) {
+ if (!mHasFeature) {
+ return false;
+ }
+
+ int passwordQuality = getPasswordQuality(null, userHandle);
+ if (passwordQuality > DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
+ return true;
+ }
+
+ int encryptionStatus = getStorageEncryptionStatus(userHandle);
+ if (encryptionStatus == DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE
+ || encryptionStatus == DevicePolicyManager.ENCRYPTION_STATUS_ACTIVATING) {
+ return true;
+ }
+
+ // Keystore.isEmpty() requires system UID
+ long token = Binder.clearCallingIdentity();
+ try {
+ if (!KeyStore.getInstance().isEmpty()) {
+ return true;
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+
+ return false;
+ }
+
// Returns the active device owner or null if there is no device owner.
private ActiveAdmin getDeviceOwnerAdmin() {
String deviceOwnerPackageName = getDeviceOwner();
@@ -4236,6 +4267,17 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
mDeviceOwner.clearDeviceOwner();
mDeviceOwner.writeOwnerFile();
updateDeviceOwnerLocked();
+ // Restore backup manager.
+ long ident = Binder.clearCallingIdentity();
+ try {
+ IBackupManager ibm = IBackupManager.Stub.asInterface(
+ ServiceManager.getService(Context.BACKUP_SERVICE));
+ ibm.setBackupServiceActive(UserHandle.USER_OWNER, true);
+ } catch (RemoteException e) {
+ throw new IllegalStateException("Failed activating backup service.", e);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
}
}
}
diff --git a/services/java/com/android/server/AppsFailureReceiver.java b/services/java/com/android/server/AppsFailureReceiver.java
new file mode 100644
index 0000000..e99b7a4
--- /dev/null
+++ b/services/java/com/android/server/AppsFailureReceiver.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2010, T-Mobile USA, Inc.
+ * Copyright (C) 2015 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 com.android.server;
+
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ThemeUtils;
+import android.content.res.ThemeChangeRequest;
+import android.content.res.ThemeChangeRequest.RequestType;
+import android.content.res.ThemeConfig;
+import android.content.res.ThemeManager;
+import android.os.SystemClock;
+
+import com.android.internal.R;
+
+public class AppsFailureReceiver extends BroadcastReceiver {
+
+ private static final int FAILURES_THRESHOLD = 3;
+ private static final int EXPIRATION_TIME_IN_MILLISECONDS = 30000; // 30 seconds
+
+ private static final int THEME_RESET_NOTIFICATION_ID = 0x4641494C;
+
+ private int mFailuresCount = 0;
+ private long mStartTime = 0;
+
+ // This function implements the following logic.
+ // If after a theme was applied the number of application launch failures
+ // at any moment was equal to FAILURES_THRESHOLD
+ // in less than EXPIRATION_TIME_IN_MILLISECONDS
+ // the default theme is applied unconditionally.
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ if (action.equals(Intent.ACTION_APP_FAILURE)) {
+ long currentTime = SystemClock.uptimeMillis();
+ String pkgName = intent.getStringExtra("package");
+ if (currentTime - mStartTime > EXPIRATION_TIME_IN_MILLISECONDS) {
+ // reset both the count and the timer
+ mStartTime = currentTime;
+ mFailuresCount = 0;
+ }
+ if (mFailuresCount <= FAILURES_THRESHOLD) {
+ mFailuresCount++;
+ if (mFailuresCount == FAILURES_THRESHOLD) {
+ // let the theme manager take care of getting us back on the default theme
+ ThemeManager tm =
+ (ThemeManager) context.getSystemService(Context.THEME_SERVICE);
+ final String themePkgName = ThemeConfig.SYSTEM_DEFAULT;
+ ThemeChangeRequest.Builder builder = new ThemeChangeRequest.Builder();
+ builder.setOverlay(themePkgName)
+ .setStatusBar(themePkgName)
+ .setNavBar(themePkgName)
+ .setIcons(themePkgName)
+ .setFont(themePkgName)
+ .setBootanimation(themePkgName)
+ .setWallpaper(themePkgName)
+ .setLockWallpaper(themePkgName)
+ .setAlarm(themePkgName)
+ .setNotification(themePkgName)
+ .setRingtone(themePkgName)
+ .setRequestType(RequestType.THEME_RESET);
+ // Since we are resetting everything to the system theme, we can have the
+ // theme service remove all per app themes without setting them explicitly :)
+ tm.requestThemeChange(builder.build(), true);
+ postThemeResetNotification(context);
+ }
+ }
+ } else if (action.equals(Intent.ACTION_APP_FAILURE_RESET)
+ || action.equals(ThemeUtils.ACTION_THEME_CHANGED)) {
+ mFailuresCount = 0;
+ mStartTime = SystemClock.uptimeMillis();
+ } else if (action.equals(Intent.ACTION_PACKAGE_ADDED) ||
+ action.equals(Intent.ACTION_PACKAGE_REMOVED)) {
+ mFailuresCount = 0;
+ mStartTime = SystemClock.uptimeMillis();
+ }
+ }
+
+ /**
+ * Posts a notification to let the user know their theme was reset
+ * @param context
+ */
+ private void postThemeResetNotification(Context context) {
+ NotificationManager nm =
+ (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
+ String title = context.getString(R.string.theme_reset_notification_title);
+ String body = context.getString(R.string.theme_reset_notification_body);
+ Notification notice = new Notification.Builder(context)
+ .setAutoCancel(true)
+ .setOngoing(false)
+ .setContentTitle(title)
+ .setContentText(body)
+ .setStyle(new Notification.BigTextStyle().bigText(body))
+ .setSmallIcon(android.R.drawable.stat_notify_error)
+ .setWhen(System.currentTimeMillis())
+ .setCategory(Notification.CATEGORY_SYSTEM)
+ .setPriority(Notification.PRIORITY_MAX)
+ .build();
+ nm.notify(THEME_RESET_NOTIFICATION_ID, notice);
+ }
+}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 7dd16d1..90a4dc1 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -25,9 +25,16 @@ import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
+import android.content.pm.ThemeUtils;
import android.content.res.Configuration;
import android.content.res.Resources.Theme;
+import android.database.ContentObserver;
+import android.database.Cursor;
+import android.content.res.ThemeConfig;
+import android.database.ContentObserver;
import android.os.Build;
import android.os.Environment;
import android.os.FactoryTest;
@@ -40,6 +47,7 @@ import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.storage.IMountService;
+import android.provider.Settings;
import android.util.DisplayMetrics;
import android.util.EventLog;
import android.util.Slog;
@@ -61,6 +69,7 @@ import com.android.server.display.DisplayManagerService;
import com.android.server.dreams.DreamManagerService;
import com.android.server.fingerprint.FingerprintService;
import com.android.server.hdmi.HdmiControlService;
+import com.android.server.gesture.GestureService;
import com.android.server.input.InputManagerService;
import com.android.server.job.JobSchedulerService;
import com.android.server.lights.LightsService;
@@ -72,6 +81,7 @@ import com.android.server.net.NetworkStatsService;
import com.android.server.notification.NotificationManagerService;
import com.android.server.os.SchedulingPolicyService;
import com.android.server.pm.BackgroundDexOptService;
+import com.android.server.gesture.EdgeGestureService;
import com.android.server.pm.Installer;
import com.android.server.pm.LauncherAppsService;
import com.android.server.pm.PackageManagerService;
@@ -92,6 +102,7 @@ import com.android.server.wallpaper.WallpaperManagerService;
import com.android.server.webkit.WebViewUpdateService;
import com.android.server.wm.WindowManagerService;
+import cyanogenmod.providers.CMSettings;
import dalvik.system.VMRuntime;
import java.io.File;
@@ -173,6 +184,19 @@ public final class SystemServer {
mFactoryTestMode = FactoryTest.getMode();
}
+ private class AdbPortObserver extends ContentObserver {
+ public AdbPortObserver() {
+ super(null);
+ }
+ @Override
+ public void onChange(boolean selfChange) {
+ int adbPort = CMSettings.Secure.getInt(mContentResolver,
+ CMSettings.Secure.ADB_PORT, 0);
+ // setting this will control whether ADB runs on TCP/IP or USB
+ SystemProperties.set("service.adb.tcp.port", Integer.toString(adbPort));
+ }
+ }
+
private void run() {
// If a device's clock is before 1970 (before 0), a lot of
// APIs crash dealing with negative numbers, notably
@@ -438,6 +462,8 @@ public final class SystemServer {
boolean disableNetwork = SystemProperties.getBoolean("config.disable_network", false);
boolean disableNetworkTime = SystemProperties.getBoolean("config.disable_networktime", false);
boolean isEmulator = SystemProperties.get("ro.kernel.qemu").equals("1");
+ String[] externalServices = context.getResources()
+ .getStringArray(com.android.internal.R.array.config_externalCMServices);
try {
Slog.i(TAG, "Reading configuration...");
@@ -499,7 +525,7 @@ public final class SystemServer {
Slog.i(TAG, "Window Manager");
wm = WindowManagerService.main(context, inputManager,
mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL,
- !mFirstBoot, mOnlyCore);
+ true, mOnlyCore);
ServiceManager.addService(Context.WINDOW_SERVICE, wm);
ServiceManager.addService(Context.INPUT_SERVICE, inputManager);
@@ -542,6 +568,9 @@ public final class SystemServer {
LockSettingsService lockSettings = null;
AssetAtlasService atlas = null;
MediaRouterService mediaRouter = null;
+ GestureService gestureService = null;
+ EdgeGestureService edgeGestureService = null;
+ ThemeService themeService = null;
// Bring up services needed for UI.
if (mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL) {
@@ -947,6 +976,17 @@ public final class SystemServer {
new GraphicsStatsService(context));
}
+ if (context.getResources().getBoolean(
+ com.android.internal.R.bool.config_enableGestureService)) {
+ try {
+ Slog.i(TAG, "Gesture Sensor Service");
+ gestureService = new GestureService(context, inputManager);
+ ServiceManager.addService("gesture", gestureService);
+ } catch (Throwable e) {
+ Slog.e(TAG, "Failure starting Gesture Sensor Service", e);
+ }
+ }
+
if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_PRINTING)) {
mSystemServiceManager.startService(PRINT_MANAGER_SERVICE_CLASS);
}
@@ -963,6 +1003,14 @@ public final class SystemServer {
mSystemServiceManager.startService(TvInputManagerService.class);
}
+ try {
+ Slog.i(TAG, "Theme Service");
+ themeService = new ThemeService(context);
+ ServiceManager.addService(Context.THEME_SERVICE, themeService);
+ } catch (Throwable e) {
+ reportWtf("starting Theme Service", e);
+ }
+
if (!disableNonCoreServices) {
try {
Slog.i(TAG, "Media Router Service");
@@ -986,12 +1034,29 @@ public final class SystemServer {
}
mSystemServiceManager.startService(LauncherAppsService.class);
+
+ try {
+ Slog.i(TAG, "EdgeGesture service");
+ edgeGestureService = new EdgeGestureService(context, inputManager);
+ ServiceManager.addService("edgegestureservice", edgeGestureService);
+ } catch (Throwable e) {
+ Slog.e(TAG, "Failure starting EdgeGesture service", e);
+ }
}
if (!disableNonCoreServices) {
mSystemServiceManager.startService(MediaProjectionManagerService.class);
}
+ // make sure the ADB_ENABLED setting value matches the secure property value
+ CMSettings.Secure.putInt(mContentResolver, CMSettings.Secure.ADB_PORT,
+ Integer.parseInt(SystemProperties.get("service.adb.tcp.port", "-1")));
+
+ // register observer to listen for settings changes
+ mContentResolver.registerContentObserver(
+ CMSettings.Secure.getUriFor(CMSettings.Secure.ADB_PORT),
+ false, new AdbPortObserver());
+
// Before things start rolling, be sure we have decided whether
// we are in safe mode.
final boolean safeMode = wm.detectSafeMode();
@@ -1007,6 +1072,15 @@ public final class SystemServer {
// MMS service broker
mmsService = mSystemServiceManager.startService(MmsServiceBroker.class);
+ for (String service : externalServices) {
+ try {
+ Slog.i(TAG, service);
+ mSystemServiceManager.startService(service);
+ } catch (Throwable e) {
+ reportWtf("starting " + service , e);
+ }
+ }
+
// It is now time to start up the app processes...
try {
@@ -1067,6 +1141,32 @@ public final class SystemServer {
reportWtf("making Display Manager Service ready", e);
}
+ if (edgeGestureService != null) {
+ try {
+ edgeGestureService.systemReady();
+ } catch (Throwable e) {
+ reportWtf("making EdgeGesture service ready", e);
+ }
+ }
+
+ if (gestureService != null) {
+ try {
+ gestureService.systemReady();
+ } catch (Throwable e) {
+ reportWtf("making Gesture Sensor Service ready", e);
+ }
+ }
+
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(Intent.ACTION_APP_FAILURE);
+ filter.addAction(Intent.ACTION_APP_FAILURE_RESET);
+ filter.addAction(Intent.ACTION_PACKAGE_ADDED);
+ filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+ filter.addAction(ThemeUtils.ACTION_THEME_CHANGED);
+ filter.addCategory(Intent.CATEGORY_THEME_PACKAGE_INSTALLED_STATE_CHANGE);
+ filter.addDataScheme("package");
+ context.registerReceiver(new AppsFailureReceiver(), filter);
+
// These are needed to propagate to the runnable below.
final NetworkManagementService networkManagementF = networkManagement;
final NetworkStatsService networkStatsF = networkStats;
@@ -1087,6 +1187,7 @@ public final class SystemServer {
final MediaRouterService mediaRouterF = mediaRouter;
final AudioService audioServiceF = audioService;
final MmsServiceBroker mmsServiceF = mmsService;
+ final ThemeService themeServiceF = themeService;
// We now tell the activity manager it is okay to run third party
// code. It will call back into us once it has gotten to the state
@@ -1109,6 +1210,15 @@ public final class SystemServer {
Slog.i(TAG, "WebViewFactory preparation");
WebViewFactory.prepareWebViewInSystemServer();
+ // Start Nfc before SystemUi to ensure NfcTile and other apps gets a
+ // valid NfcAdapter from NfcManager
+ try {
+ startNfcService(context);
+ } catch (Throwable e) {
+ // Don't crash. Nfc is an optional service. Just annotate that isn't ready
+ Slog.e(TAG, "Nfc service didn't start. Nfc will not be available.", e);
+ }
+
try {
startSystemUi(context);
} catch (Throwable e) {
@@ -1216,6 +1326,17 @@ public final class SystemServer {
} catch (Throwable e) {
reportWtf("Notifying MmsService running", e);
}
+
+ try {
+ // now that the system is up, apply default theme if applicable
+ if (themeServiceF != null) themeServiceF.systemRunning();
+ ThemeConfig themeConfig =
+ ThemeConfig.getBootTheme(context.getContentResolver());
+ String iconPkg = themeConfig.getIconPackPkgName();
+ mPackageManagerService.updateIconMapping(iconPkg);
+ } catch (Throwable e) {
+ reportWtf("Icon Mapping failed", e);
+ }
}
});
}
@@ -1227,4 +1348,23 @@ public final class SystemServer {
//Slog.d(TAG, "Starting service: " + intent);
context.startServiceAsUser(intent, UserHandle.OWNER);
}
+
+ static final void startNfcService(Context context) {
+ IPackageManager pm = ActivityThread.getPackageManager();
+ if (pm == null) {
+ Slog.w(TAG, "Cannot get package manager, assuming no NFC feature");
+ return;
+ }
+ try {
+ if (pm.hasSystemFeature(PackageManager.FEATURE_NFC)) {
+ Intent intent = new Intent();
+ intent.setComponent(new ComponentName("com.android.nfc",
+ "com.android.nfc.NfcBootstrapService"));
+ context.startServiceAsUser(intent, UserHandle.OWNER);
+ }
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Package manager query failed, assuming no NFC feature", e);
+ return;
+ }
+ }
}
diff --git a/services/java/com/android/server/gesture/EdgeGestureInputFilter.java b/services/java/com/android/server/gesture/EdgeGestureInputFilter.java
new file mode 100644
index 0000000..c42b7d0
--- /dev/null
+++ b/services/java/com/android/server/gesture/EdgeGestureInputFilter.java
@@ -0,0 +1,539 @@
+/*
+ * Copyright (C) 2013 The CyanogenMod Project (Jens Doll)
+ *
+ * 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.gesture;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.os.Trace;
+import android.util.Slog;
+import android.view.Display;
+import android.view.DisplayInfo;
+import android.view.IInputFilter;
+import android.view.IInputFilterHost;
+import android.view.InputDevice;
+import android.view.InputEvent;
+import android.view.MotionEvent;
+import android.view.WindowManagerPolicy;
+import android.view.MotionEvent.PointerCoords;
+import android.view.MotionEvent.PointerProperties;
+
+import com.android.internal.R;
+import com.android.internal.util.gesture.EdgeGesturePosition;
+import com.android.server.gesture.EdgeGestureTracker.OnActivationListener;
+
+import java.io.PrintWriter;
+
+/**
+ * A simple input filter, that listens for edge swipe gestures in the motion event input
+ * stream.
+ * <p>
+ * There are 5 distinct states of this filter.
+ * 1) LISTEN:
+ * mTracker.active == false
+ * All motion events are passed through. If a ACTION_DOWN within a gesture trigger area happen
+ * switch to DETECTING.
+ * 2) DETECTING:
+ * mTracker.active == true
+ * All events are buffered now, and the gesture is checked by mTracker. If mTracker rejects
+ * the gesture (hopefully as fast as possible) all cached events will be flushed out and the
+ * filter falls back to LISTEN.
+ * If mTracker accepts the gesture, clear all cached events and go to LOCKED.
+ * 3) LOCKED:
+ * mTracker.active == false
+ * All events will be cached until the state changes to SYNTHESIZE through a filter
+ * unlock event. If there is a ACTION_UP, _CANCEL or any PointerId differently to the last
+ * event seen when mTracker accepted the gesture, we flush all events and go to LISTEN.
+ * 4) SYNTHESIZE:
+ * The first motion event found will be turned into a ACTION_DOWN event, all previous events
+ * will be discarded.
+ * 5) POSTSYNTHESIZE:
+ * mSyntheticDownTime != -1
+ * All following events will have the down time set to the synthesized ACTION_DOWN event time
+ * until an ACTION_UP or ACTION_CANCEL is encountered and the state is reset to LISTEN.
+ * 6) DROP:
+ * All following events will be discarded. If there is an ACTION_UP, _CANCEL
+ * we go to LISTEN state.
+ * <p>
+ * If you are reading this within Java Doc, you are doing something wrong ;)
+ */
+public class EdgeGestureInputFilter implements IInputFilter {
+ /* WARNING!! The IInputFilter interface is used directly, there is no Binder between this and
+ * the InputDispatcher.
+ * This is fine, because it prevents unnecessary parceling, but beware:
+ * This means we are running on the dispatch or listener thread of the input dispatcher. Every
+ * cycle we waste here adds to the overall input latency.
+ */
+ private static final String TAG = "EdgeGestureInputFilter";
+ private static final boolean DEBUG = false;
+ private static final boolean DEBUG_INPUT = false;
+ // TODO: Should be turned off in final commit
+ private static final boolean SYSTRACE = false;
+
+ private final Handler mHandler;
+
+ private IInputFilterHost mHost = null; // dispatcher thread
+
+ private static final class MotionEventInfo {
+ private static final int MAX_POOL_SIZE = 16;
+
+ private static final Object sLock = new Object();
+ private static MotionEventInfo sPool;
+ private static int sPoolSize;
+
+ private boolean mInPool;
+
+ public static MotionEventInfo obtain(MotionEvent event, int policyFlags) {
+ synchronized (sLock) {
+ MotionEventInfo info;
+ if (sPoolSize > 0) {
+ sPoolSize--;
+ info = sPool;
+ sPool = info.next;
+ info.next = null;
+ info.mInPool = false;
+ } else {
+ info = new MotionEventInfo();
+ }
+ info.initialize(event, policyFlags);
+ return info;
+ }
+ }
+
+ private void initialize(MotionEvent event, int policyFlags) {
+ this.event = MotionEvent.obtain(event);
+ this.policyFlags = policyFlags;
+ cachedTimeMillis = SystemClock.uptimeMillis();
+ }
+
+ public void recycle() {
+ synchronized (sLock) {
+ if (mInPool) {
+ throw new IllegalStateException("Already recycled.");
+ }
+ clear();
+ if (sPoolSize < MAX_POOL_SIZE) {
+ sPoolSize++;
+ next = sPool;
+ sPool = this;
+ mInPool = true;
+ }
+ }
+ }
+
+ private void clear() {
+ event.recycle();
+ event = null;
+ policyFlags = 0;
+ }
+
+ public MotionEventInfo next;
+ public MotionEvent event;
+ public int policyFlags;
+ public long cachedTimeMillis;
+ }
+ private final Object mLock = new Object();
+ private MotionEventInfo mMotionEventQueue; // guarded by mLock
+ private MotionEventInfo mMotionEventQueueTail; // guarded by mLock
+ /* DEBUG */
+ private int mMotionEventQueueCountDebug; // guarded by mLock
+
+ private int mDeviceId; // dispatcher only
+ private enum State {
+ LISTEN, DETECTING, LOCKED, SYNTHESIZE, POSTSYNTHESIZE, DROP;
+ }
+ private State mState = State.LISTEN; // guarded by mLock
+ private EdgeGestureTracker mTracker; // guarded by mLock
+ private volatile int mPositions; // written by handler / read by dispatcher
+ private volatile int mSensitivity; // written by handler / read by dispatcher
+
+ // only used by dispatcher
+ private long mSyntheticDownTime = -1;
+ private PointerCoords[] mTempPointerCoords = new PointerCoords[1];
+ private PointerProperties[] mTempPointerProperties = new PointerProperties[1];
+
+ public EdgeGestureInputFilter(Context context, Handler handler) {
+ mHandler = handler;
+
+ final Resources res = context.getResources();
+ mTracker = new EdgeGestureTracker(res.getDimensionPixelSize(
+ R.dimen.edge_gesture_trigger_thickness),
+ res.getDimensionPixelSize(R.dimen.edge_gesture_trigger_distance),
+ res.getDimensionPixelSize(R.dimen.edge_gesture_perpendicular_distance));
+ mTracker.setOnActivationListener(new OnActivationListener() {
+ public void onActivation(MotionEvent event, int touchX, int touchY, EdgeGesturePosition position) {
+ // mLock is held by #processMotionEvent
+ mHandler.obtainMessage(EdgeGestureService.MSG_EDGE_GESTURE_ACTIVATION,
+ touchX, touchY, position).sendToTarget();
+ mState = State.LOCKED;
+ }
+ });
+ mTempPointerCoords[0] = new PointerCoords();
+ mTempPointerProperties[0] = new PointerProperties();
+ }
+
+ // called from handler thread (lock taken)
+ public void updateDisplay(Display display, DisplayInfo displayInfo) {
+ synchronized (mLock) {
+ mTracker.updateDisplay(display);
+ }
+ }
+
+ // called from handler thread (lock taken)
+ public void updatePositions(int positions) {
+ mPositions = positions;
+ }
+
+ // called from handler thread (lock taken)
+ public void updateSensitivity(int sensitivity) {
+ mSensitivity = sensitivity;
+ }
+
+ // called from handler thread
+ public boolean unlockFilter() {
+ synchronized (mLock) {
+ if (mState == State.LOCKED) {
+ mState = State.SYNTHESIZE;
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public boolean dropSequence() {
+ synchronized (mLock) {
+ if (mState == State.LOCKED) {
+ mState = State.DROP;
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Called to enqueue the input event for filtering.
+ * The event must be recycled after the input filter processed it.
+ * This method is guaranteed to be non-reentrant.
+ *
+ * @see InputFilter#filterInputEvent(InputEvent, int)
+ * @param event The input event to enqueue.
+ */
+ // called by the input dispatcher thread
+ public void filterInputEvent(InputEvent event, int policyFlags) throws RemoteException {
+ if (SYSTRACE) {
+ Trace.traceBegin(Trace.TRACE_TAG_INPUT, "filterInputEvent");
+ }
+ try {
+ if (((event.getSource() & InputDevice.SOURCE_TOUCHSCREEN)
+ != InputDevice.SOURCE_TOUCHSCREEN)
+ || !(event instanceof MotionEvent)) {
+ sendInputEvent(event, policyFlags);
+ return;
+ }
+ if (DEBUG_INPUT) {
+ Slog.d(TAG, "Received event: " + event + ", policyFlags=0x"
+ + Integer.toHexString(policyFlags));
+ }
+ MotionEvent motionEvent = (MotionEvent) event;
+ final int deviceId = event.getDeviceId();
+ if (deviceId != mDeviceId) {
+ processDeviceSwitch(deviceId, motionEvent, policyFlags);
+ } else {
+ if ((policyFlags & WindowManagerPolicy.FLAG_PASS_TO_USER) == 0) {
+ synchronized (mLock) {
+ clearAndResetStateLocked(false, true);
+ }
+ }
+ processMotionEvent(motionEvent, policyFlags);
+ }
+ } finally {
+ event.recycle();
+ if (SYSTRACE) {
+ Trace.traceEnd(Trace.TRACE_TAG_INPUT);
+ }
+ }
+ }
+
+ private void processDeviceSwitch(int deviceId, MotionEvent motionEvent, int policyFlags) {
+ if (motionEvent.getActionMasked() == MotionEvent.ACTION_DOWN) {
+ mDeviceId = deviceId;
+ synchronized (mLock) {
+ clearAndResetStateLocked(true, false);
+ processMotionEvent(motionEvent, policyFlags);
+ }
+ } else {
+ sendInputEvent(motionEvent, policyFlags);
+ }
+ }
+
+ private void processMotionEvent(MotionEvent motionEvent, int policyFlags) {
+ final int action = motionEvent.getActionMasked();
+
+ synchronized (mLock) {
+ switch (mState) {
+ case LISTEN:
+ if (action == MotionEvent.ACTION_DOWN) {
+ boolean hit = mPositions != 0
+ && mTracker.start(motionEvent, mPositions, mSensitivity);
+ if (DEBUG) Slog.d(TAG, "start:" + hit);
+ if (hit) {
+ // cache the down event
+ cacheDelayedMotionEventLocked(motionEvent, policyFlags);
+ mState = State.DETECTING;
+ return;
+ }
+ }
+ sendInputEvent(motionEvent, policyFlags);
+ break;
+ case DETECTING:
+ cacheDelayedMotionEventLocked(motionEvent, policyFlags);
+ if (action == MotionEvent.ACTION_MOVE) {
+ if (mTracker.move(motionEvent)) {
+ // return: the tracker is either detecting or triggered onActivation
+ return;
+ }
+ }
+ if (DEBUG) {
+ Slog.d(TAG, "move: reset!");
+ }
+ clearAndResetStateLocked(false, true);
+ break;
+ case LOCKED:
+ cacheDelayedMotionEventLocked(motionEvent, policyFlags);
+ if (action != MotionEvent.ACTION_MOVE) {
+ clearAndResetStateLocked(false, true);
+ }
+ break;
+ case SYNTHESIZE:
+ if (action == MotionEvent.ACTION_MOVE) {
+ clearDelayedMotionEventsLocked();
+ sendSynthesizedMotionEventLocked(motionEvent, policyFlags);
+ mState = State.POSTSYNTHESIZE;
+ } else {
+ // This is the case where a race condition caught us: We already
+ // returned the handler thread that it is all right to call
+ // #gainTouchFocus(), but apparently this was wrong, as the gesture
+ // was canceled now.
+ clearAndResetStateLocked(false, true);
+ }
+ break;
+ case POSTSYNTHESIZE:
+ motionEvent.setDownTime(mSyntheticDownTime);
+ if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
+ mState = State.LISTEN;
+ mSyntheticDownTime = -1;
+ }
+ sendInputEvent(motionEvent, policyFlags);
+ break;
+ case DROP:
+ if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
+ clearDelayedMotionEventsLocked();
+ mState = State.LISTEN;
+ }
+ break;
+ }
+ }
+ }
+
+ private void clearAndResetStateLocked(boolean force, boolean shift) {
+ // ignore soft reset in POSTSYNTHESIZE, because we need to tamper with
+ // the event stream and going to LISTEN after an ACTION_UP anyway
+ if (!force && (mState == State.POSTSYNTHESIZE)) {
+ return;
+ }
+ switch (mState) {
+ case LISTEN:
+ // this is a nop
+ break;
+ case DETECTING:
+ mTracker.reset();
+ // intentionally no break here
+ case LOCKED:
+ case SYNTHESIZE:
+ sendDelayedMotionEventsLocked(shift);
+ break;
+ case POSTSYNTHESIZE:
+ // hard reset (this will break the event stream)
+ Slog.w(TAG, "Quit POSTSYNTHESIZE without ACTION_UP from ACTION_DOWN at "
+ + mSyntheticDownTime);
+ mSyntheticDownTime = -1;
+ break;
+ }
+ // if there are future events that need to be tampered with, goto POSTSYNTHESIZE
+ mState = mSyntheticDownTime == -1 ? State.LISTEN : State.POSTSYNTHESIZE;
+ }
+
+ private void sendInputEvent(InputEvent event, int policyFlags) {
+ try {
+ mHost.sendInputEvent(event, policyFlags);
+ } catch (RemoteException e) {
+ /* ignore */
+ }
+ }
+
+ private void cacheDelayedMotionEventLocked(MotionEvent event, int policyFlags) {
+ MotionEventInfo info = MotionEventInfo.obtain(event, policyFlags);
+ if (mMotionEventQueue == null) {
+ mMotionEventQueue = info;
+ } else {
+ mMotionEventQueueTail.next = info;
+ }
+ mMotionEventQueueTail = info;
+ mMotionEventQueueCountDebug++;
+ if (SYSTRACE) {
+ Trace.traceCounter(Trace.TRACE_TAG_INPUT, "meq", mMotionEventQueueCountDebug);
+ }
+ }
+
+ private void sendDelayedMotionEventsLocked(boolean shift) {
+ while (mMotionEventQueue != null) {
+ MotionEventInfo info = mMotionEventQueue;
+ mMotionEventQueue = info.next;
+
+ if (DEBUG) {
+ Slog.d(TAG, "Replay event: " + info.event);
+ }
+ mMotionEventQueueCountDebug--;
+ if (SYSTRACE) {
+ Trace.traceCounter(Trace.TRACE_TAG_INPUT, "meq", mMotionEventQueueCountDebug);
+ }
+ if (shift) {
+ final long offset = SystemClock.uptimeMillis() - info.cachedTimeMillis;
+ if (info.event.getActionMasked() == MotionEvent.ACTION_DOWN) {
+ mSyntheticDownTime = info.event.getDownTime() + offset;
+ }
+ sendMotionEventWithOffsetLocked(info.event, info.policyFlags, mSyntheticDownTime, offset);
+ if (info.event.getActionMasked() == MotionEvent.ACTION_UP) {
+ mSyntheticDownTime = -1;
+ }
+ } else {
+ sendInputEvent(info.event, info.policyFlags);
+ }
+ info.recycle();
+ }
+ mMotionEventQueueTail = null;
+ }
+
+ private void clearDelayedMotionEventsLocked() {
+ while (mMotionEventQueue != null) {
+ MotionEventInfo next = mMotionEventQueue.next;
+ mMotionEventQueue.recycle();
+ mMotionEventQueue = next;
+ }
+ mMotionEventQueueTail = null;
+ mMotionEventQueueCountDebug = 0;
+ if (SYSTRACE) {
+ Trace.traceCounter(Trace.TRACE_TAG_INPUT, "meq", mMotionEventQueueCountDebug);
+ }
+ }
+
+ private void sendMotionEventWithOffsetLocked(MotionEvent event, int policyFlags,
+ long downTime, long offset) {
+ final int pointerCount = event.getPointerCount();
+ PointerCoords[] coords = getTempPointerCoordsWithMinSizeLocked(pointerCount);
+ PointerProperties[] properties = getTempPointerPropertiesWithMinSizeLocked(pointerCount);
+ for (int i = 0; i < pointerCount; i++) {
+ event.getPointerCoords(i, coords[i]);
+ event.getPointerProperties(i, properties[i]);
+ }
+ final long eventTime = event.getEventTime() + offset;
+ sendInputEvent(MotionEvent.obtain(downTime, eventTime, event.getAction(), pointerCount,
+ properties, coords, event.getMetaState(), event.getButtonState(), 1.0f, 1.0f,
+ event.getDeviceId(), event.getEdgeFlags(), event.getSource(), event.getFlags()),
+ policyFlags);
+ }
+
+ private PointerCoords[] getTempPointerCoordsWithMinSizeLocked(int size) {
+ final int oldSize = mTempPointerCoords.length;
+ if (oldSize < size) {
+ PointerCoords[] oldTempPointerCoords = mTempPointerCoords;
+ mTempPointerCoords = new PointerCoords[size];
+ System.arraycopy(oldTempPointerCoords, 0, mTempPointerCoords, 0, oldSize);
+ }
+ for (int i = oldSize; i < size; i++) {
+ mTempPointerCoords[i] = new PointerCoords();
+ }
+ return mTempPointerCoords;
+ }
+
+ private PointerProperties[] getTempPointerPropertiesWithMinSizeLocked(int size) {
+ final int oldSize = mTempPointerProperties.length;
+ if (oldSize < size) {
+ PointerProperties[] oldTempPointerProperties = mTempPointerProperties;
+ mTempPointerProperties = new PointerProperties[size];
+ System.arraycopy(oldTempPointerProperties, 0, mTempPointerProperties, 0, oldSize);
+ }
+ for (int i = oldSize; i < size; i++) {
+ mTempPointerProperties[i] = new PointerProperties();
+ }
+ return mTempPointerProperties;
+ }
+
+ private void sendSynthesizedMotionEventLocked(MotionEvent event, int policyFlags) {
+ if (event.getPointerCount() == 1) {
+ event.getPointerCoords(0, mTempPointerCoords[0]);
+ event.getPointerProperties(0, mTempPointerProperties[0]);
+ MotionEvent down = MotionEvent.obtain(event.getEventTime(), event.getEventTime(),
+ MotionEvent.ACTION_DOWN, 1, mTempPointerProperties, mTempPointerCoords,
+ event.getMetaState(), event.getButtonState(),
+ 1.0f, 1.0f, event.getDeviceId(), event.getEdgeFlags(),
+ event.getSource(), event.getFlags());
+ Slog.d(TAG, "Synthesized event:" + down);
+ sendInputEvent(down, policyFlags);
+ mSyntheticDownTime = event.getEventTime();
+ } else {
+ Slog.w(TAG, "Could not synthesize MotionEvent, this will drop all following events!");
+ }
+ }
+
+ // should never be called
+ public IBinder asBinder() {
+ throw new UnsupportedOperationException();
+ }
+
+ // called by the input dispatcher thread
+ public void install(IInputFilterHost host) throws RemoteException {
+ if (DEBUG) {
+ Slog.d(TAG, "EdgeGesture input filter installed.");
+ }
+ mHost = host;
+ synchronized (mLock) {
+ clearAndResetStateLocked(true, false);
+ }
+ }
+
+ // called by the input dispatcher thread
+ public void uninstall() throws RemoteException {
+ if (DEBUG) {
+ Slog.d(TAG, "EdgeGesture input filter uninstalled.");
+ }
+ }
+
+ // called by a Binder thread
+ public void dump(PrintWriter pw, String prefix) {
+ synchronized (mLock) {
+ pw.print(prefix);
+ pw.println("mState=" + mState.name());
+ pw.print(prefix);
+ pw.println("mPositions=0x" + Integer.toHexString(mPositions));
+ pw.print(prefix);
+ pw.println("mQueue=" + mMotionEventQueueCountDebug + " items");
+ }
+ }
+}
diff --git a/services/java/com/android/server/gesture/EdgeGestureService.java b/services/java/com/android/server/gesture/EdgeGestureService.java
new file mode 100644
index 0000000..0581831
--- /dev/null
+++ b/services/java/com/android/server/gesture/EdgeGestureService.java
@@ -0,0 +1,488 @@
+/*
+ * Copyright (C) 2013 The CyanogenMod Project (Jens Doll)
+ *
+ * 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.gesture;
+
+import static com.android.internal.util.gesture.EdgeServiceConstants.POSITION_MASK;
+import static com.android.internal.util.gesture.EdgeServiceConstants.SENSITIVITY_DEFAULT;
+import static com.android.internal.util.gesture.EdgeServiceConstants.SENSITIVITY_MASK;
+import static com.android.internal.util.gesture.EdgeServiceConstants.SENSITIVITY_NONE;
+import static com.android.internal.util.gesture.EdgeServiceConstants.SENSITIVITY_SHIFT;
+import static com.android.internal.util.gesture.EdgeServiceConstants.LONG_LIVING;
+
+import android.Manifest;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.hardware.display.DisplayManager;
+import android.hardware.display.DisplayManager.DisplayListener;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+import android.os.Parcel;
+import android.os.RemoteException;
+import android.service.gesture.IEdgeGestureActivationListener;
+import android.service.gesture.IEdgeGestureHostCallback;
+import android.service.gesture.IEdgeGestureService;
+import android.util.Slog;
+import android.view.Display;
+import android.view.DisplayInfo;
+import android.view.WindowManager;
+
+import com.android.internal.util.gesture.EdgeGesturePosition;
+import com.android.server.gesture.EdgeGestureInputFilter;
+import com.android.server.input.InputManagerService;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A system service to track and handle edge swipe gestures. This service interacts with
+ * the {@link InputManagerService} to do all the dirty work for listeners:
+ * <li>Installing an input filter and listen for edge swipe gestures</li>
+ * <li>Removing those gestures from the input stream</li>
+ * <li>Transferring touch focus to new recipient</li>
+ */
+public class EdgeGestureService extends IEdgeGestureService.Stub {
+ public static final String TAG = "EdgeGestureService";
+ public static final boolean DEBUG = false;
+ public static final boolean DEBUG_INPUT = false;
+
+ public static final int MSG_EDGE_GESTURE_ACTIVATION = 32023;
+ public static final int MSG_UPDATE_SERVICE = 32025;
+
+ private final Context mContext;
+ private final InputManagerService mInputManager;
+
+ private final HandlerThread mHandlerThread = new HandlerThread("EdgeGestureHandler");
+ private Handler mHandler;
+
+ // Lock for mInputFilter, activations and listener related variables
+ private final Object mLock = new Object();
+ private EdgeGestureInputFilter mInputFilter;
+
+ private int mGlobalPositions = 0;
+ private int mGlobalSensitivity = 3;
+
+ private final class EdgeGestureActivationListenerRecord extends IEdgeGestureHostCallback.Stub implements DeathRecipient {
+ private boolean mActive;
+
+ public EdgeGestureActivationListenerRecord(IEdgeGestureActivationListener listener) {
+ this.listener = listener;
+ this.positions = 0;
+ }
+
+ public void binderDied() {
+ removeListenerRecord(this);
+ }
+
+ private void updateFlags(int flags) {
+ this.positions = flags & POSITION_MASK;
+ this.sensitivity = (flags & SENSITIVITY_MASK) >> SENSITIVITY_SHIFT;
+ this.longLiving = (flags & LONG_LIVING) != 0;
+ }
+
+ private boolean eligibleForActivation(int positionFlag) {
+ return (positions & positionFlag) != 0;
+ }
+
+ private boolean notifyEdgeGestureActivation(int touchX, int touchY, EdgeGesturePosition position) {
+ if ((positions & position.FLAG) != 0) {
+ try {
+ mActive = true;
+ listener.onEdgeGestureActivation(touchX, touchY, position.INDEX, 0);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Failed to notify process, assuming it died.", e);
+ mActive = false;
+ binderDied();
+ }
+ }
+ return mActive;
+ }
+
+ // called through Binder
+ public boolean gainTouchFocus(IBinder windowToken) {
+ if (DEBUG) {
+ Slog.d(TAG, "Gain touch focus for " + windowToken);
+ }
+ if (mActive) {
+ return mInputFilter.unlockFilter();
+ }
+ return false;
+ }
+
+ public boolean dropEventsUntilLift() {
+ if (DEBUG) {
+ Slog.d(TAG, "Will drop all next events till touch up");
+ }
+ if (mActive) {
+ return mInputFilter.dropSequence();
+ }
+ return false;
+ }
+
+ // called through Binder
+ public void restoreListenerState() throws RemoteException {
+ if (DEBUG) {
+ Slog.d(TAG, "Restore listener state");
+ }
+ if (mActive) {
+ mInputFilter.unlockFilter();
+ mActive = false;
+ synchronized (mLock) {
+ // restore input filter state by updating
+ mHandler.sendEmptyMessage(MSG_UPDATE_SERVICE);
+ }
+ }
+ }
+
+ public boolean isActive() {
+ return mActive;
+ }
+
+ public void dump(PrintWriter pw, String prefix) {
+ pw.print(prefix);
+ pw.print("mPositions=0x" + Integer.toHexString(positions));
+ pw.println(" mActive=" + mActive);
+ pw.print(prefix);
+ pw.println("mBinder=" + listener);
+ }
+
+ public int positions;
+ public int sensitivity;
+ public final IEdgeGestureActivationListener listener;
+ public boolean longLiving = false;
+ }
+ private final List<EdgeGestureActivationListenerRecord> mEdgeGestureActivationListener =
+ new ArrayList<EdgeGestureActivationListenerRecord>();
+ // end of lock guarded variables
+
+ private DisplayObserver mDisplayObserver;
+
+ // called by system server
+ public EdgeGestureService(Context context, InputManagerService inputManager) {
+ mContext = context;
+ mInputManager = inputManager;
+ }
+
+ // called by system server
+ public void systemReady() {
+ if (DEBUG) Slog.d(TAG, "Starting the edge gesture capture thread ...");
+
+ synchronized (mLock) {
+ mHandlerThread.start();
+ mHandler = new H(mHandlerThread.getLooper());
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ android.os.Process.setThreadPriority(
+ android.os.Process.THREAD_PRIORITY_FOREGROUND);
+ android.os.Process.setCanSelfBackground(false);
+ }
+ });
+ mDisplayObserver = new DisplayObserver(mContext, mHandler);
+ // check if anyone registered during startup
+ mHandler.sendEmptyMessage(MSG_UPDATE_SERVICE);
+ }
+ }
+
+
+ private void updateMonitoring() {
+ synchronized(mLock) {
+ mGlobalPositions = 0;
+ mGlobalSensitivity = SENSITIVITY_NONE;
+ boolean someLongLiving = false;
+ int activePositions = 0;
+ for (EdgeGestureActivationListenerRecord temp : mEdgeGestureActivationListener) {
+ mGlobalPositions |= temp.positions;
+ if (temp.isActive()) {
+ activePositions |= temp.positions;
+ }
+ if (temp.sensitivity != SENSITIVITY_NONE) {
+ mGlobalSensitivity = Math.max(mGlobalSensitivity, temp.sensitivity);
+ }
+ someLongLiving |= temp.longLiving;
+ }
+ boolean havePositions = mGlobalPositions != 0;
+ mGlobalPositions &= ~activePositions;
+ // if no special sensitivity is requested, we settle on DEFAULT
+ if (mGlobalSensitivity == SENSITIVITY_NONE) {
+ mGlobalSensitivity = SENSITIVITY_DEFAULT;
+ }
+
+ if (mInputFilter == null && havePositions) {
+ enforceMonitoringLocked();
+ } else if (mInputFilter != null && !havePositions && !someLongLiving) {
+ shutdownMonitoringLocked();
+ }
+ }
+ }
+
+ private void enforceMonitoringLocked() {
+ if (DEBUG) {
+ Slog.d(TAG, "Attempting to start monitoring input events ...");
+ }
+ mInputFilter = new EdgeGestureInputFilter(mContext, mHandler);
+ mInputManager.registerSecondaryInputFilter(mInputFilter);
+ mDisplayObserver.observe();
+ }
+
+ private void shutdownMonitoringLocked() {
+ if (DEBUG) {
+ Slog.d(TAG, "Shutting down monitoring input events ...");
+ }
+ mDisplayObserver.unobserve();
+ mInputManager.unregisterSecondaryInputFilter(mInputFilter);
+ mInputFilter = null;
+ }
+
+ // called through Binder
+ public IEdgeGestureHostCallback registerEdgeGestureActivationListener(IEdgeGestureActivationListener listener) {
+ if (mContext.checkCallingOrSelfPermission(Manifest.permission.INJECT_EVENTS)
+ != PackageManager.PERMISSION_GRANTED) {
+ Slog.w(TAG, "Permission Denial: can't register from from pid="
+ + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid());
+ return null;
+ }
+
+ if (listener == null) {
+ throw new IllegalArgumentException("listener must not be null");
+ }
+
+ EdgeGestureActivationListenerRecord record = null;
+ synchronized(mLock) {
+ record = findListenerRecordLocked(listener.asBinder());
+ if (record == null) {
+ record = new EdgeGestureActivationListenerRecord(listener);
+ try {
+ listener.asBinder().linkToDeath(record, 0);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Recipient died during registration pid=" + Binder.getCallingPid());
+ return null;
+ }
+ mEdgeGestureActivationListener.add(record);
+ }
+ }
+ return record;
+ }
+
+ // called through Binder
+ public void updateEdgeGestureActivationListener(IBinder listener, int positionFlags) {
+ if (listener == null) {
+ throw new IllegalArgumentException("listener must not be null");
+ }
+ synchronized(mLock) {
+ EdgeGestureActivationListenerRecord record = findListenerRecordLocked(listener);
+ if (record == null) {
+ Slog.w(TAG, "Unknown listener on update listener. Register first?");
+ throw new IllegalStateException("listener not registered");
+ }
+ record.updateFlags(positionFlags);
+ // update input filter only when #systemReady() was called
+ if (mHandler != null) {
+ mHandler.sendEmptyMessage(MSG_UPDATE_SERVICE);
+ }
+ }
+ }
+
+ private EdgeGestureActivationListenerRecord findListenerRecordLocked(IBinder listener) {
+ for (EdgeGestureActivationListenerRecord record : mEdgeGestureActivationListener) {
+ if (record.listener.asBinder().equals(listener)) {
+ return record;
+ }
+ }
+ return null;
+ }
+
+ private void removeListenerRecord(EdgeGestureActivationListenerRecord record) {
+ synchronized(mLock) {
+ mEdgeGestureActivationListener.remove(record);
+ // restore input filter state by updating
+ mHandler.sendEmptyMessage(MSG_UPDATE_SERVICE);
+ }
+ }
+
+ // called by handler thread
+ private boolean propagateActivation(int touchX, int touchY, EdgeGesturePosition position) {
+ synchronized(mLock) {
+ EdgeGestureActivationListenerRecord target = null;
+ for (EdgeGestureActivationListenerRecord record : mEdgeGestureActivationListener) {
+ if (record.eligibleForActivation(position.FLAG)) {
+ target = record;
+ break;
+ }
+ }
+ // NOTE: We can do this here because the #onGestureActivation() is a oneway
+ // Binder call. This means we do not block with holding the mListenerLock!!!
+ // If this ever change, this needs to be adjusted and if you don't know what
+ // this means, you should probably not mess around with this code, anyway.
+ if (target != null && !target.notifyEdgeGestureActivation(touchX, touchY, position)) {
+ target = null;
+ }
+ return target != null;
+ }
+ }
+
+ private final class H extends Handler {
+ public H(Looper looper) {
+ super(looper);
+ }
+
+ @Override
+ public void handleMessage(Message m) {
+ switch (m.what) {
+ case MSG_EDGE_GESTURE_ACTIVATION:
+ if (DEBUG) {
+ Slog.d(TAG, "Activating edge gesture on " + m.obj.toString());
+ }
+ // Since input filter runs asynchronously to us, double activation may happen
+ // theoretically. Take the safe route here.
+ removeMessages(MSG_EDGE_GESTURE_ACTIVATION);
+ if (propagateActivation(m.arg1, m.arg2, (EdgeGesturePosition) m.obj)) {
+ // switch off activated positions
+ updateMonitoring();
+ updateServiceHandler(mGlobalPositions, mGlobalSensitivity);
+ }
+ break;
+ case MSG_UPDATE_SERVICE:
+ updateMonitoring();
+ if (DEBUG) {
+ Slog.d(TAG, "Updating positions 0x" + Integer.toHexString(mGlobalPositions)
+ + " sensitivity: " + mGlobalSensitivity);
+ }
+ updateServiceHandler(mGlobalPositions, mGlobalSensitivity);
+ break;
+ }
+ }
+
+ private void updateServiceHandler(int positions, int sensitivity) {
+ synchronized (mLock) {
+ if (mInputFilter != null) {
+ mInputFilter.updatePositions(positions);
+ mInputFilter.updateSensitivity(sensitivity);
+ }
+ }
+ }
+ }
+
+ private final class DisplayObserver implements DisplayListener {
+ private final Handler mHandler;
+ private final DisplayManager mDisplayManager;
+
+ private final Display mDefaultDisplay;
+ private final DisplayInfo mDefaultDisplayInfo = new DisplayInfo();
+
+ public DisplayObserver(Context context, Handler handler) {
+ mHandler = handler;
+ mDisplayManager = (DisplayManager) context.getSystemService(
+ Context.DISPLAY_SERVICE);
+ final WindowManager windowManager = (WindowManager) context.getSystemService(
+ Context.WINDOW_SERVICE);
+
+ mDefaultDisplay = windowManager.getDefaultDisplay();
+ updateDisplayInfo();
+ }
+
+ private void updateDisplayInfo() {
+ if (DEBUG) {
+ Slog.d(TAG, "Updating display information ...");
+ }
+ if (mDefaultDisplay.getDisplayInfo(mDefaultDisplayInfo)) {
+ synchronized (mLock) {
+ if (mInputFilter != null) {
+ mInputFilter.updateDisplay(mDefaultDisplay, mDefaultDisplayInfo);
+ }
+ }
+ } else {
+ Slog.e(TAG, "Default display is not valid.");
+ }
+ }
+
+ public void observe() {
+ mDisplayManager.registerDisplayListener(this, mHandler);
+ updateDisplayInfo();
+ }
+
+ public void unobserve() {
+ mDisplayManager.unregisterDisplayListener(this);
+ }
+
+ @Override
+ public void onDisplayAdded(int displayId) {
+ /* do noting */
+ }
+
+ @Override
+ public void onDisplayRemoved(int displayId) {
+ /* do nothing */
+ }
+
+ @Override
+ public void onDisplayChanged(int displayId) {
+ updateDisplayInfo();
+ }
+ }
+
+ @Override
+ public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
+ throws RemoteException {
+ try {
+ return super.onTransact(code, data, reply, flags);
+ } catch (RuntimeException e) {
+ // let's log all exceptions we do not know about.
+ if (!(e instanceof IllegalArgumentException || e instanceof IllegalStateException)) {
+ Slog.e(TAG, "EdgeGestureService crashed: ", e);
+ }
+ throw e;
+ }
+ }
+
+ @Override
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ if (mContext.checkCallingOrSelfPermission(Manifest.permission.DUMP)
+ != PackageManager.PERMISSION_GRANTED) {
+ pw.println("Permission Denial: can't dump EdgeGestureService from from pid="
+ + Binder.getCallingPid()
+ + ", uid=" + Binder.getCallingUid());
+ return;
+ }
+
+ pw.println("EDGE GESTURE SERVICE (dumpsys edgegestureservice)\n");
+ synchronized(mLock) {
+ pw.println(" mInputFilter=" + mInputFilter);
+ if (mInputFilter != null) {
+ mInputFilter.dump(pw, " ");
+ }
+ pw.println(" mGlobalPositions=0x" + Integer.toHexString(mGlobalPositions));
+ pw.println(" mGlobalSensitivity=" + mGlobalSensitivity);
+ int i = 0;
+ for (EdgeGestureActivationListenerRecord record : mEdgeGestureActivationListener) {
+ if (record.isActive()) {
+ pw.println(" Active record: #" + (i + 1));
+ }
+ }
+ i = 0;
+ for (EdgeGestureActivationListenerRecord record : mEdgeGestureActivationListener) {
+ pw.println(" Listener #" + i + ":");
+ record.dump(pw, " ");
+ i++;
+ }
+ }
+ }
+}
diff --git a/services/java/com/android/server/gesture/EdgeGestureTracker.java b/services/java/com/android/server/gesture/EdgeGestureTracker.java
new file mode 100644
index 0000000..17cd95e
--- /dev/null
+++ b/services/java/com/android/server/gesture/EdgeGestureTracker.java
@@ -0,0 +1,252 @@
+/*
+ * Copyright (C) 2013 The CyanogenMod Project (Jens Doll)
+ *
+ * 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.gesture;
+
+import android.graphics.Point;
+import android.os.SystemClock;
+import android.util.Slog;
+import android.view.Display;
+import android.view.MotionEvent;
+
+import com.android.internal.util.gesture.EdgeGesturePosition;
+import com.android.internal.util.gesture.EdgeServiceConstants;
+
+/**
+ * A simple {@link MotionEvent} tracker class. The main aim of this tracker is to
+ * reject gestures as fast as possible, so there is only a small amount of events
+ * that will be delayed.
+ */
+public class EdgeGestureTracker {
+ public final static String TAG = "EdgeGestureTracker";
+ public final static boolean DEBUG = false;
+
+ public final static long TRIGGER_TIME_MS = 140;
+ public final static int PIXEL_SWIPE_OFFTAKE_SLOP = 2;
+
+ private final int mBaseThickness;
+ private final int mBaseTriggerDistance;
+ private final int mBasePerpendicularDistance;
+
+ private int mThickness;
+ private int mTriggerDistance;
+ private int mPerpendicularDistance;
+ private int mGracePeriodDistance;
+ private long mTimeOut;
+
+ private int mDisplayWidth;
+ private int mDisplayHeight;
+
+ private boolean mActive;
+ private EdgeGesturePosition mPosition;
+ private long mDownTime;
+ private int mInitialX;
+ private int mInitialY;
+ private int mOffTake;
+ private int mGracePeriod;
+
+ public interface OnActivationListener {
+ public void onActivation(MotionEvent event, int touchX, int touchY, EdgeGesturePosition position);
+ }
+ private OnActivationListener mActivationListener;
+
+ public EdgeGestureTracker(int thickness, int distance, int perpendicular) {
+ if (DEBUG) {
+ Slog.d(TAG, "init: " + thickness + "," + distance);
+ }
+ mBaseThickness = thickness;
+ mBaseTriggerDistance = distance;
+ mBasePerpendicularDistance = perpendicular;
+ setSensitivity(0);
+ }
+
+ private void setSensitivity(int sensitivity) {
+ float factor = 0.0f;
+ if (sensitivity >= 1) {
+ factor = (sensitivity - 1) / 4.0f;
+ }
+ if (DEBUG) {
+ Slog.d(TAG, "sensitivity: " + sensitivity + " => factor:" + factor);
+ }
+ // default values (without overlay):
+ // 140ms ... 210ms
+ mTimeOut = (long) (TRIGGER_TIME_MS * (factor + 1.0f));
+ // 12dp ... 18dp
+ mThickness = (int) (mBaseThickness * (factor + 1.0f));
+ // 12dp ... 6dp
+ mTriggerDistance = (int) (mBaseTriggerDistance * (1.0f - factor));
+ mPerpendicularDistance = (int) (mBasePerpendicularDistance * (1.0f - factor));
+ mGracePeriodDistance = (int) (mThickness / 3.0f);
+ }
+
+ public void setOnActivationListener(OnActivationListener listener) {
+ mActivationListener = listener;
+ }
+
+ public void reset() {
+ mActive = false;
+ }
+
+ public void updateDisplay(Display display) {
+ Point outSize = new Point(0,0);
+ display.getRealSize(outSize);
+ mDisplayWidth = outSize.x;
+ mDisplayHeight = outSize.y;
+ if (DEBUG) {
+ Slog.d(TAG, "new display: " + mDisplayWidth + "," + mDisplayHeight);
+ }
+ }
+
+ public boolean start(MotionEvent motionEvent, int positions, int sensitivity) {
+ final boolean unrestricted = (positions & EdgeServiceConstants.UNRESTRICTED) != 0;
+ final int x = (int) motionEvent.getX();
+ final float fx = motionEvent.getX() / mDisplayWidth;
+ final int y = (int) motionEvent.getY();
+ final float fy = motionEvent.getY() / mDisplayHeight;
+
+ // calculate trigger geometry based on sensitivity
+ setSensitivity(sensitivity);
+
+ if ((positions & EdgeGesturePosition.LEFT.FLAG) != 0) {
+ if (x < mThickness && (unrestricted || (fy > 0.1f && fy < 0.9f))) {
+ startWithPosition(motionEvent, EdgeGesturePosition.LEFT);
+ return true;
+ }
+ }
+ if ((positions & EdgeGesturePosition.BOTTOM.FLAG) != 0) {
+ if (y > mDisplayHeight - mThickness && (unrestricted || (fx > 0.1f && fx < 0.9f))) {
+ startWithPosition(motionEvent, EdgeGesturePosition.BOTTOM);
+ return true;
+ }
+ }
+ if ((positions & EdgeGesturePosition.RIGHT.FLAG) != 0) {
+ if (x > mDisplayWidth - mThickness && (unrestricted || (fy > 0.1f && fy < 0.9f))) {
+ startWithPosition(motionEvent, EdgeGesturePosition.RIGHT);
+ return true;
+ }
+ }
+ if ((positions & EdgeGesturePosition.TOP.FLAG) != 0) {
+ if (y < mThickness && (unrestricted || (fx > 0.1f && fx < 0.9f))) {
+ startWithPosition(motionEvent, EdgeGesturePosition.TOP);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private void startWithPosition(MotionEvent motionEvent, EdgeGesturePosition position) {
+ if (DEBUG) {
+ Slog.d(TAG, "start tracking from " + position.name());
+ }
+
+ mDownTime = motionEvent.getDownTime();
+ this.mPosition = position;
+ mInitialX = (int) motionEvent.getX();
+ mInitialY = (int) motionEvent.getY();
+ switch (position) {
+ case LEFT:
+ mGracePeriod = mGracePeriodDistance;
+ mOffTake = mInitialX - PIXEL_SWIPE_OFFTAKE_SLOP;
+ break;
+ case BOTTOM:
+ mOffTake = mInitialY + PIXEL_SWIPE_OFFTAKE_SLOP;
+ break;
+ case RIGHT:
+ mGracePeriod = mDisplayWidth - mGracePeriodDistance;
+ mOffTake = mInitialX + PIXEL_SWIPE_OFFTAKE_SLOP;
+ break;
+ case TOP:
+ mOffTake = mInitialY - PIXEL_SWIPE_OFFTAKE_SLOP;
+ break;
+ }
+ mActive = true;
+ }
+
+ public boolean move(MotionEvent motionEvent) {
+ if (!mActive || motionEvent.getEventTime() - mDownTime > mTimeOut) {
+ Slog.d(TAG, "edge gesture timeout: " + (motionEvent.getEventTime() - mDownTime));
+ mActive = false;
+ return false;
+ }
+
+ final int x = (int) motionEvent.getX();
+ final int y = (int) motionEvent.getY();
+ final int deltaX = x - mInitialX;
+ final int deltaY = y - mInitialY;
+
+ if (DEBUG) {
+ Slog.d(TAG, "move at " + x + "," + y + " " + deltaX + "," + deltaY);
+ }
+
+ boolean loaded = false;
+ switch (mPosition) {
+ case LEFT:
+ if (x < mGracePeriod) {
+ mInitialY = y;
+ }
+ if (deltaY < mPerpendicularDistance && deltaY > -mPerpendicularDistance
+ && x >= mOffTake) {
+ if (deltaX < mTriggerDistance) {
+ mOffTake = x - PIXEL_SWIPE_OFFTAKE_SLOP;
+ return true;
+ }
+ loaded = true;
+ }
+ break;
+ case BOTTOM:
+ if (deltaX < mPerpendicularDistance && deltaX > -mPerpendicularDistance
+ && y <= mOffTake) {
+ if (deltaY > -mTriggerDistance) {
+ mOffTake = y + PIXEL_SWIPE_OFFTAKE_SLOP;
+ return true;
+ }
+ loaded = true;
+ }
+ break;
+ case RIGHT:
+ if (x > mGracePeriod) {
+ mInitialY = y;
+ }
+ if (deltaY < mPerpendicularDistance && deltaY > -mPerpendicularDistance
+ && x <= mOffTake) {
+ if (deltaX > -mTriggerDistance) {
+ mOffTake = x + PIXEL_SWIPE_OFFTAKE_SLOP;
+ return true;
+ }
+ loaded = true;
+ }
+ break;
+ case TOP:
+ if (deltaX < mPerpendicularDistance && deltaX > -mPerpendicularDistance
+ && y >= mOffTake) {
+ if (deltaY < mTriggerDistance) {
+ mOffTake = y - PIXEL_SWIPE_OFFTAKE_SLOP;
+ return true;
+ }
+ loaded = true;
+ }
+ break;
+ }
+ mActive = false;
+ if (loaded && mActivationListener != null) {
+ if (DEBUG) {
+ Slog.d(TAG, "activate at " + x + "," + y + " " + mPosition + " within "
+ + (SystemClock.uptimeMillis() - mDownTime) + "ms");
+ }
+ mActivationListener.onActivation(motionEvent, x, y, mPosition);
+ }
+ return loaded;
+ }
+} \ No newline at end of file
diff --git a/services/libtvextensions/Android.mk b/services/libtvextensions/Android.mk
new file mode 100644
index 0000000..0a9e9bf
--- /dev/null
+++ b/services/libtvextensions/Android.mk
@@ -0,0 +1,21 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ jni/TvInputHalFactory.cpp \
+
+LOCAL_C_INCLUDES:= \
+ $(TOP)/frameworks/base/services/libtvextensions \
+
+LOCAL_CFLAGS += -Wno-multichar
+
+ifeq ($(TARGET_ENABLE_QC_TVINPUT_HAL_EXTENSIONS),true)
+ LOCAL_CFLAGS += -DENABLE_TVINPUT_HAL_EXTENSIONS
+endif
+
+LOCAL_MODULE:= libTvInputHalExtensions
+
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_STATIC_LIBRARY)
+
diff --git a/services/libtvextensions/common/ExtensionsLoader.hpp b/services/libtvextensions/common/ExtensionsLoader.hpp
new file mode 100644
index 0000000..010e614
--- /dev/null
+++ b/services/libtvextensions/common/ExtensionsLoader.hpp
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2013 - 2015, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <dlfcn.h>
+#include <common/TvInputHalExtensionsCommon.h>
+
+namespace android {
+
+/*
+ * Create strongly-typed objects of type T
+ * If the customization library exists and does contain a "named" constructor,
+ * invoke and create an instance
+ * Else create the object of type T itself
+ *
+ * Contains a static instance to dlopen'd library, But may end up
+ * opening the library mutiple times. Following snip from dlopen man page is
+ * reassuring "...Only a single copy of an object file is brought into the
+ * address space, even if dlopen() is invoked multiple times in reference to
+ * the file, and even if different pathnames are used to reference the file.."
+ */
+
+template <typename T>
+T *ExtensionsLoader<T>::createInstance(const char *createFunctionName) {
+ ALOGV("createInstance(%dbit) : %s", sizeof(intptr_t)*8, createFunctionName);
+ // create extended object if extensions-lib is available and
+ // TVINPUT_HAL_EXTENSIONS is enabled
+#if ENABLE_TVINPUT_HAL_EXTENSIONS
+ createFunction_t createFunc = loadCreateFunction(createFunctionName);
+ if (createFunc) {
+ return reinterpret_cast<T *>((*createFunc)());
+ }
+#endif
+ // Else, create the default object
+ return new T;
+}
+
+template <typename T>
+void ExtensionsLoader<T>::loadLib() {
+ if (!mLibHandle) {
+ mLibHandle = ::dlopen(CUSTOMIZATION_LIB_NAME, RTLD_LAZY);
+ if (!mLibHandle) {
+ ALOGV("%s", dlerror());
+ return;
+ }
+ ALOGV("Opened %s", CUSTOMIZATION_LIB_NAME);
+ }
+}
+
+template <typename T>
+createFunction_t ExtensionsLoader<T>::loadCreateFunction(const char *createFunctionName) {
+ loadLib();
+ if (!mLibHandle) {
+ return NULL;
+ }
+ createFunction_t func = (createFunction_t)dlsym(mLibHandle, createFunctionName);
+ if (!func) {
+ ALOGW("symbol %s not found: %s",createFunctionName, dlerror());
+ }
+ return func;
+}
+
+//static
+template <typename T>
+void *ExtensionsLoader<T>::mLibHandle = NULL;
+
+} //namespace android
diff --git a/services/libtvextensions/common/TvInputHalExtensionsCommon.h b/services/libtvextensions/common/TvInputHalExtensionsCommon.h
new file mode 100644
index 0000000..3db4c7b
--- /dev/null
+++ b/services/libtvextensions/common/TvInputHalExtensionsCommon.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2013 - 2015, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef _TVINPUTHAL_EXTENSIONS_COMMON_H_
+#define _TVINPUTHAL_EXTENSIONS_COMMON_H_
+
+namespace android {
+
+static const char * CUSTOMIZATION_LIB_NAME = "libTvInputHalEnhancements.so";
+
+typedef void *(*createFunction_t)(void);
+
+template <typename T>
+struct ExtensionsLoader {
+
+ static T *createInstance(const char *createFunctionName);
+
+private:
+ static void loadLib();
+ static createFunction_t loadCreateFunction(const char *createFunctionName);
+ static void *mLibHandle;
+};
+
+/*
+ * Boiler-plate to declare the class as a singleton (with a static getter)
+ * which can be loaded (dlopen'd) via ExtensionsLoader
+ */
+#define DECLARE_LOADABLE_SINGLETON(className) \
+protected: \
+ className(); \
+ virtual ~className(); \
+ static className *sInst; \
+private: \
+ className(const className&); \
+ className &operator=(className &); \
+public: \
+ static className *get() { \
+ return sInst; \
+ } \
+ friend struct ExtensionsLoader<className>;
+
+} //namespace android
+
+#endif // _TVINPUTHAL_EXTENSIONS_COMMON_H_
diff --git a/services/libtvextensions/jni/BufferProducerThread.h b/services/libtvextensions/jni/BufferProducerThread.h
new file mode 100644
index 0000000..6699edc
--- /dev/null
+++ b/services/libtvextensions/jni/BufferProducerThread.h
@@ -0,0 +1,89 @@
+/* Copyright (c) 2013 - 2015, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Not a contribution.
+ */
+/*
+ * Copyright 2014 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.
+ */
+
+#ifndef TVINPUT_HAL_INTERFACE_H_
+#define TVINPUT_HAL_INTERFACE_H_
+
+#include "jni.h"
+
+#include <gui/Surface.h>
+#include <hardware/tv_input.h>
+
+namespace android {
+
+class BufferProducerThread : public Thread {
+public:
+ BufferProducerThread(tv_input_device_t* device, int deviceId, const tv_stream_t* stream);
+
+ virtual status_t readyToRun();
+
+ virtual int setSurface(const sp<Surface>& surface);
+ virtual void onCaptured(uint32_t seq, bool succeeded);
+ virtual void shutdown();
+
+protected:
+ Mutex mLock;
+ Condition mCondition;
+ sp<Surface> mSurface;
+ tv_input_device_t* mDevice;
+ int mDeviceId;
+ tv_stream_t mStream;
+ sp<ANativeWindowBuffer_t> mBuffer;
+ enum {
+ CAPTURING,
+ CAPTURED,
+ RELEASED,
+ } mBufferState;
+ uint32_t mSeq;
+ bool mShutdown;
+
+ virtual bool threadLoop();
+
+ virtual int setSurfaceLocked(const sp<Surface>& surface);
+};
+
+} // namespace android
+
+#endif // TVINPUT_HAL_INTERFACE_H_
diff --git a/services/libtvextensions/jni/TvInputHalExtensions.h b/services/libtvextensions/jni/TvInputHalExtensions.h
new file mode 100644
index 0000000..479e544
--- /dev/null
+++ b/services/libtvextensions/jni/TvInputHalExtensions.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2013 - 2015, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef _TVINPUTHAL_EXTENSIONS_H_
+#define _TVINPUTHAL_EXTENSIONS_H_
+
+#include <utils/RefBase.h>
+#include <common/TvInputHalExtensionsCommon.h>
+#include <jni/BufferProducerThread.h>
+
+namespace android {
+
+class BufferProducerThread;
+
+/*
+ * Factory to create objects of base-classes in libstagefright
+ */
+struct TvInputHalFactory {
+ virtual sp<BufferProducerThread> createBufferProducerThread(tv_input_device_t* device,
+ int deviceId,
+ const tv_stream_t* stream);
+
+ // ----- NO TRESSPASSING BEYOND THIS LINE ------
+ DECLARE_LOADABLE_SINGLETON(TvInputHalFactory);
+};
+
+}
+
+#endif // _TVINPUTHAL_EXTENSIONS_H_
diff --git a/services/libtvextensions/jni/TvInputHalFactory.cpp b/services/libtvextensions/jni/TvInputHalFactory.cpp
new file mode 100644
index 0000000..b752066
--- /dev/null
+++ b/services/libtvextensions/jni/TvInputHalFactory.cpp
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2013 - 2015, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define LOG_TAG "TvInputHalFactory"
+#include <utils/Log.h>
+
+#include "common/ExtensionsLoader.hpp"
+#include "jni/TvInputHalExtensions.h"
+
+namespace android {
+
+ sp<BufferProducerThread> TvInputHalFactory::createBufferProducerThread(tv_input_device_t* device,
+ int deviceId,
+ const tv_stream_t* stream) {
+ return new BufferProducerThread(device, deviceId, stream);
+}
+
+// ----- NO TRESSPASSING BEYOND THIS LINE ------
+TvInputHalFactory::TvInputHalFactory() {
+}
+
+TvInputHalFactory::~TvInputHalFactory() {
+}
+
+//static
+TvInputHalFactory *TvInputHalFactory::sInst =
+ ExtensionsLoader<TvInputHalFactory>::createInstance("createExtendedFactory");
+
+} //namespace android
+
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
index ed1db6f..993faa9 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
@@ -23,15 +23,27 @@ import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
import android.content.Context;
import android.content.pm.PackageParser;
+import android.content.res.AssetManager;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.os.SystemProperties;
import android.test.AndroidTestCase;
+import android.test.mock.MockContext;
+import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
+import android.util.DisplayMetrics;
import android.util.Log;
import android.util.LongSparseArray;
import com.android.internal.os.AtomicFile;
import java.lang.reflect.Constructor;
+
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import com.android.internal.R;
+
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
@@ -160,6 +172,12 @@ public class PackageManagerSettingsTests extends AndroidTestCase {
folder.delete();
}
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ System.setProperty("dexmaker.dexcache", getContext().getCacheDir().toString());
+ }
+
private void writeOldFiles() {
deleteSystemFolder();
writePackagesXml();
@@ -269,7 +287,7 @@ public class PackageManagerSettingsTests extends AndroidTestCase {
// Write the package files and make sure they're parsed properly the first time
writeOldFiles();
Settings settings = new Settings(getContext().getFilesDir(), new Object());
- assertEquals(true, settings.readLPw(null, null, 0, false));
+ assertEquals(true, settings.readLPw(null, null, 0, false, null));
assertNotNull(settings.peekPackageLPr(PACKAGE_NAME_3));
assertNotNull(settings.peekPackageLPr(PACKAGE_NAME_1));
@@ -289,12 +307,12 @@ public class PackageManagerSettingsTests extends AndroidTestCase {
writeOldFiles();
createUserManagerServiceRef();
Settings settings = new Settings(getContext().getFilesDir(), new Object());
- assertEquals(true, settings.readLPw(null, null, 0, false));
+ assertEquals(true, settings.readLPw(null, null, 0, false, null));
settings.writeLPr();
// Create Settings again to make it read from the new files
settings = new Settings(getContext().getFilesDir(), new Object());
- assertEquals(true, settings.readLPw(null, null, 0, false));
+ assertEquals(true, settings.readLPw(null, null, 0, false, null));
PackageSetting ps = settings.peekPackageLPr(PACKAGE_NAME_2);
assertEquals(COMPONENT_ENABLED_STATE_DISABLED_USER, ps.getEnabled(0));
@@ -305,7 +323,7 @@ public class PackageManagerSettingsTests extends AndroidTestCase {
// Write the package files and make sure they're parsed properly the first time
writeOldFiles();
Settings settings = new Settings(getContext().getFilesDir(), new Object());
- assertEquals(true, settings.readLPw(null, null, 0, false));
+ assertEquals(true, settings.readLPw(null, null, 0, false, null));
// Enable/Disable a package
PackageSetting ps = settings.peekPackageLPr(PACKAGE_NAME_1);
@@ -335,4 +353,38 @@ public class PackageManagerSettingsTests extends AndroidTestCase {
hasEnabled = ps.getEnabledComponents(0) != null && ps.getEnabledComponents(0).size() > 0;
assertEquals(false, hasEnabled);
}
+
+ // Checks if a package that is locked to a different region is rejected
+ // from being installed
+ public void testPrebundledDifferentRegionReject() {
+ Settings settings = new Settings(getContext(), getContext().getFilesDir());
+ String expectedPackageNeededForRegion = "org.cyanogenmod.restricted.package";
+ Resources resources = Mockito.mock(Resources.class);
+ String[] regionRestrictedPackages = new String[] {
+ expectedPackageNeededForRegion
+ };
+ Mockito.when(resources.getStringArray(R.array.config_restrict_to_region_locked_devices))
+ .thenReturn(regionRestrictedPackages);
+ assertFalse(settings.shouldPrebundledPackageBeInstalled(resources,
+ expectedPackageNeededForRegion, resources));
+ }
+
+ // Checks if a package that is locked to the current region is accepted
+ // This also covers the test for a package that needs to be installed on a
+ // non region locked device
+ public void testPrebundledMatchingRegionAccept() {
+ Settings settings = new Settings(getContext(), getContext().getFilesDir());
+ String expectedPackageNeededForRegion = "org.cyanogenmod.restricted.package";
+ Resources resources = Mockito.mock(Resources.class);
+ String[] regionLockedPackages = new String[] {
+ expectedPackageNeededForRegion
+ };
+ Mockito.when(resources.getStringArray(R.array.config_region_locked_packages))
+ .thenReturn(regionLockedPackages);
+
+ Mockito.when(resources.getStringArray(R.array.config_restrict_to_region_locked_devices))
+ .thenReturn(regionLockedPackages);
+ assertTrue(settings.shouldPrebundledPackageBeInstalled(resources,
+ expectedPackageNeededForRegion, resources));
+ }
}
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index 2b8afba..54d9cd9 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -218,7 +218,7 @@ public class UsageStatsService extends SystemService implements
synchronized (this) {
mScreenOnTime = readScreenOnTimeLocked();
}
- mDisplayManager.registerDisplayListener(mDisplayListener, null);
+ mDisplayManager.registerDisplayListener(mDisplayListener, mHandler);
synchronized (this) {
updateDisplayLocked();
}
diff --git a/services/usb/Android.mk b/services/usb/Android.mk
index feabf0a..2a9c382 100644
--- a/services/usb/Android.mk
+++ b/services/usb/Android.mk
@@ -9,4 +9,6 @@ LOCAL_SRC_FILES += \
LOCAL_JAVA_LIBRARIES := services.core
+LOCAL_JAVA_LIBRARIES += org.cyanogenmod.platform.internal
+
include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/services/usb/java/com/android/server/usb/UsbAlsaManager.java b/services/usb/java/com/android/server/usb/UsbAlsaManager.java
index 31763e7..701272e 100644
--- a/services/usb/java/com/android/server/usb/UsbAlsaManager.java
+++ b/services/usb/java/com/android/server/usb/UsbAlsaManager.java
@@ -439,7 +439,7 @@ public final class UsbAlsaManager {
UsbAudioDevice audioDevice = mAudioDevices.remove(usbDevice);
if (audioDevice != null) {
- if (audioDevice.mHasPlayback || audioDevice.mHasPlayback) {
+ if (audioDevice.mHasPlayback || audioDevice.mHasCapture) {
notifyDeviceState(audioDevice, false);
// if there any external devices left, select one of them
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index a4a4d84..34a17a2 100644
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -51,6 +51,7 @@ import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.FgThread;
+import cyanogenmod.providers.CMSettings;
import java.io.File;
import java.io.FileNotFoundException;
@@ -322,7 +323,7 @@ public class UsbDeviceManager {
private boolean mCurrentFunctionsApplied;
private UsbAccessory mCurrentAccessory;
private int mUsbNotificationId;
- private boolean mAdbNotificationShown;
+ private int mAdbNotificationId;
private int mCurrentUser = UserHandle.USER_NULL;
public UsbHandler(Looper looper) {
@@ -348,6 +349,20 @@ public class UsbDeviceManager {
Settings.Global.getUriFor(Settings.Global.ADB_ENABLED),
false, new AdbSettingsObserver());
+ ContentObserver adbNotificationObserver = new ContentObserver(null) {
+ @Override
+ public void onChange(boolean selfChange) {
+ updateAdbNotification();
+ }
+ };
+
+ mContentResolver.registerContentObserver(
+ CMSettings.Secure.getUriFor(CMSettings.Secure.ADB_PORT),
+ false, adbNotificationObserver);
+ mContentResolver.registerContentObserver(
+ CMSettings.Secure.getUriFor(CMSettings.Secure.ADB_NOTIFY),
+ false, adbNotificationObserver);
+
// Watch for USB configuration changes
mUEventObserver.startObserving(USB_STATE_MATCH);
mUEventObserver.startObserving(ACCESSORY_START_MATCH);
@@ -794,15 +809,35 @@ public class UsbDeviceManager {
private void updateAdbNotification() {
if (mNotificationManager == null) return;
- final int id = com.android.internal.R.string.adb_active_notification_title;
- if (mAdbEnabled && mConnected) {
- if ("0".equals(SystemProperties.get("persist.adb.notify"))) return;
+ final int id;
+ boolean usbAdbActive = mAdbEnabled && mConnected;
+ boolean netAdbActive = mAdbEnabled &&
+ CMSettings.Secure.getInt(mContentResolver, CMSettings.Secure.ADB_PORT, -1) > 0;
+ boolean hideNotification = "0".equals(SystemProperties.get("persist.adb.notify"))
+ || CMSettings.Secure.getInt(mContext.getContentResolver(),
+ CMSettings.Secure.ADB_NOTIFY, 1) == 0;
+
+ if (hideNotification) {
+ id = 0;
+ } else if (usbAdbActive && netAdbActive) {
+ id = com.android.internal.R.string.adb_both_active_notification_title;
+ } else if (usbAdbActive) {
+ id = com.android.internal.R.string.adb_active_notification_title;
+ } else if (netAdbActive) {
+ id = com.android.internal.R.string.adb_net_active_notification_title;
+ } else {
+ id = 0;
+ }
- if (!mAdbNotificationShown) {
+ if (id != mAdbNotificationId) {
+ if (mAdbNotificationId != 0) {
+ mNotificationManager.cancelAsUser(null, mAdbNotificationId, UserHandle.ALL);
+ }
+ if (id != 0) {
Resources r = mContext.getResources();
CharSequence title = r.getText(id);
CharSequence message = r.getText(
- com.android.internal.R.string.adb_active_notification_message);
+ com.android.internal.R.string.adb_active_generic_notification_message);
Intent intent = Intent.makeRestartActivityTask(
new ComponentName("com.android.settings",
@@ -824,13 +859,11 @@ public class UsbDeviceManager {
.setContentIntent(pi)
.setVisibility(Notification.VISIBILITY_PUBLIC)
.build();
- mAdbNotificationShown = true;
+
mNotificationManager.notifyAsUser(null, id, notification,
UserHandle.ALL);
}
- } else if (mAdbNotificationShown) {
- mAdbNotificationShown = false;
- mNotificationManager.cancelAsUser(null, id, UserHandle.ALL);
+ mAdbNotificationId = id;
}
}
diff --git a/services/usb/java/com/android/server/usb/UsbSettingsManager.java b/services/usb/java/com/android/server/usb/UsbSettingsManager.java
index 2cf42f0..674952c 100644
--- a/services/usb/java/com/android/server/usb/UsbSettingsManager.java
+++ b/services/usb/java/com/android/server/usb/UsbSettingsManager.java
@@ -739,7 +739,7 @@ class UsbSettingsManager {
}
// Send broadcast to running activity with registered intent
- mUserContext.sendBroadcast(intent);
+ mUserContext.sendBroadcastAsUser(intent, UserHandle.ALL);
// Start activity with registered intent
resolveActivity(intent, matches, defaultPackage, device, null);
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index f149f24..66e8b3e 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -206,8 +206,32 @@ public final class Call {
*/
public static final int CAPABILITY_CAN_PAUSE_VIDEO = 0x00100000;
+ /**
+ * Call has voice privacy capability.
+ * @hide
+ */
+ public static final int CAPABILITY_VOICE_PRIVACY = 0x00400000;
+
+ /**
+ * Local device supports downgrading a video call to a voice-only call.
+ * @hide
+ */
+ public static final int CAPABILITY_SUPPORTS_DOWNGRADE_TO_VOICE_LOCAL = 0x00800000;
+
+ /**
+ * Remote device supports downgrading a video call to a voice-only call.
+ * @hide
+ */
+ public static final int CAPABILITY_SUPPORTS_DOWNGRADE_TO_VOICE_REMOTE = 0x01000000;
+
+ /**
+ * Add participant in an active or conference call option
+ * @hide
+ */
+ public static final int CAPABILITY_ADD_PARTICIPANT = 0x02000000;
+
//******************************************************************************************
- // Next CAPABILITY value: 0x00004000
+ // Next CAPABILITY value: 0x04000000
//******************************************************************************************
/**
@@ -248,6 +272,7 @@ public final class Call {
private final int mCallCapabilities;
private final int mCallProperties;
private final DisconnectCause mDisconnectCause;
+ private final long mCreateTimeMillis;
private final long mConnectTimeMillis;
private final GatewayInfo mGatewayInfo;
private final int mVideoState;
@@ -321,6 +346,12 @@ public final class Call {
if (can(capabilities, CAPABILITY_SUPPORTS_VT_REMOTE_TX)) {
builder.append(" CAPABILITY_SUPPORTS_VT_REMOTE_TX");
}
+ if (can(capabilities, CAPABILITY_SUPPORTS_DOWNGRADE_TO_VOICE_LOCAL)) {
+ builder.append(" CAPABILITY_SUPPORTS_DOWNGRADE_TO_VOICE_LOCAL");
+ }
+ if (can(capabilities, CAPABILITY_SUPPORTS_DOWNGRADE_TO_VOICE_REMOTE)) {
+ builder.append(" CAPABILITY_SUPPORTS_DOWNGRADE_TO_VOICE_REMOTE");
+ }
if (can(capabilities, CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL)) {
builder.append(" CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL");
}
@@ -333,6 +364,12 @@ public final class Call {
if (can(capabilities, CAPABILITY_CAN_PAUSE_VIDEO)) {
builder.append(" CAPABILITY_CAN_PAUSE_VIDEO");
}
+ if (can(capabilities, CAPABILITY_VOICE_PRIVACY)) {
+ builder.append(" CAPABILITY_VOICE_PRIVACY");
+ }
+ if (can(capabilities, CAPABILITY_ADD_PARTICIPANT)) {
+ builder.append(" CAPABILITY_ADD_PARTICIPANT");
+ }
builder.append("]");
return builder.toString();
}
@@ -459,6 +496,14 @@ public final class Call {
}
/**
+ * @return the time the Call object was created
+ * {@hide}
+ */
+ public long getCreateTimeMillis() {
+ return mCreateTimeMillis;
+ }
+
+ /**
* @return Information about any calling gateway the {@code Call} may be using.
*/
public GatewayInfo getGatewayInfo() {
@@ -508,6 +553,7 @@ public final class Call {
Objects.equals(mCallCapabilities, d.mCallCapabilities) &&
Objects.equals(mCallProperties, d.mCallProperties) &&
Objects.equals(mDisconnectCause, d.mDisconnectCause) &&
+ Objects.equals(mCreateTimeMillis, d.mCreateTimeMillis) &&
Objects.equals(mConnectTimeMillis, d.mConnectTimeMillis) &&
Objects.equals(mGatewayInfo, d.mGatewayInfo) &&
Objects.equals(mVideoState, d.mVideoState) &&
@@ -529,6 +575,7 @@ public final class Call {
Objects.hashCode(mCallCapabilities) +
Objects.hashCode(mCallProperties) +
Objects.hashCode(mDisconnectCause) +
+ Objects.hashCode(mCreateTimeMillis) +
Objects.hashCode(mConnectTimeMillis) +
Objects.hashCode(mGatewayInfo) +
Objects.hashCode(mVideoState) +
@@ -547,6 +594,7 @@ public final class Call {
int capabilities,
int properties,
DisconnectCause disconnectCause,
+ long createTimeMillis,
long connectTimeMillis,
GatewayInfo gatewayInfo,
int videoState,
@@ -561,6 +609,7 @@ public final class Call {
mCallCapabilities = capabilities;
mCallProperties = properties;
mDisconnectCause = disconnectCause;
+ mCreateTimeMillis = createTimeMillis;
mConnectTimeMillis = connectTimeMillis;
mGatewayInfo = gatewayInfo;
mVideoState = videoState;
@@ -682,6 +731,28 @@ public final class Call {
private Details mDetails;
/**
+ * when mIsActiveSub True indicates this call belongs to active subscription
+ * Calls belonging to active subscription are shown to user.
+ */
+ private boolean mIsActiveSub = false;
+
+ /**
+ * Set this call object as active subscription.
+ * @hide
+ */
+ public void setActive() {
+ mIsActiveSub = true;
+ }
+
+ /**
+ * return if this call object belongs to active subscription.
+ * @hide
+ */
+ public boolean isActive() {
+ return mIsActiveSub;
+ }
+
+ /**
* Obtains the post-dial sequence remaining to be emitted by this {@code Call}, if any.
*
* @return The remaining post-dial sequence, or {@code null} if there is no post-dial sequence
@@ -971,11 +1042,22 @@ public final class Call {
}
/** {@hide} */
- Call(Phone phone, String telecomCallId, InCallAdapter inCallAdapter) {
+ Call(Phone phone, String telecomCallId, InCallAdapter inCallAdapter, boolean isActiveSub) {
mPhone = phone;
mTelecomCallId = telecomCallId;
mInCallAdapter = inCallAdapter;
mState = STATE_NEW;
+ mIsActiveSub = isActiveSub;
+ }
+
+ /** {@hide} */
+ Call(Phone phone, String telecomCallId, InCallAdapter inCallAdapter, int state,
+ boolean isActiveSub) {
+ mPhone = phone;
+ mTelecomCallId = telecomCallId;
+ mInCallAdapter = inCallAdapter;
+ mState = state;
+ mIsActiveSub = isActiveSub;
}
/** {@hide} */
@@ -1003,6 +1085,7 @@ public final class Call {
parcelableCall.getCapabilities(),
parcelableCall.getProperties(),
parcelableCall.getDisconnectCause(),
+ parcelableCall.getCreateTimeMillis(),
parcelableCall.getConnectTimeMillis(),
parcelableCall.getGatewayInfo(),
parcelableCall.getVideoState(),
@@ -1028,9 +1111,10 @@ public final class Call {
}
int state = parcelableCall.getState();
- boolean stateChanged = mState != state;
+ boolean stateChanged = (mState != state) || (mIsActiveSub != parcelableCall.isActive());
if (stateChanged) {
mState = state;
+ mIsActiveSub = parcelableCall.isActive();
}
String parentId = parcelableCall.getParentCallId();
@@ -1107,6 +1191,11 @@ public final class Call {
}
}
+ /** {@hide} */
+ final void onMergeFailed() {
+ fireStateChanged(mState);
+ }
+
private void fireStateChanged(final int newState) {
for (CallbackRecord<Callback> record : mCallbackRecords) {
final Call call = this;
diff --git a/telecomm/java/android/telecom/Conference.java b/telecomm/java/android/telecom/Conference.java
index 77fdb65..f6a6dcc 100644
--- a/telecomm/java/android/telecom/Conference.java
+++ b/telecomm/java/android/telecom/Conference.java
@@ -160,7 +160,10 @@ public abstract class Conference extends Conferenceable {
* @hide
*/
public void removeCapability(int capability) {
- mConnectionCapabilities &= ~capability;
+ int newCapabilities = mConnectionCapabilities;
+ newCapabilities &= ~capability;
+
+ setConnectionCapabilities(newCapabilities);
}
/**
@@ -170,7 +173,10 @@ public abstract class Conference extends Conferenceable {
* @hide
*/
public void addCapability(int capability) {
- mConnectionCapabilities |= capability;
+ int newCapabilities = mConnectionCapabilities;
+ newCapabilities |= capability;
+
+ setConnectionCapabilities(newCapabilities);
}
/**
@@ -222,6 +228,14 @@ public abstract class Conference extends Conferenceable {
public void onSeparate(Connection connection) {}
/**
+ * Invoked when the conference adds a participant to the conference call.
+ *
+ * @param participant The participant to be added with conference call.
+ * @hide
+ */
+ public void onAddParticipant(String participant) {}
+
+ /**
* Invoked when the specified {@link Connection} should merged with the conference call.
*
* @param connection The {@code Connection} to merge.
@@ -559,6 +573,7 @@ public abstract class Conference extends Conferenceable {
private void setState(int newState) {
if (newState != Connection.STATE_ACTIVE &&
+ newState != Connection.STATE_DIALING &&
newState != Connection.STATE_HOLDING &&
newState != Connection.STATE_DISCONNECTED) {
Log.w(this, "Unsupported state transition for Conference call.",
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index 7b277c5..f025955 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -227,6 +227,13 @@ public abstract class Connection extends Conferenceable {
public static final int CAPABILITY_CAN_PAUSE_VIDEO = 0x00100000;
/**
+ * Add participant in an active or conference call option
+ *
+ * @hide
+ */
+ public static final int CAPABILITY_ADD_PARTICIPANT = 0x02000000;
+
+ /**
* For a conference, indicates the conference will not have child connections.
* <p>
* An example of a conference with child connections is a GSM conference call, where the radio
@@ -247,9 +254,26 @@ public abstract class Connection extends Conferenceable {
* @hide
*/
public static final int CAPABILITY_CONFERENCE_HAS_NO_CHILDREN = 0x00200000;
+ /**
+ * Call has voice privacy capability.
+ * @hide
+ */
+ public static final int CAPABILITY_VOICE_PRIVACY = 0x00400000;
+
+ /**
+ * Local device supports voice telephony.
+ * @hide
+ */
+ public static final int CAPABILITY_SUPPORTS_DOWNGRADE_TO_VOICE_LOCAL = 0x00800000;
+
+ /**
+ * Remote device supports voice telephony.
+ * @hide
+ */
+ public static final int CAPABILITY_SUPPORTS_DOWNGRADE_TO_VOICE_REMOTE = 0x01000000;
//**********************************************************************************************
- // Next CAPABILITY value: 0x00400000
+ // Next CAPABILITY value: 0x04000000
//**********************************************************************************************
/**
@@ -275,6 +299,13 @@ public abstract class Connection extends Conferenceable {
*/
public static final String EXTRA_CALL_SUBJECT = "android.telecom.extra.CALL_SUBJECT";
+ /**
+ * Call extras key to pack/unpack call history info.
+ * The value for this key should be an ArrayList of Strings.
+ * @hide
+ */
+ public static final String EXTRA_CALL_HISTORY_INFO = "EXTRA_CALL_HISTORY_INFO";
+
// Flag controlling whether PII is emitted into the logs
private static final boolean PII_DEBUG = Log.isLoggable(android.util.Log.DEBUG);
@@ -364,6 +395,12 @@ public abstract class Connection extends Conferenceable {
if (can(capabilities, CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL)) {
builder.append(" CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL");
}
+ if (can(capabilities, CAPABILITY_SUPPORTS_DOWNGRADE_TO_VOICE_LOCAL)) {
+ builder.append(" CAPABILITY_SUPPORTS_DOWNGRADE_TO_VOICE_LOCAL");
+ }
+ if (can(capabilities, CAPABILITY_SUPPORTS_DOWNGRADE_TO_VOICE_REMOTE)) {
+ builder.append(" CAPABILITY_SUPPORTS_DOWNGRADE_TO_VOICE_REMOTE");
+ }
if (can(capabilities, CAPABILITY_HIGH_DEF_AUDIO)) {
builder.append(" CAPABILITY_HIGH_DEF_AUDIO");
}
@@ -418,6 +455,7 @@ public abstract class Connection extends Conferenceable {
public void onConferenceStarted() {}
public void onConferenceMergeFailed(Connection c) {}
public void onExtrasChanged(Connection c, Bundle extras) {}
+ public void onCdmaConnectionTimeReset(Connection c) {}
}
/**
@@ -1582,6 +1620,16 @@ public abstract class Connection extends Conferenceable {
}
/**
+ *@hide
+ * Resets the cdma connection time.
+ */
+ public final void resetCdmaConnectionTime() {
+ for (Listener l : mListeners) {
+ l.onCdmaConnectionTimeReset(this);
+ }
+ }
+
+ /**
* Returns the connections or conferences with which this connection can be conferenced.
*/
public final List<Conferenceable> getConferenceables() {
@@ -1707,6 +1755,12 @@ public abstract class Connection extends Conferenceable {
public void onStopDtmfTone() {}
/**
+ * Notifies this to set local call hold.
+ * {@hide}
+ */
+ public void setLocalCallHold(boolean lchState) {}
+
+ /**
* Notifies this Connection of a request to disconnect.
*/
public void onDisconnect() {}
diff --git a/telecomm/java/android/telecom/ConnectionRequest.java b/telecomm/java/android/telecom/ConnectionRequest.java
index 6863214..2e8f8fd 100644
--- a/telecomm/java/android/telecom/ConnectionRequest.java
+++ b/telecomm/java/android/telecom/ConnectionRequest.java
@@ -28,7 +28,7 @@ import android.os.Parcelable;
public final class ConnectionRequest implements Parcelable {
// TODO: Token to limit recursive invocations
- private final PhoneAccountHandle mAccountHandle;
+ private PhoneAccountHandle mAccountHandle;
private final Uri mAddress;
private final Bundle mExtras;
private final int mVideoState;
@@ -74,6 +74,9 @@ public final class ConnectionRequest implements Parcelable {
*/
public PhoneAccountHandle getAccountHandle() { return mAccountHandle; }
+ /** {@hide} */
+ public void setAccountHandle(PhoneAccountHandle acc) { mAccountHandle = acc; }
+
/**
* The handle (e.g., phone number) to which the {@link Connection} is to connect.
*/
diff --git a/telecomm/java/android/telecom/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java
index 383e45b..1560af8 100644
--- a/telecomm/java/android/telecom/ConnectionService.java
+++ b/telecomm/java/android/telecom/ConnectionService.java
@@ -101,6 +101,9 @@ public abstract class ConnectionService extends Service {
private static final int MSG_ANSWER_VIDEO = 17;
private static final int MSG_MERGE_CONFERENCE = 18;
private static final int MSG_SWAP_CONFERENCE = 19;
+ private static final int MSG_SET_LOCAL_HOLD = 20;
+ //Proprietary values starts after this.
+ private static final int MSG_ADD_PARTICIPANT_WITH_CONFERENCE = 30;
private static Connection sNullConnection;
@@ -199,6 +202,14 @@ public abstract class ConnectionService extends Service {
}
@Override
+ public void setLocalCallHold(String callId, boolean lchState) {
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = callId;
+ args.argi1 = lchState ? 1 : 0;
+ mHandler.obtainMessage(MSG_SET_LOCAL_HOLD, args).sendToTarget();
+ }
+
+ @Override
public void conference(String callId1, String callId2) {
SomeArgs args = SomeArgs.obtain();
args.arg1 = callId1;
@@ -212,6 +223,14 @@ public abstract class ConnectionService extends Service {
}
@Override
+ public void addParticipantWithConference(String callId, String participant) {
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = callId;
+ args.arg2 = participant;
+ mHandler.obtainMessage(MSG_ADD_PARTICIPANT_WITH_CONFERENCE, args).sendToTarget();
+ }
+
+ @Override
public void mergeConference(String callId) {
mHandler.obtainMessage(MSG_MERGE_CONFERENCE, callId).sendToTarget();
}
@@ -322,6 +341,17 @@ public abstract class ConnectionService extends Service {
case MSG_STOP_DTMF_TONE:
stopDtmfTone((String) msg.obj);
break;
+ case MSG_SET_LOCAL_HOLD: {
+ SomeArgs args = (SomeArgs) msg.obj;
+ try {
+ String callId = (String) args.arg1;
+ boolean lchStatus = (args.argi1 == 1);
+ setLocalCallHold(callId, lchStatus);
+ } finally {
+ args.recycle();
+ }
+ break;
+ }
case MSG_CONFERENCE: {
SomeArgs args = (SomeArgs) msg.obj;
try {
@@ -336,6 +366,17 @@ public abstract class ConnectionService extends Service {
case MSG_SPLIT_FROM_CONFERENCE:
splitFromConference((String) msg.obj);
break;
+ case MSG_ADD_PARTICIPANT_WITH_CONFERENCE: {
+ SomeArgs args = (SomeArgs) msg.obj;
+ try {
+ String callId = (String) args.arg1;
+ String participant = (String) args.arg2;
+ addParticipantWithConference(callId, participant);
+ } finally {
+ args.recycle();
+ }
+ break;
+ }
case MSG_MERGE_CONFERENCE:
mergeConference((String) msg.obj);
break;
@@ -584,6 +625,12 @@ public abstract class ConnectionService extends Service {
mAdapter.setExtras(id, extras);
}
}
+
+ @Override
+ public void onCdmaConnectionTimeReset(Connection c) {
+ String id = mIdByConnection.get(c);
+ mAdapter.resetCdmaConnectionTime(id);
+ }
};
/** {@inheritDoc} */
@@ -737,6 +784,11 @@ public abstract class ConnectionService extends Service {
}
}
+ private void setLocalCallHold(String callId, boolean lchStatus) {
+ Log.d(this, "setLocalCallHold %s", callId);
+ findConnectionForAction(callId, "setLocalCallHold").setLocalCallHold(lchStatus);
+ }
+
private void conference(String callId1, String callId2) {
Log.d(this, "conference %s, %s", callId1, callId2);
@@ -799,6 +851,17 @@ public abstract class ConnectionService extends Service {
}
}
+ private void addParticipantWithConference(String callId, String participant) {
+ Log.d(this, "ConnectionService addParticipantWithConference(%s, %s)", participant, callId);
+ Conference conference = findConferenceForAction(callId, "addParticipantWithConference");
+ Connection connection = findConnectionForAction(callId, "addParticipantWithConnection");
+ if (connection != getNullConnection()) {
+ onAddParticipant(connection, participant);
+ } else if (conference != getNullConference()) {
+ conference.onAddParticipant(participant);
+ }
+ }
+
private void mergeConference(String callId) {
Log.d(this, "mergeConference(%s)", callId);
Conference conference = findConferenceForAction(callId, "mergeConference");
@@ -1085,6 +1148,19 @@ public abstract class ConnectionService extends Service {
public void onConference(Connection connection1, Connection connection2) {}
/**
+ * Add participant with connection. Invoked when user has made a request to add
+ * participant with specified connection. In response, the participant should add with
+ * the connection.
+ *
+ * @param connection A connection where participant need to add.
+ * @param participant Address of participant which will be added.
+ * @return
+ *
+ * @hide
+ */
+ public void onAddParticipant(Connection connection, String participant) {}
+
+ /**
* Indicates that a remote conference has been created for existing {@link RemoteConnection}s.
* When this method is invoked, this {@link ConnectionService} should create its own
* representation of the conference call and send it to telecom using {@link #addConference}.
diff --git a/telecomm/java/android/telecom/ConnectionServiceAdapter.java b/telecomm/java/android/telecom/ConnectionServiceAdapter.java
index 4562514..30bd373 100644
--- a/telecomm/java/android/telecom/ConnectionServiceAdapter.java
+++ b/telecomm/java/android/telecom/ConnectionServiceAdapter.java
@@ -230,6 +230,18 @@ final class ConnectionServiceAdapter implements DeathRecipient {
}
/**
+ * Resets the cdma connection time.
+ */
+ void resetCdmaConnectionTime(String callId) {
+ for (IConnectionServiceAdapter adapter : mAdapters) {
+ try {
+ adapter.resetCdmaConnectionTime(callId);
+ } catch (RemoteException e) {
+ }
+ }
+ }
+
+ /**
* Indicates that the call no longer exists. Can be used with either a call or a conference
* call.
*
diff --git a/telecomm/java/android/telecom/ConnectionServiceAdapterServant.java b/telecomm/java/android/telecom/ConnectionServiceAdapterServant.java
index 293dc11..b8e7c22 100644
--- a/telecomm/java/android/telecom/ConnectionServiceAdapterServant.java
+++ b/telecomm/java/android/telecom/ConnectionServiceAdapterServant.java
@@ -419,6 +419,10 @@ final class ConnectionServiceAdapterServant {
args.arg2 = extras;
mHandler.obtainMessage(MSG_SET_EXTRAS, args).sendToTarget();
}
+
+ @Override
+ public void resetCdmaConnectionTime(String callId) {
+ }
};
public ConnectionServiceAdapterServant(IConnectionServiceAdapter delegate) {
diff --git a/telecomm/java/android/telecom/InCallAdapter.java b/telecomm/java/android/telecom/InCallAdapter.java
index 0cf7212..7d0f5a7 100644
--- a/telecomm/java/android/telecom/InCallAdapter.java
+++ b/telecomm/java/android/telecom/InCallAdapter.java
@@ -273,4 +273,17 @@ public final class InCallAdapter {
} catch (RemoteException ignored) {
}
}
+
+ /**
+ * Instructs Telecomm to switch to other active subscripion
+ *
+ * @param subid switch to subscription denoted by subId
+ * {@hide}
+ */
+ public void switchToOtherActiveSub(String subId) {
+ try {
+ mAdapter.switchToOtherActiveSub(subId);
+ } catch (RemoteException e) {
+ }
+ }
}
diff --git a/telecomm/java/android/telecom/InCallService.java b/telecomm/java/android/telecom/InCallService.java
index 19c613d..1b6a98f 100644
--- a/telecomm/java/android/telecom/InCallService.java
+++ b/telecomm/java/android/telecom/InCallService.java
@@ -73,6 +73,7 @@ public abstract class InCallService extends Service {
private static final int MSG_ON_CALL_AUDIO_STATE_CHANGED = 5;
private static final int MSG_BRING_TO_FOREGROUND = 6;
private static final int MSG_ON_CAN_ADD_CALL_CHANGED = 7;
+ private static final int MSG_ON_MERGE_FAILED = 8;
/** Default Handler used to consolidate binder method calls onto a single thread. */
private final Handler mHandler = new Handler(Looper.getMainLooper()) {
@@ -91,6 +92,9 @@ public abstract class InCallService extends Service {
case MSG_ADD_CALL:
mPhone.internalAddCall((ParcelableCall) msg.obj);
break;
+ case MSG_ON_MERGE_FAILED:
+ mPhone.onMergeFailed((ParcelableCall) msg.obj);
+ break;
case MSG_UPDATE_CALL:
mPhone.internalUpdateCall((ParcelableCall) msg.obj);
break;
@@ -156,6 +160,11 @@ public abstract class InCallService extends Service {
}
@Override
+ public void onMergeFailed(ParcelableCall call) {
+ mHandler.obtainMessage(MSG_ON_MERGE_FAILED, call).sendToTarget();
+ }
+
+ @Override
public void bringToForeground(boolean showDialpad) {
mHandler.obtainMessage(MSG_BRING_TO_FOREGROUND, showDialpad ? 1 : 0, 0).sendToTarget();
}
@@ -301,6 +310,18 @@ public abstract class InCallService extends Service {
}
/**
+ * Instructs Telecomm to switch to other active subscripion
+ *
+ * @param subId switch to this subscription
+ * @hide
+ */
+ public void switchToOtherActiveSub(String subId) {
+ if (mPhone != null) {
+ mPhone.switchToOtherActiveSub(subId);
+ }
+ }
+
+ /**
* Sets the audio route (speaker, bluetooth, etc...). When this request is honored, there will
* be change to the {@link #getCallAudioState()}.
*
diff --git a/telecomm/java/android/telecom/ParcelableCall.java b/telecomm/java/android/telecom/ParcelableCall.java
index 8cf4aeb..5b343e6 100644
--- a/telecomm/java/android/telecom/ParcelableCall.java
+++ b/telecomm/java/android/telecom/ParcelableCall.java
@@ -39,6 +39,7 @@ public final class ParcelableCall implements Parcelable {
private final List<String> mCannedSmsResponses;
private final int mCapabilities;
private final int mProperties;
+ private final long mCreateTimeMillis;
private final long mConnectTimeMillis;
private final Uri mHandle;
private final int mHandlePresentation;
@@ -56,6 +57,7 @@ public final class ParcelableCall implements Parcelable {
private final List<String> mConferenceableCallIds;
private final Bundle mIntentExtras;
private final Bundle mExtras;
+ private final boolean mIsActiveSub;
public ParcelableCall(
String id,
@@ -64,6 +66,7 @@ public final class ParcelableCall implements Parcelable {
List<String> cannedSmsResponses,
int capabilities,
int properties,
+ long createTimeMillis,
long connectTimeMillis,
Uri handle,
int handlePresentation,
@@ -79,13 +82,15 @@ public final class ParcelableCall implements Parcelable {
int videoState,
List<String> conferenceableCallIds,
Bundle intentExtras,
- Bundle extras) {
+ Bundle extras,
+ boolean isActiveSub) {
mId = id;
mState = state;
mDisconnectCause = disconnectCause;
mCannedSmsResponses = cannedSmsResponses;
mCapabilities = capabilities;
mProperties = properties;
+ mCreateTimeMillis = createTimeMillis;
mConnectTimeMillis = connectTimeMillis;
mHandle = handle;
mHandlePresentation = handlePresentation;
@@ -102,6 +107,7 @@ public final class ParcelableCall implements Parcelable {
mConferenceableCallIds = Collections.unmodifiableList(conferenceableCallIds);
mIntentExtras = intentExtras;
mExtras = extras;
+ mIsActiveSub = isActiveSub;
}
/** The unique ID of the call. */
@@ -137,6 +143,11 @@ public final class ParcelableCall implements Parcelable {
/** Bitmask of properties of the call. */
public int getProperties() { return mProperties; }
+ /** The time that the call object was created */
+ public long getCreateTimeMillis() {
+ return mCreateTimeMillis;
+ }
+
/** The time that the call switched to the active state. */
public long getConnectTimeMillis() {
return mConnectTimeMillis;
@@ -259,6 +270,13 @@ public final class ParcelableCall implements Parcelable {
return mIsVideoCallProviderChanged;
}
+ /**
+ * return if this call object belongs to active subscription.
+ */
+ public boolean isActive() {
+ return mIsActiveSub;
+ }
+
/** Responsible for creating ParcelableCall objects for deserialized Parcels. */
public static final Parcelable.Creator<ParcelableCall> CREATOR =
new Parcelable.Creator<ParcelableCall> () {
@@ -272,6 +290,7 @@ public final class ParcelableCall implements Parcelable {
source.readList(cannedSmsResponses, classLoader);
int capabilities = source.readInt();
int properties = source.readInt();
+ long createTimeMillis = source.readLong();
long connectTimeMillis = source.readLong();
Uri handle = source.readParcelable(classLoader);
int handlePresentation = source.readInt();
@@ -291,6 +310,7 @@ public final class ParcelableCall implements Parcelable {
source.readList(conferenceableCallIds, classLoader);
Bundle intentExtras = source.readBundle(classLoader);
Bundle extras = source.readBundle(classLoader);
+ boolean isActiveSub = (source.readInt() == 1) ? true : false;
return new ParcelableCall(
id,
state,
@@ -298,6 +318,7 @@ public final class ParcelableCall implements Parcelable {
cannedSmsResponses,
capabilities,
properties,
+ createTimeMillis,
connectTimeMillis,
handle,
handlePresentation,
@@ -313,7 +334,8 @@ public final class ParcelableCall implements Parcelable {
videoState,
conferenceableCallIds,
intentExtras,
- extras);
+ extras,
+ isActiveSub);
}
@Override
@@ -337,6 +359,7 @@ public final class ParcelableCall implements Parcelable {
destination.writeList(mCannedSmsResponses);
destination.writeInt(mCapabilities);
destination.writeInt(mProperties);
+ destination.writeLong(mCreateTimeMillis);
destination.writeLong(mConnectTimeMillis);
destination.writeParcelable(mHandle, 0);
destination.writeInt(mHandlePresentation);
@@ -354,6 +377,7 @@ public final class ParcelableCall implements Parcelable {
destination.writeList(mConferenceableCallIds);
destination.writeBundle(mIntentExtras);
destination.writeBundle(mExtras);
+ destination.writeInt(mIsActiveSub ? 1 : 0);
}
@Override
diff --git a/telecomm/java/android/telecom/Phone.java b/telecomm/java/android/telecom/Phone.java
index 47154da..0fd124d 100644
--- a/telecomm/java/android/telecom/Phone.java
+++ b/telecomm/java/android/telecom/Phone.java
@@ -123,7 +123,7 @@ public final class Phone {
final void internalAddCall(ParcelableCall parcelableCall) {
Call call = new Call(this, parcelableCall.getId(), mInCallAdapter,
- parcelableCall.getState());
+ parcelableCall.getState(), parcelableCall.isActive());
mCallByTelecomCallId.put(parcelableCall.getId(), call);
mCalls.add(call);
checkCallTree(parcelableCall);
@@ -179,6 +179,12 @@ public final class Phone {
}
}
+ final void onMergeFailed(ParcelableCall parcelableCall) {
+ Call call = mCallByTelecomCallId.get(parcelableCall.getId());
+ if (call != null) {
+ call.onMergeFailed();
+ }
+ }
/**
* Called to destroy the phone and cleanup any lingering calls.
*/
@@ -280,6 +286,16 @@ public final class Phone {
}
/**
+ * Instructs Telecomm to switch to other active subscripion
+ *
+ * @param subId switch to this subscription
+ * {@hide}
+ */
+ public void switchToOtherActiveSub(String subId) {
+ mInCallAdapter.switchToOtherActiveSub(subId);
+ }
+
+ /**
* Obtains the current phone call audio state of the {@code Phone}.
*
* @return An object encapsulating the audio state.
diff --git a/telecomm/java/android/telecom/PhoneAccount.java b/telecomm/java/android/telecom/PhoneAccount.java
index cdb0bf2..f890f4d 100644
--- a/telecomm/java/android/telecom/PhoneAccount.java
+++ b/telecomm/java/android/telecom/PhoneAccount.java
@@ -34,6 +34,7 @@ import android.text.TextUtils;
import java.lang.String;
import java.util.ArrayList;
+import java.util.BitSet;
import java.util.Collections;
import java.util.List;
import java.util.MissingResourceException;
@@ -366,6 +367,43 @@ public final class PhoneAccount implements Parcelable {
}
/**
+ * Contains information related to
+ * LCH and ACTIVE.
+ */
+ private BitSet callsStatus = new BitSet();
+
+ /**
+ * {@hide}
+ */
+ public static final int LCH = 1;
+
+ /**
+ * {@hide}
+ */
+ public static final int ACTIVE = 2;
+
+ /**
+ * {@hide}
+ */
+ public void setBit(int bit) {
+ callsStatus.set(bit);
+ }
+
+ /**
+ * {@hide}
+ */
+ public void unSetBit(int bit) {
+ callsStatus.set(bit, false);
+ }
+
+ /**
+ * {@hide}
+ */
+ public boolean isSet(int bit) {
+ return callsStatus.get(bit);
+ }
+
+ /**
* Returns a builder initialized with the current {@link PhoneAccount} instance.
*
* @return The builder.
diff --git a/telecomm/java/android/telecom/RemoteConnectionService.java b/telecomm/java/android/telecom/RemoteConnectionService.java
index dc0de0c..372d736 100644
--- a/telecomm/java/android/telecom/RemoteConnectionService.java
+++ b/telecomm/java/android/telecom/RemoteConnectionService.java
@@ -330,6 +330,10 @@ final class RemoteConnectionService {
.setExtras(extras);
}
}
+
+ @Override
+ public void resetCdmaConnectionTime(String callId) {
+ }
};
private final ConnectionServiceAdapterServant mServant =
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index 067e734..673adb2 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -22,6 +22,7 @@ import android.net.Uri;
import android.os.Bundle;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.Log;
@@ -1039,6 +1040,37 @@ public class TelecomManager {
}
/**
+ * Returns current active subscription.
+ * Active subscription is the one from which calls are displayed to user when there are actve
+ * calls on both subscriptions.
+ * @hide
+ */
+ public int getActiveSubscription() {
+ try {
+ if (isServiceConnected()) {
+ return getTelecomService().getActiveSubscription();
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException attempting to get the active subsription.", e);
+ }
+ return SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+ }
+
+ /**
+ * switches to other active subscription.
+ * @hide
+ */
+ public void switchToOtherActiveSub(int subId) {
+ try {
+ if (isServiceConnected()) {
+ getTelecomService().switchToOtherActiveSub(subId);
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException attempting to switchToOtherActiveSub.", e);
+ }
+ }
+
+ /**
* Registers a new incoming call. A {@link ConnectionService} should invoke this method when it
* has an incoming call. The specified {@link PhoneAccountHandle} must have been registered
* with {@link #registerPhoneAccount}. Once invoked, this method will cause the system to bind
diff --git a/telecomm/java/android/telecom/VideoCallImpl.java b/telecomm/java/android/telecom/VideoCallImpl.java
index c8072d1..93484cd 100644
--- a/telecomm/java/android/telecom/VideoCallImpl.java
+++ b/telecomm/java/android/telecom/VideoCallImpl.java
@@ -57,13 +57,20 @@ public class VideoCallImpl extends VideoCall {
private final class VideoCallListenerBinder extends IVideoCallback.Stub {
@Override
public void receiveSessionModifyRequest(VideoProfile videoProfile) {
+ if (mHandler == null) {
+ return;
+ }
mHandler.obtainMessage(MessageHandler.MSG_RECEIVE_SESSION_MODIFY_REQUEST,
videoProfile).sendToTarget();
+
}
@Override
public void receiveSessionModifyResponse(int status, VideoProfile requestProfile,
VideoProfile responseProfile) {
+ if (mHandler == null) {
+ return;
+ }
SomeArgs args = SomeArgs.obtain();
args.arg1 = status;
args.arg2 = requestProfile;
@@ -74,12 +81,18 @@ public class VideoCallImpl extends VideoCall {
@Override
public void handleCallSessionEvent(int event) {
+ if (mHandler == null) {
+ return;
+ }
mHandler.obtainMessage(MessageHandler.MSG_HANDLE_CALL_SESSION_EVENT, event)
.sendToTarget();
}
@Override
public void changePeerDimensions(int width, int height) {
+ if (mHandler == null) {
+ return;
+ }
SomeArgs args = SomeArgs.obtain();
args.arg1 = width;
args.arg2 = height;
@@ -88,18 +101,27 @@ public class VideoCallImpl extends VideoCall {
@Override
public void changeVideoQuality(int videoQuality) {
+ if (mHandler == null) {
+ return;
+ }
mHandler.obtainMessage(MessageHandler.MSG_CHANGE_VIDEO_QUALITY, videoQuality, 0)
.sendToTarget();
}
@Override
public void changeCallDataUsage(long dataUsage) {
+ if (mHandler == null) {
+ return;
+ }
mHandler.obtainMessage(MessageHandler.MSG_CHANGE_CALL_DATA_USAGE, dataUsage)
.sendToTarget();
}
@Override
public void changeCameraCapabilities(VideoProfile.CameraCapabilities cameraCapabilities) {
+ if (mHandler == null) {
+ return;
+ }
mHandler.obtainMessage(MessageHandler.MSG_CHANGE_CAMERA_CAPABILITIES,
cameraCapabilities).sendToTarget();
}
diff --git a/telecomm/java/com/android/internal/telecom/IConnectionService.aidl b/telecomm/java/com/android/internal/telecom/IConnectionService.aidl
index c2e8530..23d70d5 100644
--- a/telecomm/java/com/android/internal/telecom/IConnectionService.aidl
+++ b/telecomm/java/com/android/internal/telecom/IConnectionService.aidl
@@ -71,4 +71,8 @@ oneway interface IConnectionService {
void swapConference(String conferenceCallId);
void onPostDialContinue(String callId, boolean proceed);
+
+ void setLocalCallHold(String callId, boolean lchState);
+
+ void addParticipantWithConference(String callId, String recipients);
}
diff --git a/telecomm/java/com/android/internal/telecom/IConnectionServiceAdapter.aidl b/telecomm/java/com/android/internal/telecom/IConnectionServiceAdapter.aidl
index 7647444..ef4915c 100644
--- a/telecomm/java/com/android/internal/telecom/IConnectionServiceAdapter.aidl
+++ b/telecomm/java/com/android/internal/telecom/IConnectionServiceAdapter.aidl
@@ -86,4 +86,6 @@ oneway interface IConnectionServiceAdapter {
void addExistingConnection(String callId, in ParcelableConnection connection);
void setExtras(String callId, in Bundle extras);
+
+ void resetCdmaConnectionTime(String callId);
}
diff --git a/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl b/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl
index 863fff2..ee51efa 100644
--- a/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl
+++ b/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl
@@ -60,4 +60,6 @@ oneway interface IInCallAdapter {
void turnOnProximitySensor();
void turnOffProximitySensor(boolean screenOnImmediately);
+
+ void switchToOtherActiveSub(String subId);
}
diff --git a/telecomm/java/com/android/internal/telecom/IInCallService.aidl b/telecomm/java/com/android/internal/telecom/IInCallService.aidl
index ded47d5..f4ba9a0 100644
--- a/telecomm/java/com/android/internal/telecom/IInCallService.aidl
+++ b/telecomm/java/com/android/internal/telecom/IInCallService.aidl
@@ -45,4 +45,6 @@ oneway interface IInCallService {
void bringToForeground(boolean showDialpad);
void onCanAddCallChanged(boolean canAddCall);
+
+ void onMergeFailed(in ParcelableCall call);
}
diff --git a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
index 2e07759..cad8c5d 100644
--- a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
+++ b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
@@ -232,4 +232,14 @@ interface ITelecomService {
* @see TelecomServiceImpl#setDefaultDialer
*/
boolean setDefaultDialer(in String packageName);
+
+ /**
+ * @see TelecommManager#getActiveSubscription
+ */
+ int getActiveSubscription();
+
+ /**
+ * @see TelecommManager#switchToOtherActiveSub
+ */
+ void switchToOtherActiveSub(int subId);
}
diff --git a/telephony/java/android/telephony/DisconnectCause.java b/telephony/java/android/telephony/DisconnectCause.java
index 8443490..cb68b6b 100644
--- a/telephony/java/android/telephony/DisconnectCause.java
+++ b/telephony/java/android/telephony/DisconnectCause.java
@@ -187,6 +187,66 @@ public class DisconnectCause {
*/
public static final int CDMA_ALREADY_ACTIVATED = 49;
+ /** call failed due to LTE to 3G/2G handover not feasible */
+ public static final int HO_NOT_FEASIBLE = 50;
+
+ public static final int NO_CIRCUIT_AVAIL = 51;
+ public static final int NO_ROUTE_TO_DESTINAON = 52;
+ public static final int OPERATOR_DETERMINED_BARRING = 53;
+ public static final int CALL_FAIL_NO_USER_RESPONDING = 54;
+ public static final int CALL_FAIL_NO_ANSWER_FROM_USER = 55;
+ public static final int CALL_FAIL_DESTINATION_OUT_OF_ORDER = 56;
+ public static final int BEARER_CAPABILITY_NOT_AUTHORIZED = 57;
+ public static final int CHANNEL_UNACCEPTABLE = 58;
+ public static final int CALL_REJECTED = 59;
+ public static final int NUMBER_CHANGED = 60;
+ public static final int PREEMPTION = 61;
+ public static final int FACILITY_REJECTED = 62;
+ public static final int RESP_TO_STATUS_ENQUIRY = 63;
+ public static final int NORMAL_UNSPECIFIED = 64;
+ public static final int NETWORK_OUT_OF_ORDER = 65;
+ public static final int TEMPORARY_FAILURE = 66;
+ public static final int SWITCHING_EQUIPMENT_CONGESTION = 67;
+ public static final int ACCESS_INFORMATION_DISCARDED = 68;
+ public static final int REQUESTED_CIRCUIT_OR_CHANNEL_NOT_AVAILABLE = 69;
+ public static final int RESOURCES_UNAVAILABLE_OR_UNSPECIFIED = 70;
+ public static final int QOS_UNAVAILABLE = 71;
+ public static final int REQUESTED_FACILITY_NOT_SUBSCRIBED = 72;
+ public static final int INCOMING_CALLS_BARRED_WITHIN_CUG = 73;
+ public static final int BEARER_CAPABILITY_UNAVAILABLE = 74;
+ public static final int SERVICE_OPTION_NOT_AVAILABLE = 75;
+ public static final int BEARER_SERVICE_NOT_IMPLEMENTED = 76;
+ public static final int REQUESTED_FACILITY_NOT_IMPLEMENTED = 77;
+ public static final int ONLY_DIGITAL_INFORMATION_BEARER_AVAILABLE = 78;
+ public static final int SERVICE_OR_OPTION_NOT_IMPLEMENTED = 79;
+ public static final int INVALID_TRANSACTION_IDENTIFIER = 80;
+ public static final int USER_NOT_MEMBER_OF_CUG = 81;
+ public static final int INCOMPATIBLE_DESTINATION = 82;
+ public static final int INVALID_TRANSIT_NW_SELECTION = 83;
+ public static final int SEMANTICALLY_INCORRECT_MESSAGE = 84;
+ public static final int INVALID_MANDATORY_INFORMATION = 85;
+ public static final int MESSAGE_TYPE_NON_IMPLEMENTED = 86;
+ public static final int MESSAGE_TYPE_NOT_COMPATIBLE_WITH_PROTOCOL_STATE = 87;
+ public static final int INFORMATION_ELEMENT_NON_EXISTENT = 88;
+ public static final int CONDITIONAL_IE_ERROR = 89;
+ public static final int MESSAGE_NOT_COMPATIBLE_WITH_PROTOCOL_STATE = 90;
+ public static final int RECOVERY_ON_TIMER_EXPIRED = 91;
+ public static final int PROTOCOL_ERROR_UNSPECIFIED = 92;
+ public static final int INTERWORKING_UNSPECIFIED = 93;
+ public static final int LOCAL_LOW_BATTERY = 94;
+ public static final int LOW_BATTERY = 95;
+
+ /** EMERGENCY call failed with temporary fail cause */
+ public static final int EMERGENCY_TEMP_FAILURE = 96;
+ /** EMERGENCY call failed with permanent fail cause */
+ public static final int EMERGENCY_PERM_FAILURE = 97;
+
+ /**
+ * Call was rejected due to number being blacklisted by user.
+ * {@@hide}
+ */
+ public static final int CALL_BLACKLISTED = 400;
+
//*********************************************************************************************
// When adding a disconnect type:
// 1) Please assign the new type the next id value below.
@@ -195,14 +255,14 @@ public class DisconnectCause {
// 4) Update toString() with the newly added disconnect type.
// 5) Update android.telecom.DisconnectCauseUtil with any mappings to a telecom.DisconnectCause.
//
- // NextId: 50
+ // NextId: 98
//*********************************************************************************************
/** Smallest valid value for call disconnect codes. */
public static final int MINIMUM_VALID_VALUE = NOT_DISCONNECTED;
/** Largest valid value for call disconnect codes. */
- public static final int MAXIMUM_VALID_VALUE = CDMA_ALREADY_ACTIVATED;
+ public static final int MAXIMUM_VALID_VALUE = CALL_BLACKLISTED;
/** Private constructor to avoid class instantiation. */
private DisconnectCause() {
@@ -310,6 +370,104 @@ public class DisconnectCause {
return "IMS_MERGED_SUCCESSFULLY";
case CDMA_ALREADY_ACTIVATED:
return "CDMA_ALREADY_ACTIVATED";
+ case HO_NOT_FEASIBLE:
+ return "HO_NOT_FEASIBLE";
+ case NO_CIRCUIT_AVAIL:
+ return "NO_CIRCUIT_AVAIL";
+ case NO_ROUTE_TO_DESTINAON:
+ return "NO_ROUTE_TO_DESTINAON";
+ case OPERATOR_DETERMINED_BARRING:
+ return "OPERATOR_DETERMINED_BARRING";
+ case CALL_FAIL_NO_USER_RESPONDING:
+ return "CALL_FAIL_NO_USER_RESPONDING";
+ case CALL_FAIL_NO_ANSWER_FROM_USER:
+ return "CALL_FAIL_NO_ANSWER_FROM_USER";
+ case CALL_FAIL_DESTINATION_OUT_OF_ORDER:
+ return "CALL_FAIL_DESTINATION_OUT_OF_ORDER";
+ case BEARER_CAPABILITY_NOT_AUTHORIZED:
+ return "BEARER_CAPABILITY_NOT_AUTHORIZED";
+ case CHANNEL_UNACCEPTABLE:
+ return "CHANNEL_UNACCEPTABLE";
+ case CALL_REJECTED:
+ return "CALL_REJECTED";
+ case NUMBER_CHANGED:
+ return "NUMBER_CHANGED";
+ case PREEMPTION:
+ return "PREEMPTION";
+ case FACILITY_REJECTED:
+ return "FACILITY_REJECTED";
+ case RESP_TO_STATUS_ENQUIRY:
+ return "RESP_TO_STATUS_ENQUIRY";
+ case NORMAL_UNSPECIFIED:
+ return "NORMAL_UNSPECIFIED";
+ case NETWORK_OUT_OF_ORDER:
+ return "NETWORK_OUT_OF_ORDER";
+ case TEMPORARY_FAILURE:
+ return "TEMPORARY_FAILURE";
+ case SWITCHING_EQUIPMENT_CONGESTION:
+ return "SWITCHING_EQUIPMENT_CONGESTION";
+ case ACCESS_INFORMATION_DISCARDED:
+ return "ACCESS_INFORMATION_DISCARDED";
+ case REQUESTED_CIRCUIT_OR_CHANNEL_NOT_AVAILABLE:
+ return "REQUESTED_CIRCUIT_OR_CHANNEL_NOT_AVAILABLE";
+ case RESOURCES_UNAVAILABLE_OR_UNSPECIFIED:
+ return "RESOURCES_UNAVAILABLE_OR_UNSPECIFIED";
+ case QOS_UNAVAILABLE:
+ return "QOS_UNAVAILABLE";
+ case REQUESTED_FACILITY_NOT_SUBSCRIBED:
+ return "REQUESTED_FACILITY_NOT_SUBSCRIBED";
+ case INCOMING_CALLS_BARRED_WITHIN_CUG:
+ return "INCOMING_CALLS_BARRED_WITHIN_CUG";
+ case BEARER_CAPABILITY_UNAVAILABLE:
+ return "BEARER_CAPABILITY_UNAVAILABLE";
+ case SERVICE_OPTION_NOT_AVAILABLE:
+ return "SERVICE_OPTION_NOT_AVAILABLE";
+ case BEARER_SERVICE_NOT_IMPLEMENTED:
+ return "BEARER_SERVICE_NOT_IMPLEMENTED";
+ case REQUESTED_FACILITY_NOT_IMPLEMENTED:
+ return "REQUESTED_FACILITY_NOT_IMPLEMENTED";
+ case ONLY_DIGITAL_INFORMATION_BEARER_AVAILABLE:
+ return "ONLY_DIGITAL_INFORMATION_BEARER_AVAILABLE";
+ case SERVICE_OR_OPTION_NOT_IMPLEMENTED:
+ return "SERVICE_OR_OPTION_NOT_IMPLEMENTED";
+ case INVALID_TRANSACTION_IDENTIFIER:
+ return "INVALID_TRANSACTION_IDENTIFIER";
+ case USER_NOT_MEMBER_OF_CUG:
+ return "USER_NOT_MEMBER_OF_CUG";
+ case INCOMPATIBLE_DESTINATION:
+ return "INCOMPATIBLE_DESTINATION";
+ case INVALID_TRANSIT_NW_SELECTION:
+ return "INVALID_TRANSIT_NW_SELECTION";
+ case SEMANTICALLY_INCORRECT_MESSAGE:
+ return "SEMANTICALLY_INCORRECT_MESSAGE";
+ case INVALID_MANDATORY_INFORMATION:
+ return "INVALID_MANDATORY_INFORMATION";
+ case MESSAGE_TYPE_NON_IMPLEMENTED:
+ return "MESSAGE_TYPE_NON_IMPLEMENTED";
+ case MESSAGE_TYPE_NOT_COMPATIBLE_WITH_PROTOCOL_STATE:
+ return "MESSAGE_TYPE_NOT_COMPATIBLE_WITH_PROTOCOL_STATE";
+ case INFORMATION_ELEMENT_NON_EXISTENT:
+ return "INFORMATION_ELEMENT_NON_EXISTENT";
+ case CONDITIONAL_IE_ERROR:
+ return "CONDITIONAL_IE_ERROR";
+ case MESSAGE_NOT_COMPATIBLE_WITH_PROTOCOL_STATE:
+ return "MESSAGE_NOT_COMPATIBLE_WITH_PROTOCOL_STATE";
+ case RECOVERY_ON_TIMER_EXPIRED:
+ return "RECOVERY_ON_TIMER_EXPIRED";
+ case PROTOCOL_ERROR_UNSPECIFIED:
+ return "PROTOCOL_ERROR_UNSPECIFIED";
+ case INTERWORKING_UNSPECIFIED:
+ return "INTERWORKING_UNSPECIFIED";
+ case LOCAL_LOW_BATTERY:
+ return "LOCAL_LOW_BATTERY";
+ case LOW_BATTERY:
+ return "LOW_BATTERY";
+ case EMERGENCY_TEMP_FAILURE:
+ return "EMERGENCY_TEMP_FAILURE";
+ case EMERGENCY_PERM_FAILURE:
+ return "EMERGENCY_PERM_FAILURE";
+ case CALL_BLACKLISTED:
+ return "CALL_BLACKLISTED";
default:
return "INVALID: " + cause;
}
diff --git a/telephony/java/android/telephony/PhoneNumberUtils.java b/telephony/java/android/telephony/PhoneNumberUtils.java
index b430340..5ee1fb2 100644
--- a/telephony/java/android/telephony/PhoneNumberUtils.java
+++ b/telephony/java/android/telephony/PhoneNumberUtils.java
@@ -16,6 +16,7 @@
package android.telephony;
+import android.util.SparseArray;
import com.android.i18n.phonenumbers.NumberParseException;
import com.android.i18n.phonenumbers.PhoneNumberUtil;
import com.android.i18n.phonenumbers.PhoneNumberUtil.PhoneNumberFormat;
@@ -25,6 +26,7 @@ import com.android.i18n.phonenumbers.ShortNumberUtil;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
+import android.location.Country;
import android.location.CountryDetector;
import android.net.Uri;
import android.os.SystemProperties;
@@ -77,6 +79,7 @@ public class PhoneNumberUtils
static final String LOG_TAG = "PhoneNumberUtils";
private static final boolean DBG = false;
+ private static Country sCountryDetector = null;
/*
* global-phone-number = ["+"] 1*( DIGIT / written-sep )
* written-sep = ("-"/".")
@@ -139,6 +142,55 @@ public class PhoneNumberUtils
return !isDialable(ch) && !(('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z'));
}
+ /**
+ * On some CDMA networks +COUNTRYCODE must be rewritten to 0 when making a local
+ * call from within the user's home network. We maintain a white list of
+ * (country code prefix) -> (rewrite rule) to perform this substitution.
+ *
+ * Since country codes are variable length it is easiest to compile a regex
+ */
+ private static SparseArray<RewriteRule> sCdmaLocalRewriteWhitelist;
+ private static Pattern sCdmaLocalRewritePattern;
+ static {
+ sCdmaLocalRewriteWhitelist = new SparseArray<RewriteRule>();
+ addRewriteRule(62, "ID", "0"); // indonesia
+ addRewriteRule(380, "UA", "0"); // ukraine
+
+ StringBuffer regex = new StringBuffer();
+ regex.append("[+](");
+ for (int i=0; i < sCdmaLocalRewriteWhitelist.size(); ++i) {
+ int countryCode = sCdmaLocalRewriteWhitelist.keyAt(i);
+ if (i > 0) {
+ regex.append("|");
+ }
+ regex.append(countryCode);
+ }
+ regex.append(")");
+ sCdmaLocalRewritePattern = Pattern.compile(regex.toString());
+ }
+
+ private static class RewriteRule {
+ public int countryCodePrefix;
+ public String isoCountryCode;
+ public String replacement;
+
+ public RewriteRule(int countryCodePrefix, String isoCountryCode, String replacement) {
+ this.countryCodePrefix = countryCodePrefix;
+ this.isoCountryCode = isoCountryCode;
+ this.replacement = replacement;
+ }
+
+ public String apply(String dialStr) {
+ return dialStr.replaceFirst("[+]" + countryCodePrefix, replacement);
+ }
+ }
+
+ private static void addRewriteRule(int countryCodePrefix,
+ String isoCountryCode, String replacement) {
+ sCdmaLocalRewriteWhitelist.put(countryCodePrefix,
+ new RewriteRule(countryCodePrefix, isoCountryCode, replacement));
+ }
+
/** Extracts the phone number from an Intent.
*
* @param intent the intent to get the number of
@@ -2057,12 +2109,9 @@ public class PhoneNumberUtils
private static boolean isLocalEmergencyNumberInternal(int subId, String number,
Context context,
boolean useExactMatch) {
- String countryIso;
- CountryDetector detector = (CountryDetector) context.getSystemService(
- Context.COUNTRY_DETECTOR);
- if (detector != null && detector.detectCountry() != null) {
- countryIso = detector.detectCountry().getCountryIso();
- } else {
+ String countryIso = getCountryIso(context);
+ Rlog.w(LOG_TAG, "isLocalEmergencyNumberInternal" + countryIso);
+ if (countryIso == null) {
Locale locale = context.getResources().getConfiguration().locale;
countryIso = locale.getCountry();
Rlog.w(LOG_TAG, "No CountryDetector; falling back to countryIso based on locale: "
@@ -2071,6 +2120,28 @@ public class PhoneNumberUtils
return isEmergencyNumberInternal(subId, number, countryIso, useExactMatch);
}
+ private static String getCountryIso(Context context) {
+ Rlog.w(LOG_TAG, "getCountryIso " + sCountryDetector);
+ if (sCountryDetector == null) {
+ CountryDetector detector = (CountryDetector) context.getSystemService(
+ Context.COUNTRY_DETECTOR);
+ if (detector != null) {
+ sCountryDetector = detector.detectCountry();
+ }
+ }
+
+ if (sCountryDetector == null) {
+ return null;
+ } else {
+ return sCountryDetector.getCountryIso();
+ }
+ }
+
+ /** @hide */
+ public static void resetCountryDetectorInfo() {
+ sCountryDetector = null;
+ }
+
/**
* isVoiceMailNumber: checks a given number against the voicemail
* number provided by the RIL and SIM card. The caller must have
@@ -2560,6 +2631,29 @@ public class PhoneNumberUtils
}
/**
+ * Returns a rewrite rule for the country code prefix if the dial string matches the
+ * whitelist and the user is in their home network
+ *
+ * @param dialStr number being dialed
+ * @param currIso ISO code of currently attached network
+ * @param defaultIso ISO code of user's sim
+ * @return RewriteRule or null if conditions fail
+ */
+ private static RewriteRule getCdmaLocalRewriteRule(String dialStr,
+ String currIso, String defaultIso) {
+ Matcher m = sCdmaLocalRewritePattern.matcher(dialStr);
+ if (m.find()) {
+ String dialPrefix = m.group(1);
+ RewriteRule rule = sCdmaLocalRewriteWhitelist.get(Integer.valueOf(dialPrefix));
+ if (currIso.equalsIgnoreCase(defaultIso) &&
+ currIso.equalsIgnoreCase(rule.isoCountryCode)) {
+ return rule;
+ }
+ }
+ return null;
+ }
+
+ /**
* Determines if the specified number is actually a URI
* (i.e. a SIP address) rather than a regular PSTN phone number,
* based on whether or not the number contains an "@" character.
@@ -2622,8 +2716,16 @@ public class PhoneNumberUtils
// Remove the leading plus sign
retStr = newStr;
} else {
- // Replaces the plus sign with the default IDP
- retStr = networkDialStr.replaceFirst("[+]", getCurrentIdp(useNanp));
+ RewriteRule rewriteRule =
+ getCdmaLocalRewriteRule(networkDialStr,
+ TelephonyManager.getDefault().getNetworkCountryIso(),
+ TelephonyManager.getDefault().getSimCountryIso());
+ if (rewriteRule != null) {
+ retStr = rewriteRule.apply(networkDialStr);
+ } else {
+ // Replaces the plus sign with the default IDP
+ retStr = networkDialStr.replaceFirst("[+]", getCurrentIdp(useNanp));
+ }
}
}
if (DBG) log("processPlusCode, retStr=" + retStr);
diff --git a/telephony/java/android/telephony/RadioAccessFamily.java b/telephony/java/android/telephony/RadioAccessFamily.java
index 2bfaf1b..2906a2d 100644..100755
--- a/telephony/java/android/telephony/RadioAccessFamily.java
+++ b/telephony/java/android/telephony/RadioAccessFamily.java
@@ -47,6 +47,7 @@ public class RadioAccessFamily implements Parcelable {
public static final int RAF_HSPAP = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_HSPAP);
public static final int RAF_GSM = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_GSM);
public static final int RAF_TD_SCDMA = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_TD_SCDMA);
+ public static final int RAF_LTE_CA = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_LTE_CA);
// Grouping of RAFs
private static final int GSM = RAF_GSM | RAF_GPRS | RAF_EDGE;
@@ -54,6 +55,7 @@ public class RadioAccessFamily implements Parcelable {
private static final int CDMA = RAF_IS95A | RAF_IS95B | RAF_1xRTT;
private static final int EVDO = RAF_EVDO_0 | RAF_EVDO_A | RAF_EVDO_B | RAF_EHRPD;
private static final int WCDMA = HS | RAF_UMTS;
+ private static final int LTE = RAF_LTE | RAF_LTE_CA;
/* Phone ID of phone */
private int mPhoneId;
@@ -162,19 +164,19 @@ public class RadioAccessFamily implements Parcelable {
raf = CDMA | EVDO;
break;
case RILConstants.NETWORK_MODE_LTE_CDMA_EVDO:
- raf = RAF_LTE | CDMA | EVDO;
+ raf = LTE | CDMA | EVDO;
break;
case RILConstants.NETWORK_MODE_LTE_GSM_WCDMA:
- raf = RAF_LTE | GSM | WCDMA;
+ raf = LTE | GSM | WCDMA;
break;
case RILConstants.NETWORK_MODE_LTE_CDMA_EVDO_GSM_WCDMA:
- raf = RAF_LTE | CDMA | EVDO | GSM | WCDMA;
+ raf = LTE | CDMA | EVDO | GSM | WCDMA;
break;
case RILConstants.NETWORK_MODE_LTE_ONLY:
- raf = RAF_LTE;
+ raf = LTE;
break;
case RILConstants.NETWORK_MODE_LTE_WCDMA:
- raf = RAF_LTE | WCDMA;
+ raf = LTE | WCDMA;
break;
case RILConstants.NETWORK_MODE_CDMA_NO_EVDO:
raf = CDMA;
@@ -232,6 +234,7 @@ public class RadioAccessFamily implements Parcelable {
raf = ((WCDMA & raf) > 0) ? (WCDMA | raf) : raf;
raf = ((CDMA & raf) > 0) ? (CDMA | raf) : raf;
raf = ((EVDO & raf) > 0) ? (EVDO | raf) : raf;
+ raf = ((LTE & raf) > 0) ? (LTE | raf) : raf;
return raf;
}
@@ -254,19 +257,19 @@ public class RadioAccessFamily implements Parcelable {
case (CDMA | EVDO):
type = RILConstants.NETWORK_MODE_CDMA;
break;
- case (RAF_LTE | CDMA | EVDO):
+ case (LTE | CDMA | EVDO):
type = RILConstants.NETWORK_MODE_LTE_CDMA_EVDO;
break;
- case (RAF_LTE | GSM | WCDMA):
+ case (LTE | GSM | WCDMA):
type = RILConstants.NETWORK_MODE_LTE_GSM_WCDMA;
break;
- case (RAF_LTE | CDMA | EVDO | GSM | WCDMA):
+ case (LTE | CDMA | EVDO | GSM | WCDMA):
type = RILConstants.NETWORK_MODE_LTE_CDMA_EVDO_GSM_WCDMA;
break;
- case RAF_LTE:
+ case LTE:
type = RILConstants.NETWORK_MODE_LTE_ONLY;
break;
- case (RAF_LTE | WCDMA):
+ case (LTE | WCDMA):
type = RILConstants.NETWORK_MODE_LTE_WCDMA;
break;
case CDMA:
@@ -339,6 +342,7 @@ public class RadioAccessFamily implements Parcelable {
case "CDMA": return CDMA;
case "EVDO": return EVDO;
case "WCDMA": return WCDMA;
+ case "LTE_CA": return RAF_LTE_CA;
default: return RAF_UNKNOWN;
}
}
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index 1337487..d411376 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -154,6 +154,12 @@ public class ServiceState implements Parcelable {
*/
public static final int RIL_RADIO_TECHNOLOGY_IWLAN = 18;
/**
+ * LTE_CA
+ * @hide
+ */
+ public static final int RIL_RADIO_TECHNOLOGY_LTE_CA = 19;
+
+ /**
* Available registration states for GSM, UMTS and CDMA.
*/
/** @hide */
@@ -728,11 +734,14 @@ public class ServiceState implements Parcelable {
case RIL_RADIO_TECHNOLOGY_GSM:
rtString = "GSM";
break;
+ case RIL_RADIO_TECHNOLOGY_TD_SCDMA:
+ rtString = "TD-SCDMA";
+ break;
case RIL_RADIO_TECHNOLOGY_IWLAN:
rtString = "IWLAN";
break;
- case RIL_RADIO_TECHNOLOGY_TD_SCDMA:
- rtString = "TD-SCDMA";
+ case RIL_RADIO_TECHNOLOGY_LTE_CA:
+ rtString = "LTE_CA";
break;
default:
rtString = "Unexpected";
@@ -1075,6 +1084,8 @@ public class ServiceState implements Parcelable {
return TelephonyManager.NETWORK_TYPE_TD_SCDMA;
case ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN:
return TelephonyManager.NETWORK_TYPE_IWLAN;
+ case ServiceState.RIL_RADIO_TECHNOLOGY_LTE_CA:
+ return TelephonyManager.NETWORK_TYPE_LTE_CA;
default:
return TelephonyManager.NETWORK_TYPE_UNKNOWN;
}
@@ -1126,7 +1137,9 @@ public class ServiceState implements Parcelable {
|| radioTechnology == RIL_RADIO_TECHNOLOGY_HSPAP
|| radioTechnology == RIL_RADIO_TECHNOLOGY_GSM
|| radioTechnology == RIL_RADIO_TECHNOLOGY_TD_SCDMA
- || radioTechnology == RIL_RADIO_TECHNOLOGY_IWLAN;
+ || radioTechnology == RIL_RADIO_TECHNOLOGY_IWLAN
+ || radioTechnology == RIL_RADIO_TECHNOLOGY_LTE_CA;
+
}
/** @hide */
diff --git a/telephony/java/android/telephony/SignalStrength.java b/telephony/java/android/telephony/SignalStrength.java
index fced667..997b6ff 100644
--- a/telephony/java/android/telephony/SignalStrength.java
+++ b/telephony/java/android/telephony/SignalStrength.java
@@ -19,6 +19,7 @@ package android.telephony;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
+import android.os.SystemProperties;
import android.telephony.Rlog;
import android.content.res.Resources;
@@ -52,6 +53,7 @@ public class SignalStrength implements Parcelable {
public static final int INVALID = 0x7FFFFFFF;
private static final int RSRP_THRESH_TYPE_STRICT = 0;
+ private static final int RSRP_THRESH_TYPE_CUSTOM = 2;
private static final int[] RSRP_THRESH_STRICT = new int[] {-140, -115, -105, -95, -85, -44};
private static final int[] RSRP_THRESH_LENIENT = new int[] {-140, -128, -118, -108, -98, -44};
@@ -146,11 +148,10 @@ public class SignalStrength implements Parcelable {
int cdmaDbm, int cdmaEcio,
int evdoDbm, int evdoEcio, int evdoSnr,
int lteSignalStrength, int lteRsrp, int lteRsrq, int lteRssnr, int lteCqi,
- int tdScdmaRscp, boolean gsmFlag) {
+ boolean gsmFlag) {
initialize(gsmSignalStrength, gsmBitErrorRate, cdmaDbm, cdmaEcio,
evdoDbm, evdoEcio, evdoSnr, lteSignalStrength, lteRsrp,
lteRsrq, lteRssnr, lteCqi, gsmFlag);
- mTdScdmaRscp = tdScdmaRscp;
}
/**
@@ -162,10 +163,11 @@ public class SignalStrength implements Parcelable {
int cdmaDbm, int cdmaEcio,
int evdoDbm, int evdoEcio, int evdoSnr,
int lteSignalStrength, int lteRsrp, int lteRsrq, int lteRssnr, int lteCqi,
- boolean gsmFlag) {
+ int tdScdmaRscp, boolean gsmFlag) {
initialize(gsmSignalStrength, gsmBitErrorRate, cdmaDbm, cdmaEcio,
evdoDbm, evdoEcio, evdoSnr, lteSignalStrength, lteRsrp,
lteRsrq, lteRssnr, lteCqi, gsmFlag);
+ mTdScdmaRscp = tdScdmaRscp;
}
/**
@@ -398,11 +400,12 @@ public class SignalStrength implements Parcelable {
mLteSignalStrength = (mLteSignalStrength >= 0) ? mLteSignalStrength : 99;
mLteRsrp = ((mLteRsrp >= 44) && (mLteRsrp <= 140)) ? -mLteRsrp : SignalStrength.INVALID;
mLteRsrq = ((mLteRsrq >= 3) && (mLteRsrq <= 20)) ? -mLteRsrq : SignalStrength.INVALID;
- mLteRssnr = ((mLteRssnr >= -200) && (mLteRssnr <= 300)) ? mLteRssnr
+ mLteRssnr = ((mLteRssnr >= -200) && (mLteRssnr <= 300) && !(mLteRsrq == SignalStrength.INVALID && mLteRssnr == -1)) ? mLteRssnr
: SignalStrength.INVALID;
mTdScdmaRscp = ((mTdScdmaRscp >= 25) && (mTdScdmaRscp <= 120))
? -mTdScdmaRscp : SignalStrength.INVALID;
+
// Cqi no change
if (DBG) log("Signal after validate=" + this);
}
@@ -494,6 +497,16 @@ public class SignalStrength implements Parcelable {
return mLteCqi;
}
+ /** @hide */
+ public boolean needsOldRilFeature(String feature) {
+ String[] features = SystemProperties.get("ro.telephony.ril.config", "").split(",");
+ for (String found: features) {
+ if (found.equals(feature))
+ return true;
+ }
+ return false;
+ }
+
/**
* Retrieve an abstract level value for the overall signal strength.
*
@@ -506,8 +519,9 @@ public class SignalStrength implements Parcelable {
int level = 0;
if (isGsm) {
+ boolean oldRil = needsOldRilFeature("signalstrength");
level = getLteLevel();
- if (level == SIGNAL_STRENGTH_NONE_OR_UNKNOWN) {
+ if (level == SIGNAL_STRENGTH_NONE_OR_UNKNOWN || oldRil) {
level = getTdScdmaLevel();
if (level == SIGNAL_STRENGTH_NONE_OR_UNKNOWN) {
level = getGsmLevel();
@@ -539,7 +553,8 @@ public class SignalStrength implements Parcelable {
public int getAsuLevel() {
int asuLevel = 0;
if (isGsm) {
- if (getLteLevel() == SIGNAL_STRENGTH_NONE_OR_UNKNOWN) {
+ boolean oldRil = needsOldRilFeature("signalstrength");
+ if (getLteLevel() == SIGNAL_STRENGTH_NONE_OR_UNKNOWN || oldRil) {
if (getTdScdmaLevel() == SIGNAL_STRENGTH_NONE_OR_UNKNOWN) {
asuLevel = getGsmAsuLevel();
} else {
@@ -575,8 +590,9 @@ public class SignalStrength implements Parcelable {
int dBm = INVALID;
if(isGsm()) {
+ boolean oldRil = needsOldRilFeature("signalstrength");
dBm = getLteDbm();
- if (dBm == INVALID) {
+ if (dBm == INVALID || oldRil) {
if (getTdScdmaLevel() == SIGNAL_STRENGTH_NONE_OR_UNKNOWN) {
dBm = getGsmDbm();
} else {
@@ -796,6 +812,9 @@ public class SignalStrength implements Parcelable {
int[] threshRsrp;
if (rsrpThreshType == RSRP_THRESH_TYPE_STRICT) {
threshRsrp = RSRP_THRESH_STRICT;
+ } else if (rsrpThreshType == RSRP_THRESH_TYPE_CUSTOM) {
+ threshRsrp = Resources.getSystem().getIntArray(com.android.internal.R.array.
+ config_LTE_RSRP_custom_levels);
} else {
threshRsrp = RSRP_THRESH_LENIENT;
}
@@ -933,7 +952,7 @@ public class SignalStrength implements Parcelable {
return tdScdmaAsuLevel;
}
- /**
+ /**
* @return hash code
*/
@Override
diff --git a/telephony/java/android/telephony/SubscriptionInfo.java b/telephony/java/android/telephony/SubscriptionInfo.java
index d1d6e0d..5e5b70d 100644
--- a/telephony/java/android/telephony/SubscriptionInfo.java
+++ b/telephony/java/android/telephony/SubscriptionInfo.java
@@ -111,9 +111,14 @@ public class SubscriptionInfo implements Parcelable {
/**
* @hide
*/
+ public int mUserNwMode;
+
+ /**
+ * @hide
+ */
public SubscriptionInfo(int id, String iccId, int simSlotIndex, CharSequence displayName,
CharSequence carrierName, int nameSource, int iconTint, String number, int roaming,
- Bitmap icon, int mcc, int mnc, String countryIso) {
+ Bitmap icon, int mcc, int mnc, String countryIso, int userNwMode) {
this.mId = id;
this.mIccId = iccId;
this.mSimSlotIndex = simSlotIndex;
@@ -126,6 +131,7 @@ public class SubscriptionInfo implements Parcelable {
this.mIconBitmap = icon;
this.mMcc = mcc;
this.mMnc = mnc;
+ this.mUserNwMode = userNwMode;
this.mCountryIso = countryIso;
}
@@ -277,6 +283,14 @@ public class SubscriptionInfo implements Parcelable {
}
/**
+ * Returns the User set Network mode.
+ * @hide
+ */
+ public int getUserNwMode() {
+ return this.mUserNwMode;
+ }
+
+ /**
* @return the ISO country code
*/
public String getCountryIso() {
@@ -297,11 +311,12 @@ public class SubscriptionInfo implements Parcelable {
int dataRoaming = source.readInt();
int mcc = source.readInt();
int mnc = source.readInt();
+ int userNwMode = source.readInt();
String countryIso = source.readString();
Bitmap iconBitmap = Bitmap.CREATOR.createFromParcel(source);
return new SubscriptionInfo(id, iccId, simSlotIndex, displayName, carrierName,
- nameSource, iconTint, number, dataRoaming, iconBitmap, mcc, mnc, countryIso);
+ nameSource, iconTint, number, dataRoaming, iconBitmap, mcc, mnc, countryIso, userNwMode);
}
@Override
@@ -323,6 +338,7 @@ public class SubscriptionInfo implements Parcelable {
dest.writeInt(mDataRoaming);
dest.writeInt(mMcc);
dest.writeInt(mMnc);
+ dest.writeInt(mUserNwMode);
dest.writeString(mCountryIso);
mIconBitmap.writeToParcel(dest, flags);
}
@@ -354,6 +370,6 @@ public class SubscriptionInfo implements Parcelable {
+ " displayName=" + mDisplayName + " carrierName=" + mCarrierName
+ " nameSource=" + mNameSource + " iconTint=" + mIconTint
+ " dataRoaming=" + mDataRoaming + " iconBitmap=" + mIconBitmap + " mcc " + mMcc
- + " mnc " + mMnc + "}";
+ + " mnc " + mMnc + " mUserNwMode=" + mUserNwMode + "}";
}
}
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 32b7383..1578b43 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -121,6 +121,39 @@ public class SubscriptionManager {
public static final int SIM_NOT_INSERTED = -1;
/**
+ * The Network mode of SIM/sub.
+ * <P>Type: INTEGER (int)</P>
+ */
+ /** @hide */
+ public static final String NETWORK_MODE = "network_mode";
+
+ /**
+ * The user configured Network mode of SIM/sub.
+ * <P>Type: INTEGER (int)</P>
+ * {@hide}
+ */
+ public static final String USER_NETWORK_MODE = "user_network_mode";
+
+ /** @hide */
+ public static final int DEFAULT_NW_MODE = -1;
+
+ /**
+ * The activation state of SIM/sub.
+ * <P>Type: INTEGER (int)</P>
+ */
+ /** @hide */
+ public static final String SUB_STATE = "sub_state";
+
+ /** @hide */
+ public static final int INACTIVE = 0;
+
+ /** @hide */
+ public static final int ACTIVE = 1;
+
+ /** @hide */
+ public static final int SUB_CONFIGURATION_IN_PROGRESS = 2;
+
+ /**
* TelephonyProvider column name for user displayed name.
* <P>Type: TEXT (String)</P>
*/
@@ -1118,6 +1151,53 @@ public class SubscriptionManager {
}
/** @hide */
+ public static void activateSubId(int subId) {
+ logd("activateSubId sub id = " + subId);
+ try {
+ getISubInfo().activateSubId(subId);
+ } catch (RemoteException ex) {
+ return;
+ }
+ }
+
+ /** @hide */
+ public static void deactivateSubId(int subId) {
+ logd("deactivateSubId sub id = " + subId);
+ try {
+ getISubInfo().deactivateSubId(subId);
+ } catch (RemoteException ex) {
+ return;
+ }
+ }
+
+ /** @hide */
+ public static int getSubState(int subId) {
+ logd("getSubState sub id = " + subId);
+ try {
+ return getISubInfo().getSubState(subId);
+ } catch (RemoteException ex) {
+ return INACTIVE;
+ }
+ }
+
+ /** @hide */
+ public static int setSubState(int subId, int subState) {
+ logd("setSubState sub id = " + subId + " state = " + subState);
+ try {
+ return getISubInfo().setSubState(subId, subState);
+ } catch (RemoteException ex) {
+ return INACTIVE;
+ }
+ }
+
+ /**
+ @hide
+ */
+ private static ISub getISubInfo() {
+ return ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ }
+
+ /** @hide */
public static void putPhoneIdAndSubIdExtra(Intent intent, int phoneId) {
int[] subIds = SubscriptionManager.getSubId(phoneId);
if (subIds != null && subIds.length > 0) {
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 65caf56..08d7ffe 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -1,4 +1,7 @@
/*
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ *
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,10 +21,12 @@ package android.telephony;
import android.annotation.Nullable;
import android.annotation.SystemApi;
+import android.Manifest;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.app.ActivityThread;
import android.content.ContentResolver;
+import android.app.AppOpsManager;
import android.content.Context;
import android.content.Intent;
import android.provider.Settings;
@@ -31,6 +36,7 @@ import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemProperties;
import android.telecom.PhoneAccount;
+import android.text.TextUtils;
import android.util.Log;
import com.android.internal.telecom.ITelecomService;
@@ -45,6 +51,7 @@ import com.android.internal.telephony.TelephonyProperties;
import java.io.FileInputStream;
import java.io.IOException;
+import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -721,6 +728,7 @@ public class TelephonyManager {
* @param slotId of which deviceID is returned
*/
public String getDeviceId(int slotId) {
+ android.util.SeempLog.record_str(8, ""+slotId);
// FIXME this assumes phoneId == slotId
try {
IPhoneSubInfo info = getSubscriberInfo();
@@ -817,6 +825,7 @@ public class TelephonyManager {
* {@link android.Manifest.permission#ACCESS_COARSE_LOCATION ACCESS_FINE_LOCATION}.
*/
public CellLocation getCellLocation() {
+ android.util.SeempLog.record(49);
try {
ITelephony telephony = getITelephony();
if (telephony == null) {
@@ -914,6 +923,7 @@ public class TelephonyManager {
*/
@Deprecated
public List<NeighboringCellInfo> getNeighboringCellInfo() {
+ android.util.SeempLog.record(50);
try {
ITelephony telephony = getITelephony();
if (telephony == null)
@@ -1164,6 +1174,15 @@ public class TelephonyManager {
return retVal;
}
+ /**
+ * Return if the current radio is LTE on GSM
+ * @hide
+ */
+ public static int getLteOnGsmModeStatic() {
+ return SystemProperties.getInt(TelephonyProperties.PROPERTY_LTE_ON_GSM_DEVICE,
+ 0);
+ }
+
//
//
// Current Network
@@ -1340,11 +1359,12 @@ public class TelephonyManager {
public static final int NETWORK_TYPE_HSPAP = 15;
/** Current network is GSM {@hide} */
public static final int NETWORK_TYPE_GSM = 16;
- /** Current network is TD_SCDMA {@hide} */
+ /** Current network is TD_SCDMA {@hide} */
public static final int NETWORK_TYPE_TD_SCDMA = 17;
/** Current network is IWLAN {@hide} */
public static final int NETWORK_TYPE_IWLAN = 18;
-
+ /** Current network is LTE_CA {@hide} */
+ public static final int NETWORK_TYPE_LTE_CA = 19;
/**
* @return the NETWORK_TYPE_xxxx for current data connection.
*/
@@ -1389,10 +1409,12 @@ public class TelephonyManager {
* @see #NETWORK_TYPE_LTE
* @see #NETWORK_TYPE_EHRPD
* @see #NETWORK_TYPE_HSPAP
+ * @see #NETWORK_TYPE_TD_SCDMA
*
* <p>
* Requires Permission:
* {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+ * @hide
*/
/** {@hide} */
public int getNetworkType(int subId) {
@@ -1512,6 +1534,21 @@ public class TelephonyManager {
}
}
+ /**
+ * Returns the icc operator numeric for a given subId
+ *
+ */
+ /** {@hide} */
+ public String getIccOperatorNumericForData(int subId) {
+ try{
+ return getITelephony().getIccOperatorNumericForData(subId);
+ } catch (RemoteException ex) {
+ return null;
+ } catch (NullPointerException ex) {
+ return null;
+ }
+ }
+
/** Unknown network class. {@hide} */
public static final int NETWORK_CLASS_UNKNOWN = 0;
/** Class of broadly defined "2G" networks. {@hide} */
@@ -1549,6 +1586,7 @@ public class TelephonyManager {
return NETWORK_CLASS_3_G;
case NETWORK_TYPE_LTE:
case NETWORK_TYPE_IWLAN:
+ case NETWORK_TYPE_LTE_CA:
return NETWORK_CLASS_4_G;
default:
return NETWORK_CLASS_UNKNOWN;
@@ -1612,11 +1650,44 @@ public class TelephonyManager {
return "TD_SCDMA";
case NETWORK_TYPE_IWLAN:
return "IWLAN";
+ case NETWORK_TYPE_LTE_CA:
+ return "LTE_CA";
default:
return "UNKNOWN";
}
}
+ /**
+ * convert network class to string base on network type
+ * @param type for which network type is returned
+ * @return the network class type string
+ * @hide
+ */
+ public String networkClassToString(int type) {
+ String ratClassName = "";
+ int networkClass = getNetworkClass(type);
+ Rlog.d(TAG, "networkType = " + type + " networkClass = " + networkClass);
+ if (mContext == null) return null;
+ switch (networkClass) {
+ case TelephonyManager.NETWORK_CLASS_2_G:
+ ratClassName = mContext.getResources().getString(
+ com.android.internal.R.string.config_rat_2g);
+ break;
+ case TelephonyManager.NETWORK_CLASS_3_G:
+ ratClassName = mContext.getResources().getString(
+ com.android.internal.R.string.config_rat_3g);
+ break;
+ case TelephonyManager.NETWORK_CLASS_4_G:
+ ratClassName = mContext.getResources().getString(
+ com.android.internal.R.string.config_rat_4g);
+ break;
+ default:
+ ratClassName = "";
+ break;
+ }
+ return ratClassName;
+ }
+
//
//
// SIM Card
@@ -1917,6 +1988,7 @@ public class TelephonyManager {
*/
/** {@hide} */
public String getSimSerialNumber(int subId) {
+ android.util.SeempLog.record_str(388, ""+subId);
try {
IPhoneSubInfo info = getSubscriberInfo();
if (info == null)
@@ -1977,6 +2049,21 @@ public class TelephonyManager {
}
}
+ /**
+ * Return if the current radio is LTE on GSM
+ * @hide
+ */
+ public int getLteOnGsmMode() {
+ try {
+ return getITelephony().getLteOnGsmMode();
+ } catch (RemoteException ex) {
+ return 0;
+ } catch (NullPointerException ex) {
+ // This could happen before phone restarts due to crashing
+ return 0;
+ }
+ }
+
//
//
// Subscriber Info
@@ -2006,6 +2093,7 @@ public class TelephonyManager {
*/
/** {@hide} */
public String getSubscriberId(int subId) {
+ android.util.SeempLog.record_str(389, ""+subId);
try {
IPhoneSubInfo info = getSubscriberInfo();
if (info == null)
@@ -2094,6 +2182,7 @@ public class TelephonyManager {
*/
/** {@hide} */
public String getLine1NumberForSubscriber(int subId) {
+ android.util.SeempLog.record_str(9, ""+subId);
String number = null;
try {
ITelephony telephony = getITelephony();
@@ -2891,6 +2980,40 @@ public class TelephonyManager {
}
/**
+ * Allows an application to add a protected sms address if the application has
+ * been granted the permission MODIFY_PROTECTED_SMS_LIST.
+ * @param address
+ * @hide
+ */
+ public void addProtectedSmsAddress(String address) {
+ mContext.enforceCallingOrSelfPermission(
+ Manifest.permission.MODIFY_PROTECTED_SMS_LIST, null);
+ try {
+ getITelephony().addProtectedSmsAddress(address);
+ } catch (RemoteException ex) {
+ } catch (NullPointerException ex) {
+ }
+ }
+
+ /**
+ * Allows an application to revoke/remove a protected sms address if the application has been
+ * granted the permission MODIFY_PROTECTED_SMS_LIST.
+ * @param address
+ * @return true if address is successfully removed
+ * @hide
+ */
+ public boolean revokeProtectedSmsAddress(String address) {
+ mContext.enforceCallingOrSelfPermission(
+ Manifest.permission.MODIFY_PROTECTED_SMS_LIST, null);
+ try {
+ return getITelephony().revokeProtectedSmsAddress(address);
+ } catch (RemoteException ex) {
+ } catch (NullPointerException ex) {
+ }
+ return false;
+ }
+
+ /**
* Returns the MMS user agent.
*/
public String getMmsUserAgent() {
@@ -3356,13 +3479,7 @@ public class TelephonyManager {
/** @hide */
public int getSimCount() {
- // FIXME Need to get it from Telephony Dev Controller when that gets implemented!
- // and then this method shouldn't be used at all!
- if(isMultiSimEnabled()) {
- return 2;
- } else {
- return 1;
- }
+ return getPhoneCount();
}
/**
@@ -4158,11 +4275,18 @@ public class TelephonyManager {
public void setDataEnabled(int subId, boolean enable) {
try {
Log.d(TAG, "setDataEnabled: enabled=" + enable);
+ AppOpsManager appOps = (AppOpsManager)mContext.getSystemService(Context.APP_OPS_SERVICE);
+ if (enable) {
+ if (appOps.noteOp(AppOpsManager.OP_DATA_CONNECT_CHANGE) != AppOpsManager.MODE_ALLOWED) {
+ Log.w(TAG, "Permission denied by user.");
+ return;
+ }
+ }
ITelephony telephony = getITelephony();
if (telephony != null)
telephony.setDataEnabled(subId, enable);
} catch (RemoteException e) {
- Log.e(TAG, "Error calling ITelephony#setDataEnabled", e);
+ Log.e(TAG, "Error calling setDataEnabled", e);
}
}
diff --git a/telephony/java/com/android/ims/ImsCallProfile.java b/telephony/java/com/android/ims/ImsCallProfile.java
index 5f84e0c..50ee543 100644
--- a/telephony/java/com/android/ims/ImsCallProfile.java
+++ b/telephony/java/com/android/ims/ImsCallProfile.java
@@ -188,6 +188,7 @@ public class ImsCallProfile implements Parcelable {
public static final String EXTRA_CODEC = "Codec";
public static final String EXTRA_DISPLAY_TEXT = "DisplayText";
public static final String EXTRA_ADDITIONAL_CALL_INFO = "AdditionalCallInfo";
+ public static final String EXTRA_IS_CALL_PULL = "CallPull";
/**
* Extra key which the RIL can use to indicate the radio technology used for a call.
diff --git a/telephony/java/com/android/ims/ImsReasonInfo.java b/telephony/java/com/android/ims/ImsReasonInfo.java
index 2769a2b..3ab415c 100644
--- a/telephony/java/com/android/ims/ImsReasonInfo.java
+++ b/telephony/java/com/android/ims/ImsReasonInfo.java
@@ -84,6 +84,8 @@ public class ImsReasonInfo implements Parcelable {
public static final int CODE_LOCAL_CALL_VOLTE_RETRY_REQUIRED = 147;
// IMS call is already terminated (in TERMINATED state)
public static final int CODE_LOCAL_CALL_TERMINATED = 148;
+ // Handover not feasible
+ public static final int CODE_LOCAL_HO_NOT_FEASIBLE = 149;
/**
* TIMEOUT (IMS -> Telephony)
@@ -153,6 +155,9 @@ public class ImsReasonInfo implements Parcelable {
public static final int CODE_SIP_USER_REJECTED = 361;
// Others
public static final int CODE_SIP_GLOBAL_ERROR = 362;
+ // Emergency failure
+ public static final int CODE_EMERGENCY_TEMP_FAILURE = 363;
+ public static final int CODE_EMERGENCY_PERM_FAILURE = 364;
/**
* MEDIA (IMS -> Telephony)
@@ -236,6 +241,16 @@ public class ImsReasonInfo implements Parcelable {
public static final int CODE_ANSWERED_ELSEWHERE = 1014;
/**
+ * For VICE - Call Pull request has failed
+ */
+ public static final int CODE_CALL_PULL_OUT_OF_SYNC = 1015;
+
+ /**
+ * For VICE - Call has been pulled from primary to secondary
+ */
+ public static final int CODE_CALL_END_CAUSE_CALL_PULL = 1016;
+
+ /**
* Network string error messages.
* mExtraMessage may have these values.
*/
diff --git a/telephony/java/com/android/ims/ImsStreamMediaProfile.java b/telephony/java/com/android/ims/ImsStreamMediaProfile.java
index 359b270..216cef5 100644
--- a/telephony/java/com/android/ims/ImsStreamMediaProfile.java
+++ b/telephony/java/com/android/ims/ImsStreamMediaProfile.java
@@ -51,6 +51,16 @@ public class ImsStreamMediaProfile implements Parcelable {
public static final int AUDIO_QUALITY_GSM_EFR = 8;
public static final int AUDIO_QUALITY_GSM_FR = 9;
public static final int AUDIO_QUALITY_GSM_HR = 10;
+ public static final int AUDIO_QUALITY_G711U = 11;
+ public static final int AUDIO_QUALITY_G723 = 12;
+ public static final int AUDIO_QUALITY_G711A = 13;
+ public static final int AUDIO_QUALITY_G722 = 14;
+ public static final int AUDIO_QUALITY_G711AB = 15;
+ public static final int AUDIO_QUALITY_G729 = 16;
+ public static final int AUDIO_QUALITY_EVS_NB = 17;
+ public static final int AUDIO_QUALITY_EVS_WB = 18;
+ public static final int AUDIO_QUALITY_EVS_SWB = 19;
+ public static final int AUDIO_QUALITY_EVS_FB = 20;
/**
* Video information
@@ -76,7 +86,7 @@ public class ImsStreamMediaProfile implements Parcelable {
}
public ImsStreamMediaProfile() {
- mAudioQuality = AUDIO_QUALITY_AMR_WB;
+ mAudioQuality = AUDIO_QUALITY_NONE;
mAudioDirection = DIRECTION_SEND_RECEIVE;
mVideoQuality = VIDEO_QUALITY_NONE;
mVideoDirection = DIRECTION_INVALID;
diff --git a/telephony/java/com/android/ims/internal/IImsRegistrationListener.aidl b/telephony/java/com/android/ims/internal/IImsRegistrationListener.aidl
index 23a69d1..507a293 100644
--- a/telephony/java/com/android/ims/internal/IImsRegistrationListener.aidl
+++ b/telephony/java/com/android/ims/internal/IImsRegistrationListener.aidl
@@ -17,6 +17,7 @@
package com.android.ims.internal;
import com.android.ims.ImsReasonInfo;
+
/**
* A listener type for receiving notifications about the changes to
* the IMS connection(registration).
@@ -26,30 +27,36 @@ import com.android.ims.ImsReasonInfo;
interface IImsRegistrationListener {
/**
* Notifies the application when the device is connected to the IMS network.
+ *
+ * @param imsRadioTech the radio access technology. Valid values are {@code
+ * RIL_RADIO_TECHNOLOGY_*} defined in {@link ServiceState}.
*/
- void registrationConnected();
+ void registrationConnected(int imsRadioTech) = 0;
/**
* Notifies the application when the device is trying to connect the IMS network.
+ *
+ * @param imsRadioTech the radio access technology. Valid values are {@code
+ * RIL_RADIO_TECHNOLOGY_*} defined in {@link ServiceState}.
*/
- void registrationProgressing();
+ void registrationProgressing(int imsRadioTech) = 1;
/**
* Notifies the application when the device is disconnected from the IMS network.
*/
- void registrationDisconnected(in ImsReasonInfo imsReasonInfo);
+ void registrationDisconnected(in ImsReasonInfo imsReasonInfo) = 2;
/**
* Notifies the application when its suspended IMS connection is resumed,
* meaning the connection now allows throughput.
*/
- void registrationResumed();
+ void registrationResumed() = 3;
/**
* Notifies the application when its current IMS connection is suspended,
* meaning there is no data throughput.
*/
- void registrationSuspended();
+ void registrationSuspended() = 4;
/**
* Notifies the application when its current IMS connection is updated
@@ -60,7 +67,7 @@ interface IImsRegistrationListener {
* If {@code event} is 0, meaning the specified service is removed from the IMS connection.
* Else ({@code event} is 1), meaning the specified service is added to the IMS connection.
*/
- void registrationServiceCapabilityChanged(int serviceClass, int event);
+ void registrationServiceCapabilityChanged(int serviceClass, int event) = 5;
/**
* Notifies the application when features on a particular service enabled or
@@ -71,11 +78,17 @@ interface IImsRegistrationListener {
* @param disabledFeatures features disabled as defined in com.android.ims.ImsConfig#FeatureConstants.
*/
void registrationFeatureCapabilityChanged(int serviceClass,
- in int[] enabledFeatures, in int[] disabledFeatures);
+ in int[] enabledFeatures, in int[] disabledFeatures) = 6;
/**
* Updates the application with the waiting voice message count.
* @param count The number of waiting voice messages.
*/
- void voiceMessageCountUpdate(int count);
+ void voiceMessageCountUpdate(int count) = 7;
+
+ /**
+ * Compatibility with AOSP
+ */
+ void registrationConnected() = 8;
+ void registrationProgressing() = 9;
}
diff --git a/telephony/java/com/android/internal/telephony/CallerInfo.java b/telephony/java/com/android/internal/telephony/CallerInfo.java
index be7e702..6e1a004 100644
--- a/telephony/java/com/android/internal/telephony/CallerInfo.java
+++ b/telephony/java/com/android/internal/telephony/CallerInfo.java
@@ -165,6 +165,7 @@ public class CallerInfo {
* number. The returned CallerInfo is null if no number is supplied.
*/
public static CallerInfo getCallerInfo(Context context, Uri contactRef, Cursor cursor) {
+ android.util.SeempLog.record_uri(12, contactRef);
CallerInfo info = new CallerInfo();
info.photoResource = 0;
info.phoneLabel = null;
@@ -325,6 +326,7 @@ public class CallerInfo {
* with all relevant fields empty or null.
*/
public static CallerInfo getCallerInfo(Context context, String number, int subId) {
+ android.util.SeempLog.record_str(12, "number="+number+",subId="+subId);
if (TextUtils.isEmpty(number)) {
return null;
diff --git a/telephony/java/com/android/internal/telephony/IExtTelephony.aidl b/telephony/java/com/android/internal/telephony/IExtTelephony.aidl
new file mode 100644
index 0000000..063308d
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/IExtTelephony.aidl
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+package com.android.internal.telephony;
+
+
+/**
+ * Interface used to interact with the telephony framework for
+ * Telephony value adds.
+ * {@hide}
+ */
+interface IExtTelephony {
+
+ /**
+ * Returns the current SIM Manual provision status.
+ * @param slotId user preferred slotId.
+ * @return Card provision status as integer, below are
+ * possible return values.
+ * '0' - returned if Uicc Card is not provisioned.
+ * '1' - returned if Uicc Card provisioned.
+ * '-1'- returned if there is an error @ below layers OR
+ * if framework does not received info from Modem yet.
+ * '-2' returned when SIM card is not present in slot.
+ * Requires Permission: android.Manifest.permission.READ_PHONE_STATE
+ */
+ int getCurrentUiccCardProvisioningStatus(int slotId);
+
+ /**
+ * Returns the user preferred Uicc card provision status.
+ * @param slotId user preferred slotId.
+ * @return User preference value as integer, below are
+ * possible return values.
+ * '0' - returned if Uicc Card is not provisioned.
+ * '1' - returned if Uicc Card provisioned.
+ * '-1'- returned if there is an error @ below layers OR
+ * if framework does not received info from Modem yet.
+ * '-2' returned when SIM card is not present in slot.
+ * Requires Permission: android.Manifest.permission.READ_PHONE_STATE
+ */
+ int getUiccCardProvisioningUserPreference(int slotId);
+
+ /**
+ * Activates the Uicc card.
+ * @param slotId user preferred slotId.
+ * @return Uicc card activation result as Integer, below are
+ * supported return values:
+ * '0' - Success
+ * '-1' -Generic Failure
+ * '-2' -Invalid input
+ * '-3 -Another request in progress
+ * Requires Permission: android.Manifest.permission.MODIFY_PHONE_STATE
+ */
+ int activateUiccCard(int slotId);
+
+ /**
+ * Deactivates UICC card.
+ * @param slotId user preferred slotId.
+ * @return Uicc card deactivation result as Integer, below are
+ * supported return values:
+ * '0' - Success
+ * '-1' -Generic Failure
+ * '-2' -Invalid input
+ * '-3 -Another request in progress
+ * Requires Permission: android.Manifest.permission.MODIFY_PHONE_STATE
+ */
+ int deactivateUiccCard(int slotId);
+
+ /**
+ * Check for Sms Prompt is Enabled or Not.
+ * @return
+ * true - Sms Prompt is Enabled
+ * false - Sms prompt is Disabled
+ * Requires Permission: android.Manifest.permission.READ_PHONE_STATE
+ */
+ boolean isSMSPromptEnabled();
+
+ /**
+ * Enable/Disable Sms prompt option.
+ * @param - enabled
+ * true - to enable Sms prompt
+ * false - to disable Sms prompt
+ * Requires Permission: android.Manifest.permission.MODIFY_PHONE_STATE
+ */
+ void setSMSPromptEnabled(boolean enabled);
+
+ /**
+ * Get logical phone id for Emergency call.
+ * @param - void
+ * @return phone id
+ */
+ int getPhoneIdForECall();
+}
diff --git a/telephony/java/com/android/internal/telephony/ISms.aidl b/telephony/java/com/android/internal/telephony/ISms.aidl
index 70a8653..1377734 100644
--- a/telephony/java/com/android/internal/telephony/ISms.aidl
+++ b/telephony/java/com/android/internal/telephony/ISms.aidl
@@ -187,6 +187,53 @@ interface ISms {
in PendingIntent deliveryIntent);
/**
+ * Send an SMS with options using Subscription Id.
+ *
+ * @param subId the subId on which the SMS has to be sent.
+ * @param destAddr the address to send the message to
+ * @param scAddr the SMSC to send the message through, or NULL for the
+ * default SMSC
+ * @param text the body of the message to send
+ * @param sentIntent if not NULL this <code>PendingIntent</code> is
+ * broadcast when the message is sucessfully sent, or failed.
+ * The result code will be <code>Activity.RESULT_OK<code> for success,
+ * or one of these errors:<br>
+ * <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
+ * <code>RESULT_ERROR_RADIO_OFF</code><br>
+ * <code>RESULT_ERROR_NULL_PDU</code><br>
+ * For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include
+ * the extra "errorCode" containing a radio technology specific value,
+ * generally only useful for troubleshooting.<br>
+ * The per-application based SMS control checks sentIntent. If sentIntent
+ * is NULL the caller will be checked against all unknown applications,
+ * which cause smaller number of SMS to be sent in checking period.
+ * @param deliveryIntent if not NULL this <code>PendingIntent</code> is
+ * broadcast when the message is delivered to the recipient. The
+ * raw pdu of the status report is in the extended data ("pdu").
+ * @param priority Priority level of the message
+ * Refer specification See 3GPP2 C.S0015-B, v2.0, table 4.5.9-1
+ * ---------------------------------
+ * PRIORITY | Level of Priority
+ * ---------------------------------
+ * '00' | Normal
+ * '01' | Interactive
+ * '10' | Urgent
+ * '11' | Emergency
+ * ----------------------------------
+ * Any Other values included Negative considered as Invalid Priority Indicator of the message.
+ * @param isExpectMore is a boolean to indicate the sending message is multi segmented or not.
+ * @param validityPeriod Validity Period of the message in mins.
+ * Refer specification 3GPP TS 23.040 V6.8.1 section 9.2.3.12.1.
+ * Validity Period(Minimum) -> 5 mins
+ * Validity Period(Maximum) -> 635040 mins(i.e.63 weeks).
+ * Any Other values included Negative considered as Invalid Validity Period of the message.
+ */
+ void sendTextForSubscriberWithOptions(in int subId, String callingPkg, in String destAddr,
+ in String scAddr, in String text, in PendingIntent sentIntent,
+ in PendingIntent deliveryIntent, in int priority, in boolean isExpectMore,
+ in int validityPeriod);
+
+ /**
* Inject an SMS PDU into the android platform.
*
* @param subId the subId on which the SMS has to be injected.
@@ -234,6 +281,51 @@ interface ISms {
in List<PendingIntent> deliveryIntents, in boolean persistMessageForNonDefaultSmsApp);
/**
+ * Send a multi-part text based SMS with options using Subscription Id.
+ *
+ * @param subId the subId on which the SMS has to be sent.
+ * @param destinationAddress the address to send the message to
+ * @param scAddress is the service center address or null to use
+ * the current default SMSC
+ * @param parts an <code>ArrayList</code> of strings that, in order,
+ * comprise the original message
+ * @param sentIntents if not null, an <code>ArrayList</code> of
+ * <code>PendingIntent</code>s (one for each message part) that is
+ * broadcast when the corresponding message part has been sent.
+ * The result code will be <code>Activity.RESULT_OK<code> for success,
+ * or one of these errors:
+ * <code>RESULT_ERROR_GENERIC_FAILURE</code>
+ * <code>RESULT_ERROR_RADIO_OFF</code>
+ * <code>RESULT_ERROR_NULL_PDU</code>.
+ * @param deliveryIntents if not null, an <code>ArrayList</code> of
+ * <code>PendingIntent</code>s (one for each message part) that is
+ * broadcast when the corresponding message part has been delivered
+ * to the recipient. The raw pdu of the status report is in the
+ * extended data ("pdu").
+ * @param priority Priority level of the message
+ * Refer specification See 3GPP2 C.S0015-B, v2.0, table 4.5.9-1
+ * ---------------------------------
+ * PRIORITY | Level of Priority
+ * ---------------------------------
+ * '00' | Normal
+ * '01' | Interactive
+ * '10' | Urgent
+ * '11' | Emergency
+ * ----------------------------------
+ * Any Other values included Negative considered as Invalid Priority Indicator of the message.
+ * @param isExpectMore is a boolean to indicate the sending message is multi segmented or not.
+ * @param validityPeriod Validity Period of the message in mins.
+ * Refer specification 3GPP TS 23.040 V6.8.1 section 9.2.3.12.1.
+ * Validity Period(Minimum) -> 5 mins
+ * Validity Period(Maximum) -> 635040 mins(i.e.63 weeks).
+ * Any Other values included Negative considered as Invalid Validity Period of the message.
+ */
+ void sendMultipartTextForSubscriberWithOptions(in int subId, String callingPkg,
+ in String destinationAddress, in String scAddress, in List<String> parts,
+ in List<PendingIntent> sentIntents, in List<PendingIntent> deliveryIntents,
+ in int priority, in boolean isExpectMore, in int validityPeriod);
+
+ /**
* Enable reception of cell broadcast (SMS-CB) messages with the given
* message identifier and RAN type. The RAN type specify this message ID
* belong to 3GPP (GSM) or 3GPP2(CDMA). Note that if two different clients
@@ -447,4 +539,12 @@ interface ISms {
void sendStoredMultipartText(int subId, String callingPkg, in Uri messageUri,
String scAddress, in List<PendingIntent> sentIntents,
in List<PendingIntent> deliveryIntents);
+
+ /**
+ * Get the capacity count of sms on Icc card.
+ *
+ * @param subId for subId which getSmsCapacityOnIcc is queried.
+ * @return capacity of ICC
+ */
+ int getSmsCapacityOnIccForSubscriber(int subId);
}
diff --git a/telephony/java/com/android/internal/telephony/ISub.aidl b/telephony/java/com/android/internal/telephony/ISub.aidl
index f6aef08..1323258 100755
--- a/telephony/java/com/android/internal/telephony/ISub.aidl
+++ b/telephony/java/com/android/internal/telephony/ISub.aidl
@@ -183,4 +183,12 @@ interface ISub {
int getSimStateForSlotIdx(int slotIdx);
boolean isActiveSubId(int subId);
+
+ void activateSubId(int subId);
+
+ void deactivateSubId(int subId);
+
+ int setSubState(int subId, int subStatus);
+
+ int getSubState(int subId);
}
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index dcece26..c3db8c2 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -488,6 +488,13 @@ interface ITelephony {
int getVoiceNetworkTypeForSubscriber(int subId, String callingPackage);
/**
+ * Return icc operator numeric for given subId
+ * @param subId user preferred subId.
+ * Returns icc operator numeric
+ */
+ String getIccOperatorNumericForData(int subId);
+
+ /**
* Return true if an ICC card is present
*/
boolean hasIccCard();
@@ -531,6 +538,22 @@ interface ITelephony {
*/
void setCellInfoListRate(int rateInMillis);
+
+ /**
+ * Return if the current radio is LTE on GSM
+ */
+ int getLteOnGsmMode();
+
+ /**
+ * Adds a protected sms address to the {@link Settings.Secure.PROTECTED_SMS_ADDRESSES}
+ */
+ void addProtectedSmsAddress(String address);
+
+ /**
+ * Revokes a protected sms address from {@link Settings.Secure.PROTECTED_SMS_ADDRESSES}
+ */
+ boolean revokeProtectedSmsAddress(String address);
+
/**
* get default sim
* @return sim id
@@ -547,6 +570,18 @@ interface ITelephony {
*/
IccOpenLogicalChannelResponse iccOpenLogicalChannel(String AID);
+
+ /**
+ * Opens a logical channel to the ICC card for a particular subId.
+ *
+ * Input parameters equivalent to TS 27.007 AT+CCHO command.
+ *
+ * @param subId user preferred subId.
+ * @param AID Application id. See ETSI 102.221 and 101.220.
+ * @return an IccOpenLogicalChannelResponse object.
+ */
+ IccOpenLogicalChannelResponse iccOpenLogicalChannelUsingSubId(int subId, String AID);
+
/**
* Closes a previously opened logical channel to the ICC card.
*
@@ -559,6 +594,19 @@ interface ITelephony {
boolean iccCloseLogicalChannel(int channel);
/**
+ * Closes a previously opened logical channel to the ICC card for a
+ * particular subId.
+ *
+ * Input parameters equivalent to TS 27.007 AT+CCHC command.
+ *
+ * @param subId user preferred subId.
+ * @param channel is the channel id to be closed as retruned by a
+ * successful iccOpenLogicalChannel.
+ * @return true if the channel was closed successfully.
+ */
+ boolean iccCloseLogicalChannelUsingSubId(int subId, int channel);
+
+ /**
* Transmit an APDU to the ICC card over a logical channel.
*
* Input parameters equivalent to TS 27.007 AT+CGLA command.
@@ -579,6 +627,28 @@ interface ITelephony {
int p1, int p2, int p3, String data);
/**
+ * Transmit an APDU to the ICC card over a logical channel for a
+ * particular subId.
+ *
+ * Input parameters equivalent to TS 27.007 AT+CGLA command.
+ *
+ * @param subId user preferred subId.
+ * @param channel is the channel id to be closed as retruned by a
+ * successful iccOpenLogicalChannel.
+ * @param cla Class of the APDU command.
+ * @param instruction Instruction of the APDU command.
+ * @param p1 P1 value of the APDU command.
+ * @param p2 P2 value of the APDU command.
+ * @param p3 P3 value of the APDU command. If p3 is negative a 4 byte APDU
+ * is sent to the SIM.
+ * @param data Data to be sent with the APDU.
+ * @return The APDU response from the ICC card with the status appended at
+ * the end.
+ */
+ String iccTransmitApduLogicalChannelUsingSubId(int subId, int channel, int cla,
+ int instruction, int p1, int p2, int p3, String data);
+
+ /**
* Transmit an APDU to the ICC card over the basic channel.
*
* Input parameters equivalent to TS 27.007 AT+CSIM command.
@@ -597,6 +667,26 @@ interface ITelephony {
int p1, int p2, int p3, String data);
/**
+ * Transmit an APDU to the ICC card over the basic channel for a particular
+ * subId.
+ *
+ * Input parameters equivalent to TS 27.007 AT+CSIM command.
+ *
+ * @param subId user preferred subId.
+ * @param cla Class of the APDU command.
+ * @param instruction Instruction of the APDU command.
+ * @param p1 P1 value of the APDU command.
+ * @param p2 P2 value of the APDU command.
+ * @param p3 P3 value of the APDU command. If p3 is negative a 4 byte APDU
+ * is sent to the SIM.
+ * @param data Data to be sent with the APDU.
+ * @return The APDU response from the ICC card with the status appended at
+ * the end.
+ */
+ String iccTransmitApduBasicChannelUsingSubId(int subId, int cla, int instruction,
+ int p1, int p2, int p3, String data);
+
+ /**
* Returns the response APDU for a command APDU sent through SIM_IO.
*
* @param fileID
@@ -611,6 +701,22 @@ interface ITelephony {
String filePath);
/**
+ * Returns the response APDU for a command APDU sent through SIM_IO
+ * for a particular subId.
+ *
+ * @param subId user preferred subId.
+ * @param fileID
+ * @param command
+ * @param p1 P1 value of the APDU command.
+ * @param p2 P2 value of the APDU command.
+ * @param p3 P3 value of the APDU command.
+ * @param filePath
+ * @return The APDU response.
+ */
+ byte[] iccExchangeSimIOUsingSubId(int subId, int fileID, int command, int p1, int p2,
+ int p3, String filePath);
+
+ /**
* Send ENVELOPE to the SIM and returns the response.
*
* @param contents String containing SAT/USAT response in hexadecimal
@@ -1005,4 +1111,15 @@ interface ITelephony {
* Return the modem activity info.
*/
ModemActivityInfo getModemActivityInfo();
+
+ /**
+ * Get ATR (Answer To Reset; as per ISO/IEC 7816-4) from SIM card
+ */
+ byte[] getAtr();
+
+ /**
+ * Get ATR (Answer To Reset; as per ISO/IEC 7816-4) from SIM card
+ * for a particular subId.
+ */
+ byte[] getAtrUsingSubId(int subId);
}
diff --git a/telephony/java/com/android/internal/telephony/OperatorInfo.java b/telephony/java/com/android/internal/telephony/OperatorInfo.java
index a29d7c1..7db6600 100644
--- a/telephony/java/com/android/internal/telephony/OperatorInfo.java
+++ b/telephony/java/com/android/internal/telephony/OperatorInfo.java
@@ -33,6 +33,7 @@ public class OperatorInfo implements Parcelable {
private String mOperatorAlphaLong;
private String mOperatorAlphaShort;
private String mOperatorNumeric;
+ private String mRadioTech;
private State mState = State.UNKNOWN;
@@ -57,6 +58,11 @@ public class OperatorInfo implements Parcelable {
return mState;
}
+ public String
+ getRadioTech() {
+ return mRadioTech;
+ }
+
OperatorInfo(String operatorAlphaLong,
String operatorAlphaShort,
String operatorNumeric,
@@ -65,6 +71,14 @@ public class OperatorInfo implements Parcelable {
mOperatorAlphaLong = operatorAlphaLong;
mOperatorAlphaShort = operatorAlphaShort;
mOperatorNumeric = operatorNumeric;
+ mRadioTech = "";
+ /* operatorNumeric format: PLMN+RAT or PLMN */
+ if (null != operatorNumeric) {
+ String values[] = operatorNumeric.split("\\+");
+ mOperatorNumeric = values[0];
+ if (values.length > 1)
+ mRadioTech = values[1];
+ }
mState = state;
}
@@ -108,6 +122,7 @@ public class OperatorInfo implements Parcelable {
return "OperatorInfo " + mOperatorAlphaLong
+ "/" + mOperatorAlphaShort
+ "/" + mOperatorNumeric
+ + "/" + mRadioTech
+ "/" + mState;
}
@@ -132,7 +147,7 @@ public class OperatorInfo implements Parcelable {
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(mOperatorAlphaLong);
dest.writeString(mOperatorAlphaShort);
- dest.writeString(mOperatorNumeric);
+ dest.writeString(mOperatorNumeric + "+" + mRadioTech);
dest.writeSerializable(mState);
}
diff --git a/telephony/java/com/android/internal/telephony/PhoneConstants.java b/telephony/java/com/android/internal/telephony/PhoneConstants.java
index 572cc6f..5fd7d5e 100644..100755
--- a/telephony/java/com/android/internal/telephony/PhoneConstants.java
+++ b/telephony/java/com/android/internal/telephony/PhoneConstants.java
@@ -183,7 +183,8 @@ public class PhoneConstants {
public enum CardUnavailableReason {
REASON_CARD_REMOVED,
REASON_RADIO_UNAVAILABLE,
- REASON_SIM_REFRESH_RESET
+ REASON_SIM_REFRESH_RESET,
+ REASON_APM_SIM_POWER_DOWN
};
// Initial MTU value.
diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java
index 7088be8..af79ff8 100644..100755
--- a/telephony/java/com/android/internal/telephony/RILConstants.java
+++ b/telephony/java/com/android/internal/telephony/RILConstants.java
@@ -77,7 +77,7 @@ public interface RILConstants {
int SIM_SAP_MSG_SIZE_TOO_SMALL = 34;
int SIM_SAP_CONNECT_OK_CALL_ONGOING = 35;
int LCE_NOT_SUPPORTED = 36; /* Link Capacity Estimation (LCE) not supported */
-
+ int INVALID_PARAMETER = 37;
/* NETWORK_MODE_* See ril.h RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE */
int NETWORK_MODE_WCDMA_PREF = 0; /* GSM/WCDMA (WCDMA preferred) */
@@ -334,6 +334,7 @@ cat include/telephony/ril.h | \
int RIL_REQUEST_STOP_LCE = 133;
int RIL_REQUEST_PULL_LCEDATA = 134;
int RIL_REQUEST_GET_ACTIVITY_INFO = 135;
+ int RIL_REQUEST_SIM_GET_ATR = 136;
int RIL_UNSOL_RESPONSE_BASE = 1000;
int RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED = 1000;
@@ -382,4 +383,6 @@ cat include/telephony/ril.h | \
int RIL_UNSOL_ON_SS = 1043;
int RIL_UNSOL_STK_CC_ALPHA_NOTIFY = 1044;
int RIL_UNSOL_LCEDATA_RECV = 1045;
+
+ int RIL_UNSOL_STK_SEND_SMS_RESULT = 11002; /* Samsung STK */
}
diff --git a/telephony/java/com/android/internal/telephony/TelephonyProperties.java b/telephony/java/com/android/internal/telephony/TelephonyProperties.java
index 645c3a1..73e778c 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyProperties.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyProperties.java
@@ -88,6 +88,11 @@ public interface TelephonyProperties
*/
static final String PROPERTY_LTE_ON_CDMA_DEVICE = "telephony.lteOnCdmaDevice";
+ /**
+ * {@see BaseCommands#getLteOnGsmMode()}
+ */
+ static final String PROPERTY_LTE_ON_GSM_DEVICE = "telephony.lteOnGsmDevice";
+
static final String CURRENT_ACTIVE_PHONE = "gsm.current.phone-type";
//****** SIM Card
@@ -217,4 +222,44 @@ public interface TelephonyProperties
* or Earpiece, based on the default audio routing strategy.
*/
static final String PROPERTY_VIDEOCALL_AUDIO_OUTPUT = "persist.radio.call.audio.output";
+
+ /**
+ * Used when Presence app sends Dial intent with specific schema
+ * If true: skip schema parsing and use Tel schema
+ * If false: parse schema
+ */
+ static final String EXTRA_SKIP_SCHEMA_PARSING =
+ "org.codeaurora.extra.SKIP_SCHEMA_PARSING";
+
+ /**
+ * For Group Conference Calling
+ * If true: isConferenceUri in Dial is set to true,
+ * which indicates that Dial is for Conference Calling
+ * If false: above is set to false
+ */
+ static final String EXTRAS_IS_CONFERENCE_URI = "isConferenceUri";
+
+ /**
+ * For Group Conference Dialing Feature
+ * If true: Dial intent triggered from Group Conference Calling screen
+ * if false: normal dial
+ */
+ static final String EXTRA_DIAL_CONFERENCE_URI =
+ "org.codeaurora.extra.DIAL_CONFERENCE_URI";
+
+ /**
+ * For Add Participant Feature
+ * If true: Dial intent triggered from Dialpad is for AddParticipant
+ * if false: normal dial
+ */
+ static final String ADD_PARTICIPANT_KEY = "add_participant";
+
+ /**
+ * For VICE Feature
+ * If true: Dial intent is for call pull functionality
+ * if false: normal dial
+ */
+ static final String EXTRA_IS_CALL_PULL =
+ "org.codeaurora.extra.IS_CALL_PULL";
+
}
diff --git a/test-runner/src/android/test/mock/MockContext.java b/test-runner/src/android/test/mock/MockContext.java
index e09d124..d530491 100644
--- a/test-runner/src/android/test/mock/MockContext.java
+++ b/test-runner/src/android/test/mock/MockContext.java
@@ -98,6 +98,12 @@ public class MockContext extends Context {
throw new UnsupportedOperationException();
}
+ /** @hide */
+ @Override
+ public void recreateTheme() {
+ throw new UnsupportedOperationException();
+ }
+
@Override
public ClassLoader getClassLoader() {
throw new UnsupportedOperationException();
@@ -645,6 +651,19 @@ public class MockContext extends Context {
/** {@hide} */
@Override
+ public Context createPackageContextAsUser(String packageName, String themePackageName,
+ int flags, UserHandle user) throws PackageManager.NameNotFoundException {
+ throw new UnsupportedOperationException();
+ }
+
+ /** {@hide} */
+ public Context createApplicationContext(ApplicationInfo application,
+ String themePackageName, int flags) throws PackageManager.NameNotFoundException {
+ throw new UnsupportedOperationException();
+ }
+
+ /** {@hide} */
+ @Override
public int getUserId() {
throw new UnsupportedOperationException();
}
diff --git a/test-runner/src/android/test/mock/MockPackageManager.java b/test-runner/src/android/test/mock/MockPackageManager.java
index 1ff621a..7aacb23 100644
--- a/test-runner/src/android/test/mock/MockPackageManager.java
+++ b/test-runner/src/android/test/mock/MockPackageManager.java
@@ -510,6 +510,27 @@ public class MockPackageManager extends PackageManager {
throw new UnsupportedOperationException();
}
+ /** @hide */
+ @Override
+ public Resources getThemedResourcesForApplication(ApplicationInfo app, String themePkgName)
+ throws NameNotFoundException {
+ return null;
+ }
+
+ /** @hide */
+ @Override
+ public Resources getThemedResourcesForApplication(String appPackageName, String themePkgName)
+ throws NameNotFoundException {
+ return null;
+ }
+
+ /** @hide */
+ @Override
+ public Resources getThemedResourcesForApplicationAsUser(String appPackageName,
+ String themePkgName, int userId) throws NameNotFoundException {
+ return null;
+ }
+
@Override
public PackageInfo getPackageArchiveInfo(String archiveFilePath, int flags) {
throw new UnsupportedOperationException();
@@ -870,6 +891,13 @@ public class MockPackageManager extends PackageManager {
public boolean isUpgrade() {
throw new UnsupportedOperationException();
}
+ /**
+ * @hide
+ */
+ @Override
+ public void setComponentProtectedSetting(ComponentName componentName, boolean newState) {
+ throw new UnsupportedOperationException();
+ }
/**
* @hide
@@ -942,4 +970,20 @@ public class MockPackageManager extends PackageManager {
public Drawable loadUnbadgedItemIcon(PackageItemInfo itemInfo, ApplicationInfo appInfo) {
throw new UnsupportedOperationException();
}
+
+ /**
+ * @hide
+ */
+ @Override
+ public void updateIconMaps(String pkgName) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public int processThemeResources(String themePkgName) {
+ throw new UnsupportedOperationException();
+ }
}
diff --git a/tests/ThemeTests/cm11_to_cm12/downgrade_to_cm11.sh b/tests/ThemeTests/cm11_to_cm12/downgrade_to_cm11.sh
new file mode 100755
index 0000000..9f8a2c6
--- /dev/null
+++ b/tests/ThemeTests/cm11_to_cm12/downgrade_to_cm11.sh
@@ -0,0 +1,34 @@
+#!/bin/sh
+
+#****************************************************************************************
+# Run this script to move your CM12 device move back to a CM11 state. This is
+# useful when you want to manually test CM11 to CM12 upgrade without reflashing the device
+#***************************************************************************************
+
+#Delete all themes related data
+adb shell sqlite3 /data/data/com.android.providers.settings/databases/settings.db "DELETE FROM secure WHERE name='themeConfig'";
+adb shell sqlite3 /data/data/com.android.providers.settings/databases/settings.db "DELETE FROM secure WHERE name='theme_prev_boot_api_level'";
+adb shell sqlite3 /data/data/com.android.providers.settings/databases/settings.db "pragma user_version=115"
+adb shell sqlite3 /data/data/com.android.providers.settings/databases/settings.db "DELETE FROM secure WHERE name='default_theme_package'"
+adb shell sqlite3 /data/data/com.android.providers.settings/databases/settings.db "DELETE FROM secure WHERE name='default_theme_components'"
+
+#HEXO Config (Comment HOLO if you use this)
+adb shell sqlite3 /data/data/com.android.providers.settings/databases/settings.db "INSERT INTO secure (name,value) VALUES('themeConfig','{\"default\":{\"mOverlayPkgName\":\"com.cyngn.hexo\",\"mIconPkgName\":\"com.tung91.mianogen\",\"mFontPkgName\":\"bigwave.thyrus.darkuinte\"}}')";
+
+#HOLO Config (Comment HEXO if you use this)
+#adb shell sqlite3 /data/data/com.android.providers.settings/databases/settings.db "INSERT INTO secure (name,value) VALUES('themeConfig','{\"default\":{\"mOverlayPkgName\":\"holo\",\"mIconPkgName\":\"com.tung91.mianogen\",\"mFontPkgName\":\"bigwave.thyrus.darkuinte\"}}')";
+
+
+#Default Theme Package
+adb shell sqlite3 /data/data/com.android.providers.settings/databases/settings.db "INSERT INTO secure (name,value) VALUES('default_theme_package', 'com.cyngn.hexo')"
+adb shell 'sqlite3 /data/data/com.android.providers.settings/databases/settings.db "INSERT INTO secure (name,value) VALUES(\"default_theme_components\", \"mods_overlays\")"'
+
+#Print out the db
+adb shell sqlite3 /data/data/com.android.providers.settings/databases/settings.db "SELECT * from secure"
+
+
+#ThemesProvider's default theme is called "Holo"
+adb shell sqlite3 /data/data/org.cyanogenmod.themes.provider/databases/themes.db "UPDATE themes SET pkg_name='holo', title='Holo' WHERE pkg_name='system'"
+adb shell sqlite3 /data/data/org.cyanogenmod.themes.provider/databases/themes.db "pragma user_version=10"
+
+adb shell sqlite3 /data/data/org.cyanogenmod.themes.provider/databases/themes.db "SELECT * FROM themes"
diff --git a/tools/aapt/AaptAssets.cpp b/tools/aapt/AaptAssets.cpp
index d346731..1a5d512 100644
--- a/tools/aapt/AaptAssets.cpp
+++ b/tools/aapt/AaptAssets.cpp
@@ -1048,8 +1048,23 @@ ssize_t AaptAssets::slurpFromArgs(Bundle* bundle)
goto bail;
}
totalCount += count;
- }
- else {
+ } else if (type == kFileTypeRegular) {
+ ZipFile* zip = new ZipFile;
+ status_t err = zip->open(String8(res), ZipFile::kOpenReadOnly);
+ if (err != NO_ERROR) {
+ fprintf(stderr, "error opening zip file %s\n", res);
+ delete zip;
+ totalCount = -1;
+ goto bail;
+ }
+
+ count = current->slurpResourceZip(bundle, zip, res);
+ delete zip;
+ if (count < 0) {
+ totalCount = count;
+ goto bail;
+ }
+ } else {
fprintf(stderr, "ERROR: '%s' is not a directory\n", res);
return UNKNOWN_ERROR;
}
@@ -1214,96 +1229,90 @@ bail:
}
ssize_t
-AaptAssets::slurpResourceZip(Bundle* /* bundle */, const char* filename)
+AaptAssets::slurpResourceZip(Bundle* bundle, ZipFile* zip, const char* fullZipPath)
{
+ status_t err = NO_ERROR;
int count = 0;
SortedVector<AaptGroupEntry> entries;
- ZipFile* zip = new ZipFile;
- status_t err = zip->open(filename, ZipFile::kOpenReadOnly);
- if (err != NO_ERROR) {
- fprintf(stderr, "error opening zip file %s\n", filename);
- count = err;
- delete zip;
- return -1;
- }
-
const int N = zip->getNumEntries();
for (int i=0; i<N; i++) {
ZipEntry* entry = zip->getEntryByIndex(i);
- if (entry->getDeleted()) {
+
+ if (!isEntryValid(bundle, entry)) {
continue;
}
- String8 entryName(entry->getFileName());
+ String8 entryName(entry->getFileName()); //ex: /res/drawable/foo.png
+ String8 entryLeaf = entryName.getPathLeaf(); //ex: foo.png
+ String8 entryDirFull = entryName.getPathDir(); //ex: res/drawable
+ String8 entryDir = entryDirFull.getPathLeaf(); //ex: drawable
- String8 dirName = entryName.getPathDir();
- sp<AaptDir> dir = dirName == "" ? this : makeDir(dirName);
+ err = addEntry(entryName, entryLeaf, entryDirFull, entryDir, String8(fullZipPath), 0);
+ if (err) continue;
- String8 resType;
- AaptGroupEntry kind;
+ count++;
+ }
- String8 remain;
- if (entryName.walkPath(&remain) == kResourceDir) {
- // these are the resources, pull their type out of the directory name
- kind.initFromDirName(remain.walkPath().string(), &resType);
- } else {
- // these are untyped and don't have an AaptGroupEntry
- }
- if (entries.indexOf(kind) < 0) {
- entries.add(kind);
- mGroupEntries.add(kind);
- }
+ return count;
+}
- // use the one from the zip file if they both exist.
- dir->removeFile(entryName.getPathLeaf());
+status_t
+AaptAssets::addEntry(const String8& entryName, const String8& entryLeaf,
+ const String8& /* entryDirFull */, const String8& entryDir,
+ const String8& zipFile, int compressionMethod)
+{
+ AaptGroupEntry group;
+ String8 resType;
+ bool b = group.initFromDirName(entryDir, &resType);
+ if (!b) {
+ fprintf(stderr, "invalid resource directory name: %s\n", entryDir.string());
+ return -1;
+ }
- sp<AaptFile> file = new AaptFile(entryName, kind, resType);
- status_t err = dir->addLeafFile(entryName.getPathLeaf(), file);
- if (err != NO_ERROR) {
- fprintf(stderr, "err=%s entryName=%s\n", strerror(err), entryName.string());
- count = err;
- goto bail;
- }
- file->setCompressionMethod(entry->getCompressionMethod());
+ //This will do a cached lookup as well
+ sp<AaptDir> dir = makeDir(resType); //Does lookup as well on mdirs
+ sp<AaptFile> file = new AaptFile(entryName, group, resType, zipFile);
+ file->setCompressionMethod(compressionMethod);
-#if 0
- if (entryName == "AndroidManifest.xml") {
- printf("AndroidManifest.xml\n");
- }
- printf("\n\nfile: %s\n", entryName.string());
-#endif
-
- size_t len = entry->getUncompressedLen();
- void* data = zip->uncompress(entry);
- void* buf = file->editData(len);
- memcpy(buf, data, len);
-
-#if 0
- const int OFF = 0;
- const unsigned char* p = (unsigned char*)data;
- const unsigned char* end = p+len;
- p += OFF;
- for (int i=0; i<32 && p < end; i++) {
- printf("0x%03x ", i*0x10 + OFF);
- for (int j=0; j<0x10 && p < end; j++) {
- printf(" %02x", *p);
- p++;
- }
- printf("\n");
- }
-#endif
+ dir->addLeafFile(entryLeaf, file);
- free(data);
+ sp<AaptDir> rdir = resDir(resType);
+ if (rdir == NULL) {
+ mResDirs.add(dir);
+ }
- count++;
+ return NO_ERROR;
+}
+
+bool AaptAssets::isEntryValid(Bundle* bundle, ZipEntry* entry) {
+ if (entry == NULL) {
+ return false;
}
-bail:
- delete zip;
- return count;
+ if (entry->getDeleted()) {
+ return false;
+ }
+
+ // Entries that are not inside the internal zip path can be ignored
+ if (bundle->getInternalZipPath()) {
+ bool prefixed = (strncmp(entry->getFileName(),
+ bundle->getInternalZipPath(),
+ strlen(bundle->getInternalZipPath())) == 0);
+ if (!prefixed) {
+ return false;
+ }
+ }
+
+ //Do not process directories
+ if (String8(entry->getFileName()).size() == 0) {
+ return false;
+ }
+
+ return true;
}
+
status_t AaptAssets::filter(Bundle* bundle)
{
WeakResourceFilter reqFilter;
@@ -1530,7 +1539,7 @@ status_t AaptAssets::buildIncludedResources(Bundle* bundle)
printf("Including resources from package: %s\n", includes[i].string());
}
- if (!mIncludedAssets.addAssetPath(includes[i], NULL)) {
+ if (!mIncludedAssets.addAssetPath(includes[i], 0)) {
fprintf(stderr, "ERROR: Asset package include '%s' not found.\n",
includes[i].string());
return UNKNOWN_ERROR;
diff --git a/tools/aapt/AaptAssets.h b/tools/aapt/AaptAssets.h
index 4fdc964..5b66e4e 100644
--- a/tools/aapt/AaptAssets.h
+++ b/tools/aapt/AaptAssets.h
@@ -27,6 +27,8 @@ using namespace android;
extern const char * const gDefaultIgnoreAssets;
extern const char * gUserIgnoreAssets;
+extern bool endsWith(const char* haystack, const char* needle);
+
bool valid_symbol_name(const String8& str);
class AaptAssets;
@@ -146,7 +148,7 @@ class AaptFile : public RefBase
{
public:
AaptFile(const String8& sourceFile, const AaptGroupEntry& groupEntry,
- const String8& resType)
+ const String8& resType, const String8& zipFile=String8(""))
: mGroupEntry(groupEntry)
, mResourceType(resType)
, mSourceFile(sourceFile)
@@ -154,9 +156,11 @@ public:
, mDataSize(0)
, mBufferSize(0)
, mCompression(ZipEntry::kCompressStored)
+ , mZipFile(zipFile)
{
//printf("new AaptFile created %s\n", (const char*)sourceFile);
}
+
virtual ~AaptFile() {
free(mData);
}
@@ -188,6 +192,12 @@ public:
// no compression is ZipEntry::kCompressStored.
int getCompressionMethod() const { return mCompression; }
void setCompressionMethod(int c) { mCompression = c; }
+
+ // ZIP support. In this case the sourceFile is the zip entry name
+ // and zipFile is the path to the zip File.
+ // example: sourceFile = drawable-hdpi/foo.png, zipFile = res.zip
+ const String8& getZipFile() const { return mZipFile; }
+
private:
friend class AaptGroup;
@@ -199,6 +209,7 @@ private:
size_t mDataSize;
size_t mBufferSize;
int mCompression;
+ String8 mZipFile;
};
/**
@@ -540,6 +551,8 @@ public:
void addGroupEntry(const AaptGroupEntry& entry) { mGroupEntries.add(entry); }
ssize_t slurpFromArgs(Bundle* bundle);
+ ssize_t slurpResourceZip(Bundle* bundle, ZipFile* zip, const char* fullZipPath);
+ bool isEntryValid(Bundle* bundle, ZipEntry* entry);
sp<AaptSymbols> getSymbolsFor(const String8& name);
@@ -593,7 +606,11 @@ private:
const bool overwrite=false);
ssize_t slurpResourceTree(Bundle* bundle, const String8& srcDir);
- ssize_t slurpResourceZip(Bundle* bundle, const char* filename);
+
+
+ status_t addEntry(const String8& entryName, const String8& entryLeaf,
+ const String8& entryDirFull, const String8& entryDir,
+ const String8& zipFile, int compressionMethod);
status_t filter(Bundle* bundle);
diff --git a/tools/aapt/AaptConfig.cpp b/tools/aapt/AaptConfig.cpp
index b12867a..fc42b8c 100644
--- a/tools/aapt/AaptConfig.cpp
+++ b/tools/aapt/AaptConfig.cpp
@@ -224,9 +224,20 @@ bool parse(const String8& str, ConfigDescription* out) {
success:
if (out != NULL) {
+#ifndef HAVE_ANDROID_OS
applyVersionForCompatibility(&config);
+#else
+ // Calling applyVersionForCompatibility when compiling a theme can cause
+ // the path to be changed by AAPT which results in the themed assets not being
+ // loaded. The only time (as of right now) that aapt is run on an android device
+ // is when it is being used for themes, so this should be the correct behavior
+ // in this case. If AAPT is ever used on an android device for some other reason,
+ // we will need to change this.
+ printf("AAPT is running on Android, skipping applyVersionForCompatibility");
+#endif
*out = config;
}
+
return true;
}
diff --git a/tools/aapt/Android.mk b/tools/aapt/Android.mk
index b991d55..68c2fe8f 100644
--- a/tools/aapt/Android.mk
+++ b/tools/aapt/Android.mk
@@ -133,5 +133,30 @@ LOCAL_STATIC_LIBRARIES += libaapt $(aaptHostStaticLibs)
include $(BUILD_HOST_NATIVE_TEST)
+# ==========================================================
+# Build the device executable: aapt
+# ==========================================================
+ifneq ($(SDK_ONLY),true)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := aapt
+LOCAL_CFLAGS += $(aaptCFlags)
+LOCAL_SRC_FILES := $(aaptSources) $(aaptMain)
+LOCAL_C_INCLUDES += \
+ $(aaptCIncludes) \
+ bionic
+LOCAL_SHARED_LIBRARIES := \
+ libandroidfw \
+ libutils \
+ libcutils \
+ libpng \
+ liblog \
+ libz
+LOCAL_STATIC_LIBRARIES := \
+ libexpat_static
+
+include $(BUILD_EXECUTABLE)
+
+endif # Not SDK_ONLY
endif # No TARGET_BUILD_APPS or TARGET_BUILD_PDK
diff --git a/tools/aapt/Bundle.h b/tools/aapt/Bundle.h
index cbe7c5d..145eb64 100644
--- a/tools/aapt/Bundle.h
+++ b/tools/aapt/Bundle.h
@@ -1,5 +1,6 @@
//
// Copyright 2006 The Android Open Source Project
+// This code has been modified. Portions copyright (C) 2010, T-Mobile USA, Inc.
//
// State bundle. Used to pass around stuff like command-line args.
//
@@ -49,7 +50,7 @@ public:
Bundle(void)
: mCmd(kCommandUnknown), mVerbose(false), mAndroidList(false),
mForce(false), mGrayscaleTolerance(0), mMakePackageDirs(false),
- mUpdate(false), mExtending(false),
+ mUpdate(false), mExtending(false), mExtendedPackageId(0),
mRequireLocalization(false), mPseudolocalize(NO_PSEUDOLOCALIZATION),
mWantUTF16(false), mValues(false), mIncludeMetaData(false),
mCompressionMethod(0), mJunkPath(false), mOutputAPKFile(NULL),
@@ -65,6 +66,8 @@ public:
mProduct(NULL), mUseCrunchCache(false), mErrorOnFailedInsert(false),
mErrorOnMissingConfigEntry(false), mOutputTextSymbols(NULL),
mSingleCrunchInputFile(NULL), mSingleCrunchOutputFile(NULL),
+ mOutputResourcesApkFile(NULL),
+ mInternalZipPath(NULL), mInputAPKFile(NULL),
mBuildSharedLibrary(false),
mArgc(0), mArgv(NULL)
{}
@@ -94,6 +97,8 @@ public:
void setUpdate(bool val) { mUpdate = val; }
bool getExtending(void) const { return mExtending; }
void setExtending(bool val) { mExtending = val; }
+ int getExtendedPackageId(void) const { return mExtendedPackageId; }
+ void setExtendedPackageId(int val) { mExtendedPackageId = val; }
bool getRequireLocalization(void) const { return mRequireLocalization; }
void setRequireLocalization(bool val) { mRequireLocalization = val; }
short getPseudolocalize(void) const { return mPseudolocalize; }
@@ -109,6 +114,10 @@ public:
void setJunkPath(bool val) { mJunkPath = val; }
const char* getOutputAPKFile() const { return mOutputAPKFile; }
void setOutputAPKFile(const char* val) { mOutputAPKFile = val; }
+ const char* getOutputResApk() { return mOutputResourcesApkFile; }
+ const char* getInputAPKFile() { return mInputAPKFile; }
+ void setInputAPKFile(const char* val) { mInputAPKFile = val; }
+ void setOutputResApk(const char* val) { mOutputResourcesApkFile = val; }
const char* getManifestPackageNameOverride() const { return mManifestPackageNameOverride; }
void setManifestPackageNameOverride(const char * val) { mManifestPackageNameOverride = val; }
const char* getInstrumentationPackageNameOverride() const { return mInstrumentationPackageNameOverride; }
@@ -204,6 +213,8 @@ public:
void setSingleCrunchInputFile(const char* val) { mSingleCrunchInputFile = val; }
const char* getSingleCrunchOutputFile() const { return mSingleCrunchOutputFile; }
void setSingleCrunchOutputFile(const char* val) { mSingleCrunchOutputFile = val; }
+ void setInternalZipPath(const char* val) { mInternalZipPath = val; }
+ const char* getInternalZipPath() const { return mInternalZipPath; }
bool getBuildSharedLibrary() const { return mBuildSharedLibrary; }
void setBuildSharedLibrary(bool val) { mBuildSharedLibrary = val; }
void setNoVersionVectors(bool val) { mNoVersionVectors = val; }
@@ -275,6 +286,7 @@ private:
bool mMakePackageDirs;
bool mUpdate;
bool mExtending;
+ int mExtendedPackageId;
bool mRequireLocalization;
short mPseudolocalize;
bool mWantUTF16;
@@ -326,6 +338,9 @@ private:
const char* mOutputTextSymbols;
const char* mSingleCrunchInputFile;
const char* mSingleCrunchOutputFile;
+ const char* mOutputResourcesApkFile;
+ const char* mInternalZipPath;
+ const char* mInputAPKFile;
bool mBuildSharedLibrary;
android::String8 mPlatformVersionCode;
android::String8 mPlatformVersionName;
diff --git a/tools/aapt/Command.cpp b/tools/aapt/Command.cpp
index 8a0a39c..4c10868 100644
--- a/tools/aapt/Command.cpp
+++ b/tools/aapt/Command.cpp
@@ -2439,21 +2439,48 @@ int doPackage(Bundle* bundle)
goto bail;
}
- // Write the apk
- if (outputAPKFile) {
+ if (outputAPKFile || bundle->getOutputResApk()) {
// Gather all resources and add them to the APK Builder. The builder will then
// figure out which Split they belong in.
err = addResourcesToBuilder(assets, builder);
if (err != NO_ERROR) {
goto bail;
}
+ }
+
+ //Write the res apk
+ if (bundle->getOutputResApk()) {
+ const char* resPath = bundle->getOutputResApk();
+ char *endptr;
+ int resApk_fd = strtol(resPath, &endptr, 10);
+
+ if (*endptr == '\0') {
+ //OutputResDir was a file descriptor
+ //Assume there is only one set of assets, when we deal with actual split apks this may have to change
+ err = writeAPK(bundle, resApk_fd, builder->getBaseSplit(), true);
+ } else {
+ //Assume there is only one set of assets, when we deal with actual split apks this may have to change
+ err = writeAPK(bundle, String8(bundle->getOutputResApk()), builder->getBaseSplit(), true);
+ }
+
+ if (err != NO_ERROR) {
+ fprintf(stderr, "ERROR: writing '%s' failed\n", resPath);
+ goto bail;
+ }
+ }
+
+ // Write the apk
+ if (outputAPKFile) {
+ if (err != NO_ERROR) {
+ goto bail;
+ }
const Vector<sp<ApkSplit> >& splits = builder->getSplits();
const size_t numSplits = splits.size();
for (size_t i = 0; i < numSplits; i++) {
const sp<ApkSplit>& split = splits[i];
String8 outputPath = buildApkName(String8(outputAPKFile), split);
- err = writeAPK(bundle, outputPath, split);
+ err = writeAPK(bundle, outputPath, split, false);
if (err != NO_ERROR) {
fprintf(stderr, "ERROR: packaging of '%s' failed\n", outputPath.string());
goto bail;
diff --git a/tools/aapt/Images.cpp b/tools/aapt/Images.cpp
index e4738f5..6c29ad9 100644
--- a/tools/aapt/Images.cpp
+++ b/tools/aapt/Images.cpp
@@ -27,6 +27,15 @@ png_write_aapt_file(png_structp png_ptr, png_bytep data, png_size_t length)
}
}
+static void
+png_read_mem_file(png_structp png_ptr, png_bytep data, png_size_t length)
+{
+ PngMemoryFile* pngFile = (PngMemoryFile*) png_get_io_ptr(png_ptr);
+ status_t err = pngFile->read(data, length);
+ if (err != NO_ERROR) {
+ png_error(png_ptr, "Read Error");
+ }
+}
static void
png_flush_aapt_file(png_structp /* png_ptr */)
@@ -1269,43 +1278,51 @@ static bool write_png_protected(png_structp write_ptr, String8& printableName, p
return true;
}
-status_t preProcessImage(const Bundle* bundle, const sp<AaptAssets>& /* assets */,
+status_t preProcessImage(const Bundle* bundle, const sp<AaptAssets>& /* assets */, //non-theme path
const sp<AaptFile>& file, String8* /* outNewLeafName */)
{
String8 ext(file->getPath().getPathExtension());
+ bool isImageInZip = !file->getZipFile().isEmpty();
// We currently only process PNG images.
if (strcmp(ext.string(), ".png") != 0) {
return NO_ERROR;
}
+ String8 printableName(file->getPrintableSource());
+
+ // We currently only process nine patch PNG images when building a theme apk.
+ Bundle* b = const_cast<Bundle*>(bundle);
+ if (!endsWith(printableName.string(), ".9.png") && b->getOutputResApk() != NULL) {
+ if (bundle->getVerbose()) {
+ printf("Skipping image: %s\n", file->getPrintableSource().string());
+ }
+ return NO_ERROR;
+ }
+
// Example of renaming a file:
//*outNewLeafName = file->getPath().getBasePath().getFileName();
//outNewLeafName->append(".nupng");
- String8 printableName(file->getPrintableSource());
-
if (bundle->getVerbose()) {
printf("Processing image: %s\n", printableName.string());
}
png_structp read_ptr = NULL;
png_infop read_info = NULL;
- FILE* fp;
+ FILE* fp = NULL;
image_info imageInfo;
png_structp write_ptr = NULL;
png_infop write_info = NULL;
- status_t error = UNKNOWN_ERROR;
+ PngMemoryFile* pmf = NULL;
+ ZipFile* zip = NULL;
- fp = fopen(file->getSourceFile().string(), "rb");
- if (fp == NULL) {
- fprintf(stderr, "%s: ERROR: Unable to open PNG file\n", printableName.string());
- goto bail;
- }
+ status_t error = UNKNOWN_ERROR;
+ const size_t nameLen = file->getPath().length();
read_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, (png_error_ptr)NULL,
(png_error_ptr)NULL);
if (!read_ptr) {
@@ -1317,8 +1334,46 @@ status_t preProcessImage(const Bundle* bundle, const sp<AaptAssets>& /* assets *
goto bail;
}
- if (!read_png_protected(read_ptr, printableName, read_info, file, fp, &imageInfo)) {
- goto bail;
+ if (isImageInZip) {
+ pmf = new PngMemoryFile();
+ zip = new ZipFile;
+ status_t err = zip->open(file->getZipFile(), ZipFile::kOpenReadOnly);
+ if (NO_ERROR != err) {
+ fprintf(stderr, "ERROR: Unable to open %s\n", file->getZipFile().string());
+ goto bail;
+ }
+
+ ZipEntry* entry = zip->getEntryByName(file->getSourceFile().string());
+ size_t len = entry->getUncompressedLen();
+ void* data = zip->uncompress(entry);
+ void* buf = file->editData(len);
+ memcpy(buf, data, len);
+ free(data);
+
+ pmf->setDataSource((const char*)file->getData(), file->getSize());
+ png_set_read_fn(read_ptr, pmf, png_read_mem_file);
+ read_png(printableName.string(), read_ptr, read_info, &imageInfo);
+ if (nameLen > 6) {
+ const char* name = file->getPath().string();
+ if (name[nameLen-5] == '9' && name[nameLen-6] == '.') {
+ if (do_9patch(printableName.string(), &imageInfo) != NO_ERROR) {
+ goto bail;
+ }
+ }
+ }
+ } else {
+ fp = fopen(file->getSourceFile().string(), "rb");
+ if (fp == NULL) {
+ fprintf(stderr, "%s: ERROR: Unable to open PNG file\n", printableName.string());
+ goto bail;
+ }
+ if (!read_png_protected(read_ptr, printableName, read_info, file, fp, &imageInfo)) {
+ goto bail;
+ }
+ }
+
+ if (isImageInZip) {
+ file->clearData();
}
write_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, (png_error_ptr)NULL,
@@ -1343,13 +1398,15 @@ status_t preProcessImage(const Bundle* bundle, const sp<AaptAssets>& /* assets *
error = NO_ERROR;
- if (bundle->getVerbose()) {
+ if (bundle->getVerbose() && !isImageInZip) {
fseek(fp, 0, SEEK_END);
size_t oldSize = (size_t)ftell(fp);
size_t newSize = file->getSize();
float factor = ((float)newSize)/oldSize;
int percent = (int)(factor*100);
printf(" (processed image %s: %d%% size of source)\n", printableName.string(), percent);
+ } else if (bundle->getVerbose() && isImageInZip) {
+ printf(" (processed image %s)\n", printableName.string());
}
bail:
@@ -1362,6 +1419,12 @@ bail:
if (write_ptr) {
png_destroy_write_struct(&write_ptr, &write_info);
}
+ if (zip) {
+ delete zip;
+ }
+ if (pmf) {
+ delete pmf;
+ }
if (error != NO_ERROR) {
fprintf(stderr, "ERROR: Failure processing PNG image %s\n",
@@ -1375,7 +1438,7 @@ status_t preProcessImageToCache(const Bundle* bundle, const String8& source, con
png_structp read_ptr = NULL;
png_infop read_info = NULL;
- FILE* fp;
+ FILE*volatile fp;
image_info imageInfo;
@@ -1511,3 +1574,17 @@ status_t postProcessImage(const Bundle* bundle, const sp<AaptAssets>& assets,
return NO_ERROR;
}
+
+status_t PngMemoryFile::read(png_bytep data, png_size_t length) {
+ if (data == NULL)
+ return -1;
+
+ if ((mIndex + length) >= mDataSize) {
+ length = mDataSize - mIndex;
+ }
+
+ memcpy(data, mData + mIndex, length);
+ mIndex += length;
+
+ return NO_ERROR;
+}
diff --git a/tools/aapt/Images.h b/tools/aapt/Images.h
index a0a94f8..3230ddc 100644
--- a/tools/aapt/Images.h
+++ b/tools/aapt/Images.h
@@ -10,6 +10,8 @@
#include "ResourceTable.h"
#include "Bundle.h"
+#include <png.h>
+
#include <utils/String8.h>
#include <utils/RefBase.h>
@@ -23,4 +25,18 @@ status_t preProcessImageToCache(const Bundle* bundle, const String8& source, con
status_t postProcessImage(const Bundle* bundle, const sp<AaptAssets>& assets,
ResourceTable* table, const sp<AaptFile>& file);
+class PngMemoryFile {
+public:
+ PngMemoryFile(void)
+ : mData(NULL), mDataSize(0), mIndex(0)
+ {}
+ void setDataSource(const char* data, uint32_t size) { mData = data; mDataSize = size; mIndex = 0; }
+ status_t read(png_bytep data, png_size_t length);
+
+private:
+ const char* mData;
+ uint32_t mDataSize;
+ uint32_t mIndex;
+};
+
#endif
diff --git a/tools/aapt/Main.cpp b/tools/aapt/Main.cpp
index f832c60..aa67480 100644
--- a/tools/aapt/Main.cpp
+++ b/tools/aapt/Main.cpp
@@ -1,5 +1,6 @@
//
// Copyright 2006 The Android Open Source Project
+// This code has been modified. Portions copyright (C) 2010, T-Mobile USA, Inc.
//
// Android Asset Packaging Tool main entry point.
//
@@ -14,6 +15,7 @@
#include <cstdlib>
#include <getopt.h>
#include <cassert>
+#include <ctype.h>
using namespace android;
@@ -56,7 +58,7 @@ void usage(void)
" xmltree Print the compiled xmls in the given assets.\n"
" xmlstrings Print the strings of the given compiled xml assets.\n\n", gProgName);
fprintf(stderr,
- " %s p[ackage] [-d][-f][-m][-u][-v][-x][-z][-M AndroidManifest.xml] \\\n"
+ " %s p[ackage] [-d][-f][-m][-u][-v][-x[ extending-resource-id]][-z][-M AndroidManifest.xml] \\\n"
" [-0 extension [-0 extension ...]] [-g tolerance] [-j jarfile] \\\n"
" [--debug-mode] [--min-sdk-version VAL] [--target-sdk-version VAL] \\\n"
" [--app-version VAL] [--app-version-name TEXT] [--custom-package VAL] \\\n"
@@ -114,7 +116,7 @@ void usage(void)
" -m make package directories under location specified by -J\n"
" -u update existing packages (add new, replace older, remove deleted files)\n"
" -v verbose output\n"
- " -x create extending (non-application) resource IDs\n"
+ " -x either create or assign (if specified) extending (non-application) resource IDs\n"
" -z require localization of resource attributes marked with\n"
" localization=\"suggested\"\n"
" -A additional directory in which to find raw asset files\n"
@@ -347,6 +349,14 @@ int main(int argc, char* const argv[])
break;
case 'x':
bundle.setExtending(true);
+ argc--;
+ argv++;
+ if (!argc || !isdigit(argv[0][0])) {
+ argc++;
+ argv--;
+ } else {
+ bundle.setExtendedPackageId(atoi(argv[0]));
+ }
break;
case 'z':
bundle.setRequireLocalization(true);
@@ -428,6 +438,17 @@ int main(int argc, char* const argv[])
convertPath(argv[0]);
bundle.setAndroidManifestFile(argv[0]);
break;
+ case 'X':
+ argc--;
+ argv++;
+ if (!argc) {
+ fprintf(stderr, "ERROR: No argument supplied for '-X' option\n");
+ wantUsage = true;
+ goto bail;
+ }
+ convertPath(argv[0]);
+ bundle.setInternalZipPath(argv[0]);
+ break;
case 'P':
argc--;
argv++;
@@ -497,6 +518,28 @@ int main(int argc, char* const argv[])
bundle.setCompressionMethod(ZipEntry::kCompressStored);
}
break;
+ case 'Z':
+ argc--;
+ argv++;
+ if (!argc) {
+ fprintf(stderr, "ERROR: No argument supplied for '-Z' option\n");
+ wantUsage = true;
+ goto bail;
+ }
+ convertPath(argv[0]);
+ bundle.setInputAPKFile(argv[0]);
+ break;
+ case 'r':
+ argc--;
+ argv++;
+ if (!argc) {
+ fprintf(stderr, "ERROR: No argument supplied for '-r' option\n");
+ wantUsage = true;
+ goto bail;
+ }
+ convertPath(argv[0]);
+ bundle.setOutputResApk(argv[0]);
+ break;
case '-':
if (strcmp(cp, "-debug-mode") == 0) {
bundle.setDebugMode(true);
diff --git a/tools/aapt/Main.h b/tools/aapt/Main.h
index e84c4c5..0b8adbe 100644
--- a/tools/aapt/Main.h
+++ b/tools/aapt/Main.h
@@ -42,7 +42,14 @@ extern int calcPercent(long uncompressedLen, long compressedLen);
extern android::status_t writeAPK(Bundle* bundle,
const android::String8& outputFile,
- const android::sp<OutputSet>& outputSet);
+ const android::sp<OutputSet>& outputSet,
+ bool isOverlay);
+extern android::status_t writeAPK(Bundle* bundle,
+ int fd,
+ const android::sp<OutputSet>& outputSet,
+ bool isOverlay);
+extern android::status_t writeResFile(FILE* fp, const sp<AaptAssets>& assets, sp<ApkBuilder>& builder);
+extern sp<AaptFile> getResourceFile(const sp<AaptAssets>& assets, bool makeIfNecessary=true);
extern android::status_t updatePreProcessedCache(Bundle* bundle);
diff --git a/tools/aapt/Package.cpp b/tools/aapt/Package.cpp
index cb244ec..3daf644 100644
--- a/tools/aapt/Package.cpp
+++ b/tools/aapt/Package.cpp
@@ -37,8 +37,10 @@ static const char* kNoCompressExt[] = {
};
/* fwd decls, so I can write this downward */
-ssize_t processAssets(Bundle* bundle, ZipFile* zip, const sp<const OutputSet>& outputSet);
bool processFile(Bundle* bundle, ZipFile* zip, String8 storageName, const sp<const AaptFile>& file);
+ssize_t processAssets(Bundle* bundle, ZipFile* zip, const sp<const OutputSet>& outputSet, bool isOverlay);
+bool processOverlayFile(Bundle* bundle, ZipFile* zip,
+ String8 storageName, const sp<const AaptFile>& file);
bool okayToCompress(Bundle* bundle, const String8& pathName);
ssize_t processJarFiles(Bundle* bundle, ZipFile* zip);
@@ -49,7 +51,81 @@ ssize_t processJarFiles(Bundle* bundle, ZipFile* zip);
* On success, "bundle->numPackages" will be the number of Zip packages
* we created.
*/
-status_t writeAPK(Bundle* bundle, const String8& outputFile, const sp<OutputSet>& outputSet)
+status_t writeAPK(Bundle* bundle, ZipFile* zip, const char* outputFileName,
+ const sp<OutputSet>& outputSet, bool isOverlay)
+{
+ status_t result = NO_ERROR;
+ int count;
+
+ if (bundle->getVerbose()) {
+ printf("Writing all files...\n");
+ }
+
+ count = processAssets(bundle, zip, outputSet, isOverlay);
+ if (count < 0) {
+ fprintf(stderr, "ERROR: unable to process assets while packaging '%s'\n",
+ outputFileName);
+ result = count;
+ goto bail;
+ }
+
+ if (bundle->getVerbose()) {
+ printf("Generated %d file%s\n", count, (count==1) ? "" : "s");
+ }
+
+ if (!isOverlay) {
+ count = processJarFiles(bundle, zip);
+ if (count < 0) {
+ fprintf(stderr, "ERROR: unable to process jar files while packaging '%s'\n",
+ outputFileName);
+ result = count;
+ goto bail;
+ }
+
+ if (bundle->getVerbose())
+ printf("Included %d file%s from jar/zip files.\n", count, (count==1) ? "" : "s");
+ }
+
+ result = NO_ERROR;
+
+ /*
+ * Check for cruft. We set the "marked" flag on all entries we created
+ * or decided not to update. If the entry isn't already slated for
+ * deletion, remove it now.
+ */
+ {
+ if (bundle->getVerbose())
+ printf("Checking for deleted files\n");
+ int i, removed = 0;
+ for (i = 0; i < zip->getNumEntries(); i++) {
+ ZipEntry* entry = zip->getEntryByIndex(i);
+
+ if (!entry->getMarked() && entry->getDeleted()) {
+ if (bundle->getVerbose()) {
+ printf(" (removing crufty '%s')\n",
+ entry->getFileName());
+ }
+ zip->remove(entry);
+ removed++;
+ }
+ }
+ if (bundle->getVerbose() && removed > 0)
+ printf("Removed %d file%s\n", removed, (removed==1) ? "" : "s");
+ }
+
+ /* tell Zip lib to process deletions and other pending changes */
+ result = zip->flush();
+ if (result != NO_ERROR) {
+ fprintf(stderr, "ERROR: Zip flush failed, archive may be hosed\n");
+ goto bail;
+ }
+
+bail:
+ return result;
+}
+
+status_t writeAPK(Bundle* bundle, const String8& outputFile,
+ const sp<OutputSet>& outputSet, bool isOverlay)
{
#if BENCHMARK
fprintf(stdout, "BENCHMARK: Starting APK Bundling \n");
@@ -58,7 +134,6 @@ status_t writeAPK(Bundle* bundle, const String8& outputFile, const sp<OutputSet>
status_t result = NO_ERROR;
ZipFile* zip = NULL;
- int count;
//bundle->setPackageCount(0);
@@ -105,64 +180,10 @@ status_t writeAPK(Bundle* bundle, const String8& outputFile, const sp<OutputSet>
goto bail;
}
- if (bundle->getVerbose()) {
- printf("Writing all files...\n");
- }
-
- count = processAssets(bundle, zip, outputSet);
- if (count < 0) {
- fprintf(stderr, "ERROR: unable to process assets while packaging '%s'\n",
- outputFile.string());
- result = count;
- goto bail;
- }
-
- if (bundle->getVerbose()) {
- printf("Generated %d file%s\n", count, (count==1) ? "" : "s");
- }
-
- count = processJarFiles(bundle, zip);
- if (count < 0) {
- fprintf(stderr, "ERROR: unable to process jar files while packaging '%s'\n",
- outputFile.string());
- result = count;
- goto bail;
- }
-
- if (bundle->getVerbose())
- printf("Included %d file%s from jar/zip files.\n", count, (count==1) ? "" : "s");
-
- result = NO_ERROR;
+ result = writeAPK(bundle, zip, outputFile.string(), outputSet, isOverlay);
- /*
- * Check for cruft. We set the "marked" flag on all entries we created
- * or decided not to update. If the entry isn't already slated for
- * deletion, remove it now.
- */
- {
- if (bundle->getVerbose())
- printf("Checking for deleted files\n");
- int i, removed = 0;
- for (i = 0; i < zip->getNumEntries(); i++) {
- ZipEntry* entry = zip->getEntryByIndex(i);
-
- if (!entry->getMarked() && entry->getDeleted()) {
- if (bundle->getVerbose()) {
- printf(" (removing crufty '%s')\n",
- entry->getFileName());
- }
- zip->remove(entry);
- removed++;
- }
- }
- if (bundle->getVerbose() && removed > 0)
- printf("Removed %d file%s\n", removed, (removed==1) ? "" : "s");
- }
-
- /* tell Zip lib to process deletions and other pending changes */
- result = zip->flush();
if (result != NO_ERROR) {
- fprintf(stderr, "ERROR: Zip flush failed, archive may be hosed\n");
+ fprintf(stderr, "ERROR: Writing apk failed\n");
goto bail;
}
@@ -215,7 +236,98 @@ bail:
return result;
}
-ssize_t processAssets(Bundle* bundle, ZipFile* zip, const sp<const OutputSet>& outputSet)
+/*
+ * The directory hierarchy looks like this:
+ * "outputDir" and "assetRoot" are existing directories.
+ *
+ * On success, "bundle->numPackages" will be the number of Zip packages
+ * we created.
+ */
+status_t writeAPK(Bundle* bundle, int fd, const sp<OutputSet>& outputSet, bool isOverlay)
+{
+ #if BENCHMARK
+ fprintf(stdout, "BENCHMARK: Starting APK Bundling \n");
+ long startAPKTime = clock();
+ #endif /* BENCHMARK */
+
+ status_t result = NO_ERROR;
+ ZipFile* zip = NULL;
+
+ status_t status;
+ zip = new ZipFile;
+ status = zip->openfd(fd, ZipFile::kOpenReadWrite);
+ if (status != NO_ERROR) {
+ fprintf(stderr, "ERROR: unable to open file as Zip file for writing\n");
+ result = PERMISSION_DENIED;
+ goto bail;
+ }
+
+ result = writeAPK(bundle, zip, "file_descriptor", outputSet, isOverlay);
+
+ if (result != NO_ERROR) {
+ fprintf(stderr, "ERROR: Writing apk failed\n");
+ goto bail;
+ }
+
+ /* anything here? */
+ if (zip->getNumEntries() == 0) {
+ if (bundle->getVerbose()) {
+ printf("Archive is empty -- removing\n");
+ }
+ delete zip; // close the file so we can remove it in Win32
+ zip = NULL;
+ close(fd);
+ }
+
+ assert(result == NO_ERROR);
+
+bail:
+ delete zip; // must close before remove in Win32
+ close(fd);
+ if (result != NO_ERROR) {
+ if (bundle->getVerbose()) {
+ printf("Removing archive due to earlier failures\n");
+ }
+ }
+
+ if (result == NO_ERROR && bundle->getVerbose())
+ printf("Done!\n");
+
+ #if BENCHMARK
+ fprintf(stdout, "BENCHMARK: End APK Bundling. Time Elapsed: %f ms \n",(clock() - startAPKTime)/1000.0);
+ #endif /* BENCHMARK */
+ return result;
+}
+
+status_t writeResFile(FILE* fp, const sp<AaptAssets>& /* assets */, sp<ApkBuilder>& builder) {
+ if (fp == NULL) {
+ fprintf(stderr, "Unable to open resFile for writing resTable\n");
+ return PERMISSION_DENIED;
+ }
+
+ sp<ApkSplit> split = builder->getBaseSplit();
+ const std::set<OutputEntry>& entries = split->getEntries();
+ std::set<OutputEntry>::const_iterator iter = entries.begin();
+ for (; iter != entries.end(); iter++) {
+ const OutputEntry& entry = *iter;
+
+ if (entry.getPath() == String8("resources.arsc")) {
+ sp<const AaptFile> resFile = entry.getFile();
+
+ int count = 0;
+ count = fwrite(resFile->getData(), 1, resFile->getSize(), fp);
+
+ if (count == 0) {
+ fprintf(stderr, "Nothing written to resFile\n");
+ }
+ }
+ }
+
+ return NO_ERROR;
+}
+
+ssize_t processAssets(Bundle* bundle, ZipFile* zip, const sp<const OutputSet>& outputSet,
+ bool isOverlay)
{
ssize_t count = 0;
const std::set<OutputEntry>& entries = outputSet->getEntries();
@@ -227,7 +339,9 @@ ssize_t processAssets(Bundle* bundle, ZipFile* zip, const sp<const OutputSet>& o
} else {
String8 storagePath(entry.getPath());
storagePath.convertToResPath();
- if (!processFile(bundle, zip, storagePath, entry.getFile())) {
+ bool ret = isOverlay ? processOverlayFile(bundle, zip, storagePath, entry.getFile())
+ : processFile(bundle, zip, storagePath, entry.getFile());
+ if (!ret) {
return UNKNOWN_ERROR;
}
count++;
@@ -360,6 +474,76 @@ bool processFile(Bundle* bundle, ZipFile* zip,
}
/*
+ * Process a regular file, adding it to the archive if appropriate.
+ *
+ * This function is intended for use when creating a cached overlay package.
+ * Only xml and .9.png files are processed and added to the package.
+ *
+ * If we're in "update" mode, and the file already exists in the archive,
+ * delete the existing entry before adding the new one.
+ */
+bool processOverlayFile(Bundle* bundle, ZipFile* zip,
+ String8 storageName, const sp<const AaptFile>& file)
+{
+ const bool hasData = file->hasData();
+
+ storageName.convertToResPath();
+ ZipEntry* entry;
+ bool fromGzip = false;
+ status_t result;
+
+ if (strcasecmp(storageName.getPathExtension().string(), ".gz") == 0) {
+ fromGzip = true;
+ storageName = storageName.getBasePath();
+ }
+
+ if (bundle->getUpdate()) {
+ entry = zip->getEntryByName(storageName.string());
+ if (entry != NULL) {
+ /* file already exists in archive; there can be only one */
+ if (entry->getMarked()) {
+ fprintf(stderr,
+ "ERROR: '%s' exists twice (check for with & w/o '.gz'?)\n",
+ file->getPrintableSource().string());
+ return false;
+ }
+ zip->remove(entry);
+ }
+ }
+
+ if (hasData) {
+ const char* name = storageName.string();
+ if (endsWith(name, ".9.png") || endsWith(name, ".xml") || endsWith(name, ".arsc")) {
+ result = zip->add(file->getData(), file->getSize(), storageName.string(),
+ file->getCompressionMethod(), &entry);
+ if (result == NO_ERROR) {
+ if (bundle->getVerbose()) {
+ printf(" '%s'%s", storageName.string(), fromGzip ? " (from .gz)" : "");
+ if (entry->getCompressionMethod() == ZipEntry::kCompressStored) {
+ printf(" (not compressed)\n");
+ } else {
+ printf(" (compressed %d%%)\n", calcPercent(entry->getUncompressedLen(),
+ entry->getCompressedLen()));
+ }
+ }
+ entry->setMarked(true);
+ } else {
+ if (result == ALREADY_EXISTS) {
+ fprintf(stderr, " Unable to add '%s': file already in archive (try '-u'?)\n",
+ file->getPrintableSource().string());
+ } else {
+ fprintf(stderr, " Unable to add '%s': Zip add failed\n",
+ file->getPrintableSource().string());
+ }
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+/*
* Determine whether or not we want to try to compress this file based
* on the file extension.
*/
diff --git a/tools/aapt/Resource.cpp b/tools/aapt/Resource.cpp
index 5d20815..c636c28 100644
--- a/tools/aapt/Resource.cpp
+++ b/tools/aapt/Resource.cpp
@@ -221,6 +221,24 @@ bool isValidResourceType(const String8& type)
|| type == "color" || type == "menu" || type == "mipmap";
}
+sp<AaptFile> getResourceFile(const sp<AaptAssets>& assets, bool makeIfNecessary)
+{
+ sp<AaptGroup> group = assets->getFiles().valueFor(String8("resources.arsc"));
+ sp<AaptFile> file;
+ if (group != NULL) {
+ file = group->getFiles().valueFor(AaptGroupEntry());
+ if (file != NULL) {
+ return file;
+ }
+ }
+
+ if (!makeIfNecessary) {
+ return NULL;
+ }
+ return assets->addFile(String8("resources.arsc"), AaptGroupEntry(), String8(),
+ NULL, String8());
+}
+
static status_t parsePackage(Bundle* bundle, const sp<AaptAssets>& assets,
const sp<AaptGroup>& grp)
{
@@ -1170,7 +1188,9 @@ status_t buildResources(Bundle* bundle, const sp<AaptAssets>& assets, sp<ApkBuil
packageType = ResourceTable::AppFeature;
}
- ResourceTable table(bundle, String16(assets->getPackage()), packageType);
+ int extendedPackageId = bundle->getExtendedPackageId();
+
+ ResourceTable table(bundle, String16(assets->getPackage()), packageType, extendedPackageId);
err = table.addIncludedResources(bundle, assets);
if (err != NO_ERROR) {
return err;
@@ -1252,7 +1272,7 @@ status_t buildResources(Bundle* bundle, const sp<AaptAssets>& assets, sp<ApkBuil
bool hasErrors = false;
if (drawables != NULL) {
- if (bundle->getOutputAPKFile() != NULL) {
+ if (bundle->getOutputAPKFile() != NULL || bundle->getOutputResApk()) {
err = preProcessImages(bundle, assets, drawables, "drawable");
}
if (err == NO_ERROR) {
diff --git a/tools/aapt/ResourceTable.cpp b/tools/aapt/ResourceTable.cpp
index d5a09d8..889883a 100644
--- a/tools/aapt/ResourceTable.cpp
+++ b/tools/aapt/ResourceTable.cpp
@@ -1753,7 +1753,7 @@ status_t compileResourceFile(Bundle* bundle,
return hasErrors ? STATUST(UNKNOWN_ERROR) : NO_ERROR;
}
-ResourceTable::ResourceTable(Bundle* bundle, const String16& assetsPackage, ResourceTable::PackageType type)
+ResourceTable::ResourceTable(Bundle* bundle, const String16& assetsPackage, ResourceTable::PackageType type, ssize_t pkgIdOverride)
: mAssetsPackage(assetsPackage)
, mPackageType(type)
, mTypeIdOffset(0)
@@ -1779,6 +1779,11 @@ ResourceTable::ResourceTable(Bundle* bundle, const String16& assetsPackage, Reso
assert(0);
break;
}
+
+ if (pkgIdOverride != 0) {
+ packageId = pkgIdOverride;
+ }
+
sp<Package> package = new Package(mAssetsPackage, packageId);
mPackages.add(assetsPackage, package);
mOrderedPackages.add(package);
@@ -2825,8 +2830,9 @@ status_t ResourceTable::flatten(Bundle* bundle, const sp<const ResourceFilter>&
for (size_t i = 0; i < basePackageCount; i++) {
size_t packageId = table.getBasePackageId(i);
String16 packageName(table.getBasePackageName(i));
- if (packageId > 0x01 && packageId != 0x7f &&
- packageName != String16("android")) {
+ if (packageId > 0x01 && packageId != 0x7f && packageId != 0x3f &&
+ packageName != String16("android")
+ && packageName != String16("cyanogenmod.platform")) {
libraryPackages.add(sp<Package>(new Package(packageName, packageId)));
}
}
diff --git a/tools/aapt/ResourceTable.h b/tools/aapt/ResourceTable.h
index c4bdf09..2c2df19 100644
--- a/tools/aapt/ResourceTable.h
+++ b/tools/aapt/ResourceTable.h
@@ -109,7 +109,8 @@ public:
const ConfigDescription& sourceConfig,
const int sdkVersionToGenerate);
- ResourceTable(Bundle* bundle, const String16& assetsPackage, PackageType type);
+ ResourceTable(Bundle* bundle, const String16& assetsPackage, PackageType type,
+ ssize_t pkgIdOverride);
const String16& getAssetsPackage() const {
return mAssetsPackage;
diff --git a/tools/aapt/XMLNode.cpp b/tools/aapt/XMLNode.cpp
index ca3f687..6ab55d5 100644
--- a/tools/aapt/XMLNode.cpp
+++ b/tools/aapt/XMLNode.cpp
@@ -11,6 +11,7 @@
#include <utils/ByteOrder.h>
#include <errno.h>
#include <string.h>
+#include <androidfw/AssetManager.h>
#ifndef HAVE_MS_C_RUNTIME
#define O_BINARY 0
@@ -583,9 +584,51 @@ status_t parseXMLResource(const sp<AaptFile>& file, ResXMLTree* outTree,
return NO_ERROR;
}
+sp<XMLNode> XMLNode::parseFromZip(const sp<AaptFile>& file) {
+ AssetManager assets;
+ int32_t cookie;
+
+ if (!assets.addAssetPath(file->getZipFile(), &cookie)) {
+ fprintf(stderr, "Error: Could not open path %s\n", file->getZipFile().string());
+ return NULL;
+ }
+
+ Asset* asset = assets.openNonAsset(cookie, file->getSourceFile(), Asset::ACCESS_BUFFER);
+ ssize_t len = asset->getLength();
+ const void* buf = asset->getBuffer(false);
+
+ XML_Parser parser = XML_ParserCreateNS(NULL, 1);
+ ParseState state;
+ state.filename = file->getPrintableSource();
+ state.parser = parser;
+ XML_SetUserData(parser, &state);
+ XML_SetElementHandler(parser, startElement, endElement);
+ XML_SetNamespaceDeclHandler(parser, startNamespace, endNamespace);
+ XML_SetCharacterDataHandler(parser, characterData);
+ XML_SetCommentHandler(parser, commentData);
+
+ bool done = true;
+ if (XML_Parse(parser, (char*) buf, len, done) == XML_STATUS_ERROR) {
+ SourcePos(file->getSourceFile(), (int)XML_GetCurrentLineNumber(parser)).error(
+ "Error parsing XML: %s\n", XML_ErrorString(XML_GetErrorCode(parser)));
+ return NULL;
+ }
+ XML_ParserFree(parser);
+ if (state.root == NULL) {
+ SourcePos(file->getSourceFile(), -1).error("No XML data generated when parsing");
+ }
+ return state.root;
+}
+
sp<XMLNode> XMLNode::parse(const sp<AaptFile>& file)
{
char buf[16384];
+
+ //Check for zip first
+ if (file->getZipFile().length() > 0) {
+ return parseFromZip(file);
+ }
+
int fd = open(file->getSourceFile().string(), O_RDONLY | O_BINARY);
if (fd < 0) {
SourcePos(file->getSourceFile(), -1).error("Unable to open file for read: %s",
diff --git a/tools/aapt/XMLNode.h b/tools/aapt/XMLNode.h
index 3161f65..905c6fd 100644
--- a/tools/aapt/XMLNode.h
+++ b/tools/aapt/XMLNode.h
@@ -188,6 +188,9 @@ private:
status_t flatten_node(const StringPool& strings, const sp<AaptFile>& dest,
bool stripComments, bool stripRawValues) const;
+ static sp<XMLNode> parseFromZip(const sp<AaptFile>& file);
+ static sp<XMLNode> parseFromAsset(const Asset& asset);
+
String16 mNamespacePrefix;
String16 mNamespaceUri;
String16 mElementName;
diff --git a/tools/aapt/ZipFile.cpp b/tools/aapt/ZipFile.cpp
index 36f4e73..8a4eef5 100644
--- a/tools/aapt/ZipFile.cpp
+++ b/tools/aapt/ZipFile.cpp
@@ -130,6 +130,71 @@ status_t ZipFile::open(const char* zipFileName, int flags)
}
/*
+ * Open a file and parse its guts.
+ */
+status_t ZipFile::openfd(int fd, int flags)
+{
+ bool newArchive = true;
+
+ assert(mZipFp == NULL); // no reopen
+
+ if ((flags & kOpenTruncate))
+ flags |= kOpenCreate; // trunc implies create
+
+ if ((flags & kOpenReadOnly) && (flags & kOpenReadWrite))
+ return INVALID_OPERATION; // not both
+ if (!((flags & kOpenReadOnly) || (flags & kOpenReadWrite)))
+ return INVALID_OPERATION; // not neither
+ if ((flags & kOpenCreate) && !(flags & kOpenReadWrite))
+ return INVALID_OPERATION; // create requires write
+
+ /* open the file */
+ const char* openflags;
+ if (flags & kOpenReadWrite) {
+ if (newArchive)
+ openflags = FILE_OPEN_RW_CREATE;
+ else
+ openflags = FILE_OPEN_RW;
+ } else {
+ openflags = FILE_OPEN_RO;
+ }
+ mZipFp = fdopen(fd, openflags);
+ if (mZipFp == NULL) {
+ int err = errno;
+ ALOGD("fdopen failed: %s\n", strerror(err));
+ return errnoToStatus(err);
+ }
+
+ status_t result;
+ if (!newArchive) {
+ /*
+ * Load the central directory. If that fails, then this probably
+ * isn't a Zip archive.
+ */
+ result = readCentralDir();
+ } else {
+ /*
+ * Newly-created. The EndOfCentralDir constructor actually
+ * sets everything to be the way we want it (all zeroes). We
+ * set mNeedCDRewrite so that we create *something* if the
+ * caller doesn't add any files. (We could also just unlink
+ * the file if it's brand new and nothing was added, but that's
+ * probably doing more than we really should -- the user might
+ * have a need for empty zip files.)
+ */
+ mNeedCDRewrite = true;
+ result = NO_ERROR;
+ }
+
+ if (flags & kOpenReadOnly)
+ mReadOnly = true;
+ else
+ assert(!mReadOnly);
+
+ return result;
+}
+
+/*
* Return the Nth entry in the archive.
*/
ZipEntry* ZipFile::getEntryByIndex(int idx) const
diff --git a/tools/aapt/ZipFile.h b/tools/aapt/ZipFile.h
index 7877550..d5abbf1 100644
--- a/tools/aapt/ZipFile.h
+++ b/tools/aapt/ZipFile.h
@@ -64,6 +64,7 @@ public:
kOpenTruncate = 0x08, // if it exists, empty it
};
status_t open(const char* zipFileName, int flags);
+ status_t openfd(int fd, int flags);
/*
* Add a file to the end of the archive. Specify whether you want the
diff --git a/tools/aapt/tests/ZipReading_test.cpp b/tools/aapt/tests/ZipReading_test.cpp
new file mode 100644
index 0000000..4b4f2da
--- /dev/null
+++ b/tools/aapt/tests/ZipReading_test.cpp
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2014 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.
+ */
+
+#include <utils/String8.h>
+#include <gtest/gtest.h>
+#include <gmock/gmock.h>
+#include <utils/KeyedVector.h>
+
+#include "mocks/MockZipFile.h"
+#include "mocks/MockZipEntry.h"
+
+#include "AaptConfig.h"
+#include "ConfigDescription.h"
+#include "TestHelper.h"
+
+#include "AaptAssets.h"
+
+using android::String8;
+using namespace testing;
+
+// A path to an apk that would be considered valid
+#define VALID_APK_FILE "/valid/valid.apk"
+
+// Internal zip path to a dir that aapt is being asked to compile
+#define COMPILING_OVERLAY_DIR "/assets/overlays/com.interesting.app"
+
+// Internal zip path to a valid resource. aapt is expected to compile this resource.
+#define COMPILING_OVERLAY_FILE COMPILING_OVERLAY_DIR "/res/drawable-xxhdpi/foo.png";
+
+// Internal zip path to another overlay dir that is NOT being compiled
+#define NOT_COMPILING_OVERLAY_DIR "/assets/overlays/com.boring.app"
+
+// Internal zip path to a resource for an overlay that is NOT compiling. aapt is expected to ignore
+#define NOT_COMPILING_OVERLAY_FILE COMPILING_OVERLAY_DIR "/assets/overlays/com.boring.app"
+
+static ::testing::AssertionResult TestParse(const String8& input, ConfigDescription* config=NULL) {
+ if (AaptConfig::parse(String8(input), config)) {
+ return ::testing::AssertionSuccess() << input << " was successfully parsed";
+ }
+ return ::testing::AssertionFailure() << input << " could not be parsed";
+}
+
+static ::testing::AssertionResult TestParse(const char* input, ConfigDescription* config=NULL) {
+ return TestParse(String8(input), config);
+}
+
+TEST(ZipReadingTest, TestValidZipEntryIsAdded) {
+ MockZipFile zip;
+ MockZipEntry entry1;
+ const char* zipFile = VALID_APK_FILE;
+ const char* validFilename = COMPILING_OVERLAY_FILE;
+
+ EXPECT_CALL(entry1, getFileName())
+ .WillRepeatedly(Return(validFilename));
+
+ EXPECT_CALL(zip, getNumEntries())
+ .Times(1)
+ .WillRepeatedly(Return(1));
+
+ EXPECT_CALL(zip, getEntryByIndex(_))
+ .Times(1)
+ .WillOnce(Return(&entry1));
+
+ sp<AaptAssets> assets = new AaptAssets();
+ Bundle bundle;
+ bundle.setInternalZipPath(COMPILING_OVERLAY_DIR);
+ ssize_t count = assets->slurpResourceZip(&bundle, &zip, zipFile);
+
+ Vector<sp<AaptDir> > dirs = assets->resDirs();
+ EXPECT_EQ(1, dirs.size());
+ EXPECT_EQ(1, count);
+}
+
+TEST(ZipReadingTest, TestDifferentThemeEntryNotAdded) {
+ MockZipFile zip;
+ MockZipEntry entry1;
+ const char* zipFile = VALID_APK_FILE;
+ const char* invalidFile = NOT_COMPILING_OVERLAY_FILE;
+
+ EXPECT_CALL(entry1, getFileName())
+ .WillRepeatedly(Return(invalidFile));
+
+ EXPECT_CALL(zip, getNumEntries())
+ .WillRepeatedly(Return(1));
+
+ EXPECT_CALL(zip, getEntryByIndex(_))
+ .Times(1)
+ .WillOnce(Return(&entry1));
+
+ sp<AaptAssets> assets = new AaptAssets();
+ Bundle bundle;
+ bundle.setInternalZipPath(COMPILING_OVERLAY_DIR);
+ ssize_t count = assets->slurpResourceZip(&bundle, &zip, zipFile);
+
+ Vector<sp<AaptDir> > dirs = assets->resDirs();
+ EXPECT_EQ(0, dirs.size());
+ EXPECT_EQ(0, count);
+}
+
+TEST(ZipReadingTest, TestOutsideEntryMarkedInvalid) {
+ Bundle bundle;
+ bundle.setInternalZipPath("VALID_OVERLAY_DIR");
+ MockZipEntry invalidEntry;
+ const char* invalidFile = NOT_COMPILING_OVERLAY_FILE;
+
+ EXPECT_CALL(invalidEntry, getFileName())
+ .WillRepeatedly(Return(invalidFile));
+
+ sp<AaptAssets> assets = new AaptAssets();
+ bool result = assets->isEntryValid(&bundle, &invalidEntry);
+
+ EXPECT_FALSE(result);
+}
+
+TEST(ZipReadingTest, TestNullEntryIsInvalid) {
+ Bundle bundle;
+ bundle.setInternalZipPath(COMPILING_OVERLAY_DIR);
+ MockZipEntry invalidEntry;
+ const char* invalidFile = NOT_COMPILING_OVERLAY_FILE;
+
+ EXPECT_CALL(invalidEntry, getFileName())
+ .WillRepeatedly(Return(invalidFile));
+
+ sp<AaptAssets> assets = new AaptAssets();
+ bool result = assets->isEntryValid(&bundle, NULL);
+
+ EXPECT_FALSE(result);
+}
+
+TEST(ZipReadingTest, TestDirectoryEntryMarkedInvalid) {
+ Bundle bundle;
+ bundle.setInternalZipPath(COMPILING_OVERLAY_DIR);
+ MockZipEntry invalidEntry2;
+ // Add a "/" signifying this is a dir entry not a file entry.
+ const char* dir2 = COMPILING_OVERLAY_DIR"/";
+ EXPECT_CALL(invalidEntry2, getFileName())
+ .WillRepeatedly(Return(dir2));
+
+ sp<AaptAssets> assets = new AaptAssets();
+ bool result2 = assets->isEntryValid(&bundle, &invalidEntry2);
+
+ EXPECT_FALSE(result2);
+}
diff --git a/tools/aapt/tests/mocks/MockZipEntry.h b/tools/aapt/tests/mocks/MockZipEntry.h
new file mode 100644
index 0000000..eef07f9
--- /dev/null
+++ b/tools/aapt/tests/mocks/MockZipEntry.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2014 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.
+ */
+
+#ifndef ANDROID_MOCK_ZIP_ENTRY
+#define ANDROID_MOCK_ZIP_ENTRY
+
+#include "ZipFile.h"
+#include "gmock/gmock.h"
+
+class MockZipEntry : public android::ZipEntry {
+public:
+ MOCK_CONST_METHOD0(getCompressionMethod, int());
+ MOCK_CONST_METHOD0(getFileName, const char* ());
+};
+
+#endif // ANDROID_MOCK_ZIP_ENTRY
diff --git a/tools/aapt/tests/mocks/MockZipFile.h b/tools/aapt/tests/mocks/MockZipFile.h
new file mode 100644
index 0000000..0394ce7
--- /dev/null
+++ b/tools/aapt/tests/mocks/MockZipFile.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2014 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.
+ */
+
+#ifndef ANDROID_MOCK_ZIP_FILE
+#define ANDROID_MOCK_ZIP_FILE
+
+#include "ZipFile.h"
+#include "gmock/gmock.h"
+
+class MockZipFile : public android::ZipFile {
+public:
+ MOCK_CONST_METHOD0(getNumEntries, int());
+ MOCK_CONST_METHOD1(getEntryByIndex, android::ZipEntry* (int idx));
+};
+
+#endif // ANDROID_MOCK_ZIP_FILE
diff --git a/tools/aidl/aidl.cpp b/tools/aidl/aidl.cpp
index 14c9f95..cd4fbe5 100644
--- a/tools/aidl/aidl.cpp
+++ b/tools/aidl/aidl.cpp
@@ -569,12 +569,19 @@ check_types(const char* filename, document_item_type* items)
if (methodNames.find(m->name.data) == methodNames.end()) {
methodNames[m->name.data] = m;
} else {
- fprintf(stderr,"%s:%d attempt to redefine method %s,\n",
+ if (m->hasId) {
+ fprintf(stderr, "%s:%d redefining method %s\n",
filename, m->name.lineno, m->name.data);
- method_type* old = methodNames[m->name.data];
- fprintf(stderr, "%s:%d previously defined here.\n",
- filename, old->name.lineno);
- err = 1;
+ m->deduplicate = true;
+ methodNames[m->name.data] = m;
+ } else {
+ fprintf(stderr,"%s:%d attempt to redefine method %s,\n",
+ filename, m->name.lineno, m->name.data);
+ method_type* old = methodNames[m->name.data];
+ fprintf(stderr, "%s:%d previously defined here.\n",
+ filename, old->name.lineno);
+ err = 1;
+ }
}
}
member = member->next;
@@ -1014,9 +1021,6 @@ compile_aidl(Options& options)
NAMES.Dump();
#endif
- // check the referenced types in mainDoc to make sure we've imported them
- err |= check_types(options.inputFileName.c_str(), mainDoc);
-
// finally, there really only needs to be one thing in mainDoc, and it
// needs to be an interface.
bool onlyParcelable = false;
@@ -1028,6 +1032,9 @@ compile_aidl(Options& options)
((interface_type*)mainDoc)->interface_items);
}
+ // check the referenced types in mainDoc to make sure we've imported them
+ err |= check_types(options.inputFileName.c_str(), mainDoc);
+
// after this, there shouldn't be any more errors because of the
// input.
if (err != 0 || mainDoc == NULL) {
diff --git a/tools/aidl/aidl_language.h b/tools/aidl/aidl_language.h
index de1370c..f3c850e 100644
--- a/tools/aidl/aidl_language.h
+++ b/tools/aidl/aidl_language.h
@@ -64,6 +64,7 @@ typedef struct method_type {
buffer_type semicolon_token;
buffer_type* comments_token; // points into this structure, DO NOT DELETE
int assigned_id;
+ bool deduplicate;
} method_type;
enum {
diff --git a/tools/aidl/generate_java_binder.cpp b/tools/aidl/generate_java_binder.cpp
index f291ceb..1b538ca 100644
--- a/tools/aidl/generate_java_binder.cpp
+++ b/tools/aidl/generate_java_binder.cpp
@@ -260,6 +260,12 @@ generate_method(const method_type* method, Class* interface,
string transactCodeName = "TRANSACTION_";
transactCodeName += method->name.data;
+ if (method->deduplicate) {
+ char tmp[16];
+ sprintf(tmp, "_%d", index);
+ transactCodeName += tmp;
+ }
+
char transactCodeValue[60];
sprintf(transactCodeValue, "(android.os.IBinder.FIRST_CALL_TRANSACTION + %d)", index);
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
index 689e359..6366424 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
@@ -497,6 +497,11 @@ public final class BridgeContext extends Context {
}
@Override
+ public void recreateTheme() {
+ throw new UnsupportedOperationException("recreateTheme is unsupported");
+ }
+
+ @Override
public ClassLoader getClassLoader() {
// The documentation for this method states that it should return a class loader one can
// use to retrieve classes in this package. However, when called by LayoutInflater, we do
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java
index 895f9c9..947f99c 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java
@@ -155,4 +155,20 @@ public class BridgePowerManager implements IPowerManager {
public boolean isScreenBrightnessBoosted() throws RemoteException {
return false;
}
+
+ @Override
+ public void setKeyboardVisibility(boolean visible) {
+ // pass for now.
+ }
+
+ @Override
+ public void cpuBoost(int duration) throws RemoteException {
+ // pass for now
+ }
+
+ @Override
+ public void setKeyboardLight(boolean on, int key) {
+ // pass for now
+ }
+
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/view/WindowManagerImpl.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/view/WindowManagerImpl.java
index 7e5ae8d..b23d87d 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/view/WindowManagerImpl.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/view/WindowManagerImpl.java
@@ -45,6 +45,7 @@ public class WindowManagerImpl implements WindowManager {
@Override
public void addView(View arg0, android.view.ViewGroup.LayoutParams arg1) {
+ android.util.SeempLog.record_vg(383, arg1);
// pass
}
@@ -55,6 +56,7 @@ public class WindowManagerImpl implements WindowManager {
@Override
public void updateViewLayout(View arg0, android.view.ViewGroup.LayoutParams arg1) {
+ android.util.SeempLog.record_vg(384, arg1);
// pass
}
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index 0d95b38..160fd76 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -90,6 +90,8 @@ interface IWifiManager
boolean isDualBandSupported();
+ boolean isIbssSupported();
+
boolean saveConfiguration();
DhcpInfo getDhcpInfo();
diff --git a/wifi/java/android/net/wifi/WifiChannel.java b/wifi/java/android/net/wifi/WifiChannel.java
index 640481e..a526062 100644
--- a/wifi/java/android/net/wifi/WifiChannel.java
+++ b/wifi/java/android/net/wifi/WifiChannel.java
@@ -43,6 +43,9 @@ public class WifiChannel implements Parcelable {
/** is it a DFS channel? */
public boolean isDFS;
+ /** is IBSS allowed? */
+ public boolean ibssAllowed;
+
/** public constructor */
public WifiChannel() { }
@@ -65,6 +68,7 @@ public class WifiChannel implements Parcelable {
out.writeInt(freqMHz);
out.writeInt(channelNum);
out.writeInt(isDFS ? 1 : 0);
+ out.writeInt(ibssAllowed ? 1 : 0);
}
/** implement Parcelable interface */
@@ -76,6 +80,7 @@ public class WifiChannel implements Parcelable {
channel.freqMHz = in.readInt();
channel.channelNum = in.readInt();
channel.isDFS = in.readInt() != 0;
+ channel.ibssAllowed = in.readInt() != 0;
return channel;
}
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index dc329e2..9d4f6e2 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -58,8 +58,15 @@ public class WifiConfiguration implements Parcelable {
public static final String pmfVarName = "ieee80211w";
/** {@hide} */
public static final String updateIdentiferVarName = "update_identifier";
+ /** {@hide} */
+ public static final String modeVarName = "mode";
+ /** {@hide} */
+ public static final String frequencyVarName = "frequency";
/** {@hide} */
public static final int INVALID_NETWORK_ID = -1;
+ /** {@hide} */
+ public static final String SIMNumVarName = "sim_num";
+
/**
* Recognized key management schemes.
@@ -302,6 +309,18 @@ public class WifiConfiguration implements Parcelable {
*/
public String updateIdentifier;
+ /**
+ * This is an Ad-Hoc (IBSS) network
+ * {@hide}
+ */
+ public boolean isIBSS;
+
+ /**
+ * Frequency of the Ad-Hoc (IBSS) network, if newly created
+ * {@hide}
+ */
+ public int frequency;
+
/**
* The set of key management protocols supported by this configuration.
* See {@link KeyMgmt} for descriptions of the values.
@@ -426,6 +445,12 @@ public class WifiConfiguration implements Parcelable {
public String autoJoinBSSID;
/**
+ * @hide
+ * sim number selected
+ */
+ public int SIMNum;
+
+ /**
* @hide
* Status of user approval for connection
*/
@@ -910,6 +935,8 @@ public class WifiConfiguration implements Parcelable {
roamingConsortiumIds = new long[0];
priority = 0;
hiddenSSID = false;
+ isIBSS = false;
+ frequency = 0;
disableReason = DISABLED_UNKNOWN_REASON;
allowedKeyManagement = new BitSet();
allowedProtocols = new BitSet();
@@ -929,6 +956,7 @@ public class WifiConfiguration implements Parcelable {
mIpConfiguration = new IpConfiguration();
lastUpdateUid = -1;
creatorUid = -1;
+ SIMNum = 0;
}
/**
@@ -1088,6 +1116,10 @@ public class WifiConfiguration implements Parcelable {
if (this.preSharedKey != null) {
sbuf.append('*');
}
+ sbuf.append('\n').append(" sim_num ");
+ if (this.SIMNum > 0 ) {
+ sbuf.append('*');
+ }
sbuf.append("\nEnterprise config:\n");
sbuf.append(enterpriseConfig);
@@ -1325,14 +1357,14 @@ public class WifiConfiguration implements Parcelable {
key = FQDN + KeyMgmt.strings[KeyMgmt.WPA_EAP];
} else {
if (allowedKeyManagement.get(KeyMgmt.WPA_PSK)) {
- key = SSID + KeyMgmt.strings[KeyMgmt.WPA_PSK];
+ key = SSID + "-" + KeyMgmt.strings[KeyMgmt.WPA_PSK];
} else if (allowedKeyManagement.get(KeyMgmt.WPA_EAP) ||
allowedKeyManagement.get(KeyMgmt.IEEE8021X)) {
- key = SSID + KeyMgmt.strings[KeyMgmt.WPA_EAP];
+ key = SSID + "-" + KeyMgmt.strings[KeyMgmt.WPA_EAP];
} else if (wepKeys[0] != null) {
- key = SSID + "WEP";
+ key = SSID + "-WEP";
} else {
- key = SSID + KeyMgmt.strings[KeyMgmt.NONE];
+ key = SSID + "-" + KeyMgmt.strings[KeyMgmt.NONE];
}
mCachedConfigKey = key;
}
@@ -1354,17 +1386,16 @@ public class WifiConfiguration implements Parcelable {
if (result.capabilities.contains("WEP")) {
key = key + "-WEP";
- }
-
- if (result.capabilities.contains("PSK")) {
+ } else if (result.capabilities.contains("PSK")) {
key = key + "-" + KeyMgmt.strings[KeyMgmt.WPA_PSK];
- }
-
- if (result.capabilities.contains("EAP")) {
+ } else if (result.capabilities.contains("EAP")||
+ result.capabilities.contains("IEEE8021X")) {
key = key + "-" + KeyMgmt.strings[KeyMgmt.WPA_EAP];
+ } else {
+ key = key +"-" + KeyMgmt.strings[KeyMgmt.NONE];
}
- return key;
+ return key;
}
/** @hide */
@@ -1453,6 +1484,8 @@ public class WifiConfiguration implements Parcelable {
wepTxKeyIndex = source.wepTxKeyIndex;
priority = source.priority;
hiddenSSID = source.hiddenSSID;
+ isIBSS = source.isIBSS;
+ frequency = source.frequency;
allowedKeyManagement = (BitSet) source.allowedKeyManagement.clone();
allowedProtocols = (BitSet) source.allowedProtocols.clone();
allowedAuthAlgorithms = (BitSet) source.allowedAuthAlgorithms.clone();
@@ -1522,6 +1555,7 @@ public class WifiConfiguration implements Parcelable {
noInternetAccessExpected = source.noInternetAccessExpected;
creationTime = source.creationTime;
updateTime = source.updateTime;
+ SIMNum = source.SIMNum;
}
}
@@ -1554,6 +1588,8 @@ public class WifiConfiguration implements Parcelable {
dest.writeInt(wepTxKeyIndex);
dest.writeInt(priority);
dest.writeInt(hiddenSSID ? 1 : 0);
+ dest.writeInt(isIBSS ? 1 : 0);
+ dest.writeInt(frequency);
dest.writeInt(requirePMF ? 1 : 0);
dest.writeString(updateIdentifier);
@@ -1601,6 +1637,7 @@ public class WifiConfiguration implements Parcelable {
dest.writeInt(userApproved);
dest.writeInt(numNoInternetAccessReports);
dest.writeInt(noInternetAccessExpected ? 1 : 0);
+ dest.writeInt(SIMNum);
}
/** Implement the Parcelable interface {@hide} */
@@ -1630,6 +1667,8 @@ public class WifiConfiguration implements Parcelable {
config.wepTxKeyIndex = in.readInt();
config.priority = in.readInt();
config.hiddenSSID = in.readInt() != 0;
+ config.isIBSS = in.readInt() != 0;
+ config.frequency = in.readInt();
config.requirePMF = in.readInt() != 0;
config.updateIdentifier = in.readString();
@@ -1677,6 +1716,7 @@ public class WifiConfiguration implements Parcelable {
config.userApproved = in.readInt();
config.numNoInternetAccessReports = in.readInt();
config.noInternetAccessExpected = in.readInt() != 0;
+ config.SIMNum = in.readInt();
return config;
}
diff --git a/wifi/java/android/net/wifi/WifiDevice.aidl b/wifi/java/android/net/wifi/WifiDevice.aidl
new file mode 100755
index 0000000..c1b186c
--- /dev/null
+++ b/wifi/java/android/net/wifi/WifiDevice.aidl
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package android.net.wifi;
+
+parcelable WifiDevice;
diff --git a/wifi/java/android/net/wifi/WifiDevice.java b/wifi/java/android/net/wifi/WifiDevice.java
new file mode 100755
index 0000000..163b559
--- /dev/null
+++ b/wifi/java/android/net/wifi/WifiDevice.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package android.net.wifi;
+
+import android.os.Parcelable;
+import android.os.Parcel;
+
+/**
+ * Describes information about a detected Wi-Fi STA.
+ * {@hide}
+ */
+public class WifiDevice implements Parcelable {
+ /**
+ * The device MAC address is the unique id of a Wi-Fi STA
+ */
+ public String deviceAddress = "";
+
+ /**
+ * The device name is a readable string of a Wi-Fi STA
+ */
+ public String deviceName = "";
+
+ /**
+ * The device state is the state of a Wi-Fi STA
+ */
+ public int deviceState = 0;
+
+ /**
+ * These definitions are for deviceState
+ */
+ public static final int DISCONNECTED = 0;
+ public static final int CONNECTED = 1;
+ public static final int BLACKLISTED = 2;
+
+ private static final String AP_STA_CONNECTED_STR = "AP-STA-CONNECTED";
+ private static final String AP_STA_DISCONNECTED_STR = "AP-STA-DISCONNECTED";
+
+ /** {@hide} */
+ public WifiDevice() {}
+
+ /**
+ * @param string formats supported include
+ *
+ * AP-STA-CONNECTED 42:fc:89:a8:96:09
+ * AP-STA-DISCONNECTED 42:fc:89:a8:96:09
+ *
+ * Note: The events formats can be looked up in the hostapd code
+ * @hide
+ */
+ public WifiDevice(String dataString) throws IllegalArgumentException {
+ String[] tokens = dataString.split(" ");
+
+ if (tokens.length < 2) {
+ throw new IllegalArgumentException();
+ }
+
+ if (tokens[0].indexOf(AP_STA_CONNECTED_STR) != -1) {
+ deviceState = CONNECTED;
+ } else if (tokens[0].indexOf(AP_STA_DISCONNECTED_STR) != -1) {
+ deviceState = DISCONNECTED;
+ } else {
+ throw new IllegalArgumentException();
+ }
+
+ deviceAddress = tokens[1];
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == null || !(obj instanceof WifiDevice)) {
+ return false;
+ }
+
+ WifiDevice other = (WifiDevice) obj;
+
+ if (deviceAddress == null) {
+ return (other.deviceAddress == null);
+ } else {
+ return deviceAddress.equals(other.deviceAddress);
+ }
+ }
+
+ /** Implement the Parcelable interface {@hide} */
+ public int describeContents() {
+ return 0;
+ }
+
+ /** Implement the Parcelable interface {@hide} */
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(deviceAddress);
+ dest.writeString(deviceName);
+ dest.writeInt(deviceState);
+ }
+
+ /** Implement the Parcelable interface {@hide} */
+ public static final Creator<WifiDevice> CREATOR =
+ new Creator<WifiDevice>() {
+ public WifiDevice createFromParcel(Parcel in) {
+ WifiDevice device = new WifiDevice();
+ device.deviceAddress = in.readString();
+ device.deviceName = in.readString();
+ device.deviceState = in.readInt();
+ return device;
+ }
+
+ public WifiDevice[] newArray(int size) {
+ return new WifiDevice[size];
+ }
+ };
+}
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index cf88df4..056ede1 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -1,4 +1,7 @@
/*
+ * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ *
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,6 +22,7 @@ package android.net.wifi;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.annotation.SystemApi;
+import android.app.AppOpsManager;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.ConnectivityManager.NetworkCallback;
@@ -623,6 +627,7 @@ public class WifiManager {
private static final Object sThreadRefLock = new Object();
private static int sThreadRefCount;
private static HandlerThread sHandlerThread;
+ private final AppOpsManager mAppOps;
@GuardedBy("sCM")
// TODO: Introduce refcounting and make this a per-process static callback, instead of a
@@ -644,6 +649,7 @@ public class WifiManager {
mService = service;
mTargetSdkVersion = context.getApplicationInfo().targetSdkVersion;
init();
+ mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
}
/**
@@ -1307,6 +1313,7 @@ public class WifiManager {
* in order to get valid results.
*/
public List<ScanResult> getScanResults() {
+ android.util.SeempLog.record(55);
try {
return mService.getScanResults(mContext.getOpPackageName());
} catch (RemoteException e) {
@@ -1421,6 +1428,19 @@ public class WifiManager {
}
/**
+ * Check if the chipset supports IBSS (Adhoc) mode
+ * @return {@code true} if supported, {@code false} otherwise.
+ * @hide
+ */
+ public boolean isIbssSupported() {
+ try {
+ return mService.isIbssSupported();
+ } catch (RemoteException e) {
+ return false;
+ }
+ }
+
+ /**
* Return the DHCP-assigned addresses from the last successful DHCP request,
* if any.
* @return the DHCP information
@@ -1440,6 +1460,9 @@ public class WifiManager {
* is the same as the requested state).
*/
public boolean setWifiEnabled(boolean enabled) {
+ if (mAppOps.noteOp(AppOpsManager.OP_WIFI_CHANGE) !=
+ AppOpsManager.MODE_ALLOWED)
+ return false;
try {
return mService.setWifiEnabled(enabled);
} catch (RemoteException e) {